/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var AbilitiesMenu = Container.expand(function () {
	var self = Container.call(this);
	var menuBackground = self.attachAsset('AbilitiesBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	menuBackground.alpha = 0.95;
	var closeButton = self.attachAsset('Abilitiesclosebutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.x = 33;
	closeButton.y = menuBackground.height / 2 - 60;
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideAbilities();
	};
	var gridContainer = new Container();
	self.addChild(gridContainer);
	var gridCols = 3;
	var gridRows = 3;
	var cellWidth = 350;
	var cellHeight = 300;
	var padding = 50;
	var gridTotalWidth = gridCols * cellWidth + (gridCols - 1) * padding;
	var gridTotalHeight = gridRows * cellHeight + (gridRows - 1) * padding;
	// Center the grid horizontally and vertically within the background, then move 160px right and 50px down
	gridContainer.x = -gridTotalWidth / 2 + 210; // 150 + 50 + 10 = 210
	gridContainer.y = -gridTotalHeight / 2; // -50 + 50 = 0
	var title = new Text2("Abilities", {
		size: 80,
		fill: 0xff7b00,
		weight: 800
	});
	title.anchor.set(0.5, 0.5);
	title.x = 43;
	title.y = -menuBackground.height / 2 + 80;
	self.addChild(title);
	// Create description tooltip that will be shared by all cells
	var descriptionTooltip = null;
	for (var row = 0; row < gridRows; row++) {
		for (var col = 0; col < gridCols; col++) {
			(function (r, c) {
				var abilityIndex = r * gridCols + c;
				var abilityId = 'ability_' + abilityIndex;
				var abilityCost = (abilityIndex + 1) * 100;
				var abilityDef = abilityDefinitions[abilityId];
				var cell = new Container();
				cell.x = c * (cellWidth + padding);
				cell.y = r * (cellHeight + padding);
				gridContainer.addChild(cell);
				// Set initial animation state for entrance effect
				cell.alpha = 0;
				cell.scaleX = 0.3;
				cell.scaleY = 0.3;
				cell.y += 50; // Start slightly below final position
				// Calculate staggered delay based on position (diagonal wave effect)
				var animationDelay = (r + c) * 100; // 100ms delay per diagonal step
				// Animate entrance with staggered timing
				tween(cell, {
					alpha: 1,
					scaleX: 1,
					scaleY: 1,
					y: r * (cellHeight + padding)
				}, {
					duration: 400,
					delay: animationDelay,
					easing: tween.easeOut
				});
				var abilityIcon = cell.attachAsset(abilityDef.icon, {
					anchorX: 0.5,
					anchorY: 0.5
				});
				abilityIcon.y = 50;
				abilityIcon.tint = abilityDef.color;
				// Add ability name
				var abilityName = new Text2(abilityDef.name, {
					size: 48,
					fill: 0x00ffb3,
					weight: 600
				});
				abilityName.anchor.set(0.5, 0.5);
				abilityName.y = 50; // Center in the middle of the ability icon
				cell.addChild(abilityName);
				// Position buttons below the icon
				var buttonY = 250;
				// --- Use Button ---
				var useButton = new Container();
				useButton.y = buttonY;
				cell.addChild(useButton);
				var useBg = useButton.attachAsset('ScoreButton', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 200,
					height: 100
				});
				var useText = new Text2("USE\n" + abilityCost + " C", {
					size: 36,
					fill: 0xffffff,
					align: 'center',
					weight: 600
				});
				useText.anchor.set(0.5, 0.5);
				useButton.addChild(useText);
				// --- Button Handlers ---
				useButton.down = function () {
					var canUseNow = gameStarted && !showingIntro && canStartWaves;
					if (!canUseNow) {
						var notification = game.addChild(new Notification("Cannot use abilities until game starts!"));
						return;
					}
					if (crystals >= abilityCost) {
						LK.getSound('Useabilitysound1').play();
						setCrystals(crystals - abilityCost);
						abilityDef.effect();
						hideAbilities();
					} else {
						var notification = game.addChild(new Notification("Not enough crystals!"));
					}
				};
				// --- Update visuals based on state ---
				cell.update = function () {
					var canUseNow = gameStarted && !showingIntro && canStartWaves;
					var canAfford = crystals >= abilityCost;
					if (canUseNow) {
						useBg.tint = canAfford ? 0x00ff00 : 0xff0000; // Green if affordable, red if not
					} else {
						useBg.tint = 0x808080; // Gray if not usable
					}
					abilityIcon.alpha = canAfford ? 1.0 : 0.6;
				};
				cell.update(); // Initial call to set state
				// Hover functionality removed - descriptions only show on click
				cell.down = function () {
					// Show bigger description notification when clicking on cell
					var descriptionNotification = game.addChild(new Container());
					var notificationBg = descriptionNotification.attachAsset('notification3', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					notificationBg.tint = 0x000000;
					notificationBg.alpha = 0.9;
					var descText = new Text2(abilityDef.description, {
						size: 48,
						fill: 0xffffff,
						weight: 600,
						align: 'center'
					});
					descText.anchor.set(0.5, 0.5);
					descriptionNotification.addChild(descText);
					descriptionNotification.x = 2048 / 2;
					descriptionNotification.y = 2732 / 2;
					descriptionNotification.alpha = 0;
					descriptionNotification.scaleX = 0.5;
					descriptionNotification.scaleY = 0.5;
					// Animate in
					tween(descriptionNotification, {
						alpha: 1,
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 300,
						easing: tween.easeOut
					});
					// Auto hide after 3 seconds
					LK.setTimeout(function () {
						tween(descriptionNotification, {
							alpha: 0,
							scaleX: 0.5,
							scaleY: 0.5
						}, {
							duration: 300,
							easing: tween.easeIn,
							onFinish: function onFinish() {
								descriptionNotification.destroy();
							}
						});
					}, 3000);
				};
			})(row, col);
		}
	}
	self.update = function () {
		for (var i = 0; i < gridContainer.children.length; i++) {
			var cell = gridContainer.children[i];
			if (cell.update) {
				cell.update();
			}
		}
	};
	// Tooltip functionality removed
	return self;
});
var Bullet = Container.expand(function (startX, startY, targetEnemy, damage, speed) {
	var self = Container.call(this);
	self.targetEnemy = targetEnemy;
	self.damage = damage || 10;
	self.speed = speed || 5;
	self.x = startX;
	self.y = startY;
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.update = function () {
		if (!self.targetEnemy || !self.targetEnemy.parent) {
			self.destroy();
			return;
		}
		// Check if bullet has exceeded its source tower's range (for all tower types)
		if (self.sourceTower) {
			var towerDx = self.x - self.sourceTower.x;
			var towerDy = self.y - self.sourceTower.y;
			var distanceFromTower = Math.sqrt(towerDx * towerDx + towerDy * towerDy);
			if (distanceFromTower > self.sourceTower.getRange()) {
				self.destroy();
				return;
			}
		}
		var dx = self.targetEnemy.x - self.x;
		var dy = self.targetEnemy.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < self.speed) {
			// Apply damage to target enemy with resistance scaling
			var actualDamage = self.damage;
			if (self.targetEnemy.damageResistance) {
				actualDamage = self.damage * self.targetEnemy.damageResistance;
			}
			self.targetEnemy.health -= actualDamage;
			// Play damage sound based on enemy type
			var enemyAssetId = null;
			if (self.targetEnemy.children && self.targetEnemy.children[0]) {
				// Get the asset ID from the enemy's graphics to determine sound
				var enemyGraphics = self.targetEnemy.children[0];
				// Check enemy type based on wave progression and type
				if (self.targetEnemy.type === 'immune') {
					// Big Robot enemies (immune type)
					game.playSoundWithVolume('Bigrobots_damage_sound1');
				} else if (self.targetEnemy.type === 'normal') {
					// Cyborg enemies (normal type)
					game.playSoundWithVolume('Cyborg_Damage_sound1');
				} else if (self.targetEnemy.type === 'swarm') {
					// CyberSnake enemies (swarm type)
					game.playSoundWithVolume('Cybersnake_damage_sound1');
				} else if (self.targetEnemy.type === 'flying') {
					// Flying enemies - determine specific type
					var waveGroup = Math.floor((self.targetEnemy.waveNumber - 1) / 10);
					var flyingAssets = ['Firo', 'Eye', 'Electro'];
					var assetIndex = waveGroup % flyingAssets.length;
					var flyingAsset = flyingAssets[assetIndex];
					if (flyingAsset === 'Eye') {
						game.playSoundWithVolume('Eye_Damage_sound1');
					} else if (flyingAsset === 'Firo') {
						game.playSoundWithVolume('Firo_Damage_sound1');
					} else if (flyingAsset === 'Electro') {
						game.playSoundWithVolume('Electro_Damage_sound1');
					}
				} else if (self.targetEnemy.type === 'fast') {
					// Fast enemies use Robot1, Spider1, Spider2
					game.playSoundWithVolume('Robot_Damage_sound1');
				}
			}
			if (self.targetEnemy.health <= 0) {
				self.targetEnemy.health = 0;
			} else {
				// Update enemy health bar using stored original width
				var healthPercentage = self.targetEnemy.health / self.targetEnemy.maxHealth;
				self.targetEnemy.healthBar.width = self.targetEnemy.healthBarOriginalWidth * healthPercentage;
			}
			// Apply special effects based on bullet type
			if (self.type === 'cannon') {
				// Create fire explosion effect for cannon bullets
				var explosionEffect = new Container();
				explosionEffect.x = self.targetEnemy.x;
				explosionEffect.y = self.targetEnemy.y;
				game.addChild(explosionEffect);
				// Create multiple fire particles for the explosion
				for (var fireParticle = 0; fireParticle < 8; fireParticle++) {
					var particle = explosionEffect.attachAsset('rangeCircle', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					particle.width = particle.height = 20 + Math.random() * 30;
					particle.tint = fireParticle % 2 === 0 ? 0xFF4500 : 0xFF8C00; // Orange-red fire colors
					particle.alpha = 0.8;
					particle.blendMode = 1; // Add blend mode for fire effect
					particle.x = (Math.random() - 0.5) * 40;
					particle.y = (Math.random() - 0.5) * 40;
					particle.scaleX = 0.1;
					particle.scaleY = 0.1;
					// Animate each particle exploding outward
					tween(particle, {
						scaleX: 1.5,
						scaleY: 1.5,
						x: particle.x + (Math.random() - 0.5) * 60,
						y: particle.y + (Math.random() - 0.5) * 60,
						alpha: 0
					}, {
						duration: 300 + Math.random() * 200,
						easing: tween.easeOut
					});
				}
				// Create central explosion flash
				var centralFlash = explosionEffect.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				centralFlash.width = centralFlash.height = 80;
				centralFlash.tint = 0xFFFFAA; // Bright yellow-white center
				centralFlash.alpha = 1;
				centralFlash.blendMode = 1;
				centralFlash.scaleX = 0.1;
				centralFlash.scaleY = 0.1;
				// Animate central flash
				tween(centralFlash, {
					scaleX: 2,
					scaleY: 2,
					alpha: 0
				}, {
					duration: 400,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						explosionEffect.destroy();
					}
				});
			} else if (self.type === 'Rocket') {
				// Create visual splash effect
				var splashEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'splash');
				game.addChild(splashEffect);
				// Splash damage to nearby enemies - 200x200 area means 100 pixel radius
				var splashRadius = 100;
				for (var i = 0; i < enemies.length; i++) {
					var otherEnemy = enemies[i];
					if (otherEnemy !== self.targetEnemy) {
						var splashDx = otherEnemy.x - self.targetEnemy.x;
						var splashDy = otherEnemy.y - self.targetEnemy.y;
						var splashDistance = Math.sqrt(splashDx * splashDx + splashDy * splashDy);
						if (splashDistance <= splashRadius) {
							// Apply splash damage (50% of original damage)
							otherEnemy.health -= self.damage * 0.5;
							if (otherEnemy.health <= 0) {
								otherEnemy.health = 0;
							} else {
								// Update enemy health bar using stored original width
								var healthPercentage = otherEnemy.health / otherEnemy.maxHealth;
								otherEnemy.healthBar.width = otherEnemy.healthBarOriginalWidth * healthPercentage;
							}
						}
					}
				}
			} else if (self.type === 'gumbomb') {
				// Prevent gum effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create visual gumbomb explosion effect
					var gumEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'gumbomb');
					game.addChild(gumEffect);
					// Apply gum stuck effect - enemies become completely immobilized
					if (!self.targetEnemy.gumStuck) {
						self.targetEnemy.originalSpeed = self.targetEnemy.speed;
						self.targetEnemy.speed = 0; // Completely stuck
						self.targetEnemy.gumStuck = true;
						self.targetEnemy.gumDuration = 240; // 4 seconds at 60 FPS
						// Create purple gum effect beneath the enemy
						var gumStuckGraphics = LK.getAsset('gumStuckEffect', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						gumStuckGraphics.x = self.targetEnemy.x;
						gumStuckGraphics.y = self.targetEnemy.y + self.targetEnemy.children[0].height / 2;
						gumStuckGraphics.alpha = 0;
						gumStuckGraphics.scaleX = 0.1;
						gumStuckGraphics.scaleY = 0.1;
						self.targetEnemy.gumStuckEffect = gumStuckGraphics;
						enemyLayerBottom.addChildAt(gumStuckGraphics, 0);
						// Explosion animation - scale up and fade in quickly
						tween(gumStuckGraphics, {
							alpha: 0.7,
							scaleX: 1.2,
							scaleY: 1.2
						}, {
							duration: 200,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								// Settle to normal size
								tween(gumStuckGraphics, {
									scaleX: 1,
									scaleY: 1
								}, {
									duration: 300,
									easing: tween.elasticOut
								});
								// Set up tween to destroy gum area after 4 seconds
								tween(gumStuckGraphics, {
									alpha: 0
								}, {
									duration: 4000,
									onFinish: function onFinish() {
										if (gumStuckGraphics && gumStuckGraphics.parent) {
											gumStuckGraphics.parent.removeChild(gumStuckGraphics);
										}
									}
								});
							}
						});
					} else {
						self.targetEnemy.gumDuration = 240; // Reset duration to 4 seconds
					}
				}
			} else if (self.type === 'ToxinBomb') {
				// Prevent toxin effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create ToxinBombEffect explosion effect using ToxinBombEffect asset
					var explosionEffect = new Container();
					explosionEffect.x = self.targetEnemy.x;
					explosionEffect.y = self.targetEnemy.y;
					game.addChild(explosionEffect);
					// Create the main toxin explosion using ToxinBombEffect asset
					var toxinExplosion = explosionEffect.attachAsset('ToxinBombEffect', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					toxinExplosion.width = toxinExplosion.height = 150;
					toxinExplosion.tint = 0x00FFb3; // Green toxin color
					toxinExplosion.alpha = 0.9;
					toxinExplosion.scaleX = 0.1;
					toxinExplosion.scaleY = 0.1;
					// Animate the toxin explosion expanding and fading
					tween(toxinExplosion, {
						scaleX: 1.8,
						scaleY: 1.8,
						alpha: 0.3
					}, {
						duration: 400,
						easing: tween.easeOut
					});
					// Create additional smaller toxin particles around the main explosion
					for (var toxinParticle = 0; toxinParticle < 6; toxinParticle++) {
						var particle = explosionEffect.attachAsset('ToxinBombEffect', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						particle.width = particle.height = 40 + Math.random() * 30;
						particle.tint = 0x00FFb3; // Consistent green toxin color
						particle.alpha = 0.7;
						particle.x = (Math.random() - 0.5) * 80;
						particle.y = (Math.random() - 0.5) * 80;
						particle.scaleX = 0.1;
						particle.scaleY = 0.1;
						// Animate each particle expanding outward
						tween(particle, {
							scaleX: 1.2,
							scaleY: 1.2,
							x: particle.x + (Math.random() - 0.5) * 100,
							y: particle.y + (Math.random() - 0.5) * 100,
							alpha: 0
						}, {
							duration: 500 + Math.random() * 200,
							easing: tween.easeOut
						});
					}
					// Destroy the explosion effect after animation completes
					tween(explosionEffect, {
						alpha: 1
					}, {
						duration: 600,
						onFinish: function onFinish() {
							explosionEffect.destroy();
						}
					});
					// Apply toxin effect
					self.targetEnemy.poisoned = true;
					self.targetEnemy.poisonDamage = self.damage * 0.2; // 20% of original damage per tick
					self.targetEnemy.poisonDuration = 300; // 5 seconds at 60 FPS
				}
			}
			// Flame tower does not use bullets, so destroy any 'flame' type bullets immediately
			if (self.type === 'flame') {
				self.destroy();
			} else {
				self.destroy();
			}
		} else {
			var angle = Math.atan2(dy, dx);
			// Rotate bullet to face movement direction
			if (self.children[0]) {
				// Check if this is a RifleBullet which needs rotation offset
				var rotationOffset = 0;
				if (self.type === 'rifle') {
					rotationOffset = Math.PI / 2; // Compensate for upward-pointing asset
				}
				var targetAngle = angle + rotationOffset;
				if (self.children[0].targetRotation === undefined) {
					self.children[0].targetRotation = targetAngle;
					self.children[0].rotation = targetAngle;
				} else {
					if (Math.abs(targetAngle - self.children[0].targetRotation) > 0.05) {
						tween.stop(self.children[0], {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = self.children[0].rotation;
						var angleDiff = targetAngle - currentRotation;
						// Normalize angle difference to -PI to PI range for shortest path
						while (angleDiff > Math.PI) {
							angleDiff -= Math.PI * 2;
						}
						while (angleDiff < -Math.PI) {
							angleDiff += Math.PI * 2;
						}
						self.children[0].targetRotation = targetAngle;
						tween(self.children[0], {
							rotation: currentRotation + angleDiff
						}, {
							duration: 100,
							easing: tween.easeOut
						});
					}
				}
			}
			self.x += Math.cos(angle) * self.speed;
			self.y += Math.sin(angle) * self.speed;
		}
	};
	return self;
});
var CrystalIndicator = Container.expand(function (value, x, y) {
	var self = Container.call(this);
	var shadowText = new Text2("+" + value, {
		size: 45,
		fill: 0x000000,
		weight: 800
	});
	shadowText.anchor.set(0.5, 0.5);
	shadowText.x = 2;
	shadowText.y = 2;
	self.addChild(shadowText);
	var crystalText = new Text2("+" + value, {
		size: 45,
		fill: 0xff0080,
		weight: 800
	});
	crystalText.anchor.set(0.5, 0.5);
	self.addChild(crystalText);
	self.x = x;
	self.y = y;
	self.alpha = 0;
	self.scaleX = 0.5;
	self.scaleY = 0.5;
	tween(self, {
		alpha: 1,
		scaleX: 1.2,
		scaleY: 1.2,
		y: y - 40
	}, {
		duration: 50,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(self, {
				alpha: 0,
				scaleX: 1.5,
				scaleY: 1.5,
				y: y - 80
			}, {
				duration: 600,
				easing: tween.easeIn,
				delay: 800,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		}
	});
	return self;
});
var DebugCell = Container.expand(function () {
	var self = Container.call(this);
	var cellGraphics = self.attachAsset('cell', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	cellGraphics.tint = Math.random() * 0xffffff;
	var debugArrows = [];
	// Numbers removed - using animated orange lines only
	self.update = function () {};
	self.down = function () {
		return;
		if (self.cell.type == 0 || self.cell.type == 1) {
			self.cell.type = self.cell.type == 1 ? 0 : 1;
			if (grid.pathFind()) {
				self.cell.type = self.cell.type == 1 ? 0 : 1;
				grid.pathFind();
				var notification = game.addChild(new Notification("Path is blocked!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
			}
			grid.renderDebug();
		}
	};
	self.removeArrows = function () {
		while (debugArrows.length) {
			self.removeChild(debugArrows.pop());
		}
	};
	self.render = function (data) {
		switch (data.type) {
			case 0:
			case 2:
				{
					if (data.pathId != pathId) {
						self.removeArrows();
						cellGraphics.tint = 0x880000;
						return;
					}
					var towerInRangeHighlight = false;
					if (selectedTower && data.towersInRange && data.towersInRange.indexOf(selectedTower) !== -1) {
						towerInRangeHighlight = true;
						cellGraphics.tint = 0xe14de9; // pink color with transparency
						cellGraphics.alpha = 0.5; // Almost max transparent
					} else {
						cellGraphics.tint = 0x4db3e9; // Sky blue color with transparency
						cellGraphics.alpha = 0.5; // Almost max transparent
					}
					while (debugArrows.length > data.targets.length) {
						self.removeChild(debugArrows.pop());
					}
					for (var a = 0; a < data.targets.length; a++) {
						var destination = data.targets[a];
						var ox = destination.x - data.x;
						var oy = destination.y - data.y;
						// Change lines pointing up to point down
						if (oy < 0) {
							oy = -oy; // Flip the y direction for upward pointing lines
						}
						var angle = Math.atan2(oy, ox);
						if (!debugArrows[a]) {
							// Create arrow container
							debugArrows[a] = new Container();
							// Create arrow shaft using shape asset
							var arrowShaft = LK.getAsset('cell', {
								anchorX: 0,
								anchorY: 0.5
							});
							arrowShaft.width = 40;
							arrowShaft.height = 8;
							arrowShaft.tint = 0xff0080;
							debugArrows[a].addChild(arrowShaft);
							// Create arrow head using shape asset
							var arrowHead = LK.getAsset('cell', {
								anchorX: 0,
								anchorY: 0.5
							});
							arrowHead.width = 20;
							arrowHead.height = 16;
							arrowHead.tint = 0xff0080;
							arrowHead.x = 35; // Position at end of shaft
							arrowHead.y = 0;
							debugArrows[a].addChild(arrowHead);
							self.addChildAt(debugArrows[a], 1);
						}
						// Fix rotation calculation - ensure correct direction mapping
						debugArrows[a].rotation = angle;
						// Position the line at center of cell for better visibility
						debugArrows[a].x = 0;
						debugArrows[a].y = 0;
						// Animate the violet arrow with flowing effect
						var arrow = debugArrows[a];
						arrow.animationPhase = (arrow.animationPhase || 0) + 0.1;
						// Create flowing effect by animating scale - maintain consistent base scale
						var flowScale = 1.0 + 0.3 * Math.sin(arrow.animationPhase * 1.2);
						arrow.scaleX = flowScale;
						// Reset scale Y to ensure proper aspect ratio
						arrow.scaleY = 1.0;
					}
					break;
				}
			case 1:
				{
					self.removeArrows();
					// Replace the cell with DebugWall image asset
					if (cellGraphics) {
						self.removeChild(cellGraphics);
					}
					cellGraphics = self.attachAsset('DebugWall', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					cellGraphics.alpha = 0.9; // Make wall more visible
					break;
				}
			case 3:
				{
					self.removeArrows();
					cellGraphics.tint = 0xff0080; // pink
					cellGraphics.alpha = 5;
					break;
				}
		}
	};
});
// This update method was incorrectly placed here and should be removed
var EffectIndicator = Container.expand(function (x, y, type) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	var effectGraphics = self.attachAsset('rangeCircle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	effectGraphics.blendMode = 1;
	switch (type) {
		case 'splash':
			effectGraphics.tint = 0x33CC00;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5;
			break;
		case 'slow':
			effectGraphics.tint = 0x9900FF;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'gumbomb':
			effectGraphics.tint = 0x9900FF;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 2; // Larger explosion effect
			break;
		case 'toxin':
			effectGraphics.tint = 0x00FFb3;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'flame':
			effectGraphics.tint = 0xFF8800; // Mix of yellow, orange, red
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
	}
	effectGraphics.alpha = 0.7;
	self.alpha = 0;
	// Animate the effect
	tween(self, {
		alpha: 0.8,
		scaleX: 1.5,
		scaleY: 1.5
	}, {
		duration: 200,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(self, {
				alpha: 0,
				scaleX: 2,
				scaleY: 2
			}, {
				duration: 300,
				easing: tween.easeIn,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		}
	});
	return self;
});
// Base enemy class for common functionality
var Enemy = Container.expand(function (type) {
	var self = Container.call(this);
	self.type = type || 'normal';
	self.speed = .01;
	self.cellX = 0;
	self.cellY = 0;
	self.currentCellX = 0;
	self.currentCellY = 0;
	self.currentTarget = undefined;
	self.maxHealth = 100;
	self.health = self.maxHealth;
	self.bulletsTargetingThis = [];
	self.waveNumber = currentWave;
	self.isFlying = false;
	self.isImmune = false;
	self.isBoss = false;
	// Check if this is a boss wave
	// Check if this is a boss wave
	// Apply different stats based on enemy type - increased health
	switch (self.type) {
		case 'fast':
			self.speed *= 2; // Twice as fast
			self.maxHealth = 45; // Increased from 30
			break;
		case 'immune':
			self.isImmune = true;
			self.maxHealth = 40; // Increased from 25
			break;
		case 'flying':
			self.isFlying = true;
			self.maxHealth = 40; // Increased from 25
			break;
		case 'swarm':
			self.maxHealth = 25; // Increased from 15
			break;
		case 'normal':
		default:
			self.maxHealth = 35; // Increased from 20
			break;
	}
	if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') {
		self.isBoss = true;
		// Boss enemies have 8x health and are larger
		self.maxHealth *= 8;
		// Slightly slower speed for bosses but not as much
		self.speed = self.speed * 0.8;
	}
	// Apply wave-based difficulty scaling every 5 waves
	var difficultyWaves = Math.floor((currentWave - 1) / 5);
	if (difficultyWaves > 0) {
		// Increase health by 75% every 5 waves (was 50%)
		var healthMultiplier = 1 + difficultyWaves * 0.75;
		self.maxHealth = Math.round(self.maxHealth * healthMultiplier);
		// Increase speed by 30% every 5 waves (was 20%)
		var speedMultiplier = 1 + difficultyWaves * 0.3;
		self.speed = self.speed * speedMultiplier;
		// Add damage resistance - enemies take 10% less damage every 5 waves
		self.damageResistance = 1 - Math.min(0.5, difficultyWaves * 0.1); // Cap at 50% resistance
	}
	self.health = self.maxHealth;
	// Get appropriate asset for this enemy type
	var assetId = 'enemy';
	if (self.type !== 'normal') {
		assetId = 'enemy_' + self.type;
	}
	// For flying enemies, use different assets based on wave progression
	if (self.type === 'flying') {
		// Use different flying enemy assets based on wave number
		var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change flying enemy type
		var flyingAssets = ['Firo', 'Eye', 'Electro'];
		var assetIndex = waveGroup % flyingAssets.length;
		assetId = flyingAssets[assetIndex];
	} else {
		// For ground enemies, use different Cyborg assets based on wave number
		var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change ground enemy type
		var groundAssets = ['Cyborg', 'Cyborg2', 'Cyborg3'];
		var assetIndex = waveGroup % groundAssets.length;
		if (self.type === 'normal') {
			assetId = groundAssets[assetIndex];
		} else if (self.type === 'fast') {
			// For fast enemies, use Robot1, Spider1, and Spider2 assets based on wave progression
			var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change fast enemy type
			var fastAssets = ['Robot1', 'Spider1', 'Spider2'];
			var assetIndex = waveGroup % fastAssets.length;
			assetId = fastAssets[assetIndex];
		} else if (self.type === 'immune') {
			// For immune enemies, use Big_Robot1, Big_Robot2, and Big_Robot3 assets based on wave progression
			var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change immune enemy type
			var immuneAssets = ['Big_Robot1', 'Big_Robot2', 'Big_Robot3'];
			var assetIndex = waveGroup % immuneAssets.length;
			assetId = immuneAssets[assetIndex];
		} else if (self.type === 'swarm') {
			// For swarm enemies, use CyberSnake1, CyberSnake2, and CyberSnake3 assets based on wave progression
			var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change swarm enemy type
			var swarmAssets = ['CyberSnake1', 'CyberSnake2', 'CyberSnake3'];
			var assetIndex = waveGroup % swarmAssets.length;
			assetId = swarmAssets[assetIndex];
		} else {
			// For other non-normal ground enemies, still use the original prefixed system but could be enhanced later
			assetId = 'enemy_' + self.type;
		}
	}
	var enemyGraphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Scale up boss enemies
	if (self.isBoss) {
		enemyGraphics.scaleX = 1.8;
		enemyGraphics.scaleY = 1.8;
	}
	// Fall back to regular enemy asset if specific type asset not found
	// Apply tint to differentiate enemy types
	/*switch (self.type) {
		case 'fast':
			enemyGraphics.tint = 0x00AAFF; // Blue for fast enemies
			break;
		case 'immune':
			enemyGraphics.tint = 0xAA0000; // Red for immune enemies
			break;
		case 'flying':
			enemyGraphics.tint = 0xFFFF00; // Yellow for flying enemies
			break;
		case 'swarm':
			enemyGraphics.tint = 0xFF00FF; // Pink for swarm enemies
			break;
	}*/
	// Create shadow for flying enemies
	if (self.isFlying) {
		// Create a shadow container that will be added to the shadow layer
		self.shadow = new Container();
		// Clone the enemy graphics for the shadow - use the same asset as the main enemy
		var shadowAssetId = assetId;
		// For flying enemies, make sure we use the correct asset for the shadow
		if (self.type === 'flying') {
			var waveGroup = Math.floor((currentWave - 1) / 10);
			var flyingAssets = ['Firo', 'Eye', 'Electro'];
			var assetIndex = waveGroup % flyingAssets.length;
			shadowAssetId = flyingAssets[assetIndex];
		}
		var shadowGraphics = self.shadow.attachAsset(shadowAssetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow effect
		shadowGraphics.tint = 0x000000; // Black shadow
		shadowGraphics.alpha = 0.3; // Semi-transparent
		// If this is a boss, scale up the shadow to match
		if (self.isBoss) {
			shadowGraphics.scaleX = 1.8;
			shadowGraphics.scaleY = 1.8;
		}
		// Position shadow slightly offset
		self.shadow.x = 20; // Offset right
		self.shadow.y = 20; // Offset down
		// Ensure shadow has the same rotation as the enemy
		shadowGraphics.rotation = enemyGraphics.rotation;
	}
	var healthBarOutline = self.attachAsset('EnemyHealthBarOutline', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var healthBar = self.attachAsset('Enemyhealthbar', {
		anchorX: 0,
		anchorY: 0.5
	});
	healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	healthBar.x = -healthBar.width / 2;
	self.healthBar = healthBar;
	self.healthBarOriginalWidth = healthBar.width; // Store original width
	self.update = function () {
		if (self.health <= 0) {
			self.health = 0;
			self.healthBar.width = 0;
		} else {
			// Update health bar width based on current health
			var healthPercentage = self.health / self.maxHealth;
			self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
		}
		// Handle slow effect
		if (self.isImmune) {
			// Immune enemies cannot be slowed, gum stuck, or poisoned, clear any such effects
			self.slowed = false;
			self.slowEffect = false;
			self.gumStuck = false;
			if (self.gumStuckEffect && self.gumStuckEffect.parent) {
				game.removeChild(self.gumStuckEffect);
			}
			self.gumStuckEffect = null;
			self.poisoned = false;
			self.poisonEffect = false;
			// Reset speed to original if needed
			if (self.originalSpeed !== undefined) {
				self.speed = self.originalSpeed;
			}
		} else {
			// Handle gum stuck effect
			if (self.gumStuck) {
				// Visual indication of gum stuck status
				if (!self.gumStuckEffect) {
					self.gumStuckEffect = true;
				}
				self.gumDuration--;
				if (self.gumDuration <= 0) {
					self.speed = self.originalSpeed;
					self.gumStuck = false;
					self.gumStuckEffect = false;
					// Remove gum effect visual with fade out animation
					if (self.gumStuckEffect && self.gumStuckEffect.parent) {
						tween(self.gumStuckEffect, {
							alpha: 0,
							scaleX: 1.5,
							scaleY: 1.5
						}, {
							duration: 300,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (self.gumStuckEffect && self.gumStuckEffect.parent) {
									game.removeChild(self.gumStuckEffect);
								}
								self.gumStuckEffect = null;
							}
						});
					} else {
						self.gumStuckEffect = null;
					}
					// Only reset tint if not poisoned
					if (!self.poisoned) {
						enemyGraphics.tint = 0xFFFFFF; // Reset tint
					}
				} else {
					// Update gum effect position to follow enemy
					if (self.gumStuckEffect && self.gumStuckEffect.parent) {
						self.gumStuckEffect.x = self.x;
						self.gumStuckEffect.y = self.y + enemyGraphics.height / 2;
					}
				}
			}
			// Handle poison effect
			if (self.poisoned) {
				// Visual indication of poisoned status
				if (!self.poisonEffect) {
					self.poisonEffect = true;
				}
				// Apply poison damage every 30 frames (twice per second)
				if (LK.ticks % 30 === 0) {
					var actualPoisonDamage = self.poisonDamage;
					if (self.damageResistance) {
						actualPoisonDamage = self.poisonDamage * self.damageResistance;
					}
					self.health -= actualPoisonDamage;
					if (self.health <= 0) {
						self.health = 0;
					}
					// Update enemy health bar using stored original width
					var healthPercentage = self.health / self.maxHealth;
					self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
				}
				self.poisonDuration--;
				if (self.poisonDuration <= 0) {
					self.poisoned = false;
					self.poisonEffect = false;
					// Only reset tint if not slowed
					if (!self.slowed) {
						enemyGraphics.tint = 0xFFFFFF; // Reset tint
					}
				}
			}
			// Handle weakness effect
			if (self.weakened) {
				self.weakenDuration--;
				if (self.weakenDuration <= 0) {
					self.weakened = false;
					self.damageResistance = self.originalDamageResistance || 1;
				}
			}
			// Handle dust slow effect
			if (self.dustSlowed) {
				self.dustSlowDuration--;
				if (self.dustSlowDuration <= 0) {
					self.dustSlowed = false;
					self.speed = self.originalSpeed;
				}
			}
			// Handle drowning effect
			if (self.drowning) {
				// Apply drowning damage every frame
				self.health -= self.drownDamage;
				if (self.health <= 0) {
					self.health = 0;
				} else {
					var healthPercentage = self.health / self.maxHealth;
					self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
				}
				self.drownDuration--;
				if (self.drownDuration <= 0) {
					self.drowning = false;
				}
			}
			// Handle burning effect
			if (self.burning) {
				// Apply burn damage every frame
				self.health -= self.burnDamage;
				if (self.health <= 0) {
					self.health = 0;
				} else {
					var healthPercentage = self.health / self.maxHealth;
					self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
				}
				self.burnDuration--;
				if (self.burnDuration <= 0) {
					self.burning = false;
				}
			}
			// Handle freeze effect
			if (self.frozen) {
				self.freezeDuration--;
				if (self.freezeDuration <= 0) {
					self.frozen = false;
					self.speed = self.originalSpeed;
					// Add ice shattering effect
					(function (enemy) {
						var shatterContainer = new Container();
						shatterContainer.x = enemy.x;
						shatterContainer.y = enemy.y;
						game.addChild(shatterContainer); // Add to game layer, not enemy
						for (var s = 0; s < 12; s++) {
							(function () {
								var shard = shatterContainer.attachAsset('cell', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: 0xB0E0E6,
									// Powder blue
									width: 15 + Math.random() * 10,
									height: 5 + Math.random() * 5,
									rotation: Math.random() * Math.PI * 2,
									alpha: 1.0
								});
								var angle = Math.random() * Math.PI * 2;
								var distance = 40 + Math.random() * 30;
								tween(shard, {
									x: Math.cos(angle) * distance,
									y: Math.sin(angle) * distance,
									alpha: 0,
									rotation: shard.rotation + (Math.random() - 0.5) * Math.PI
								}, {
									duration: 300 + Math.random() * 200,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										if (shard.parent) {
											shard.destroy();
										}
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (shatterContainer.parent) {
								shatterContainer.destroy();
							}
						}, 600);
					})(self);
				}
			}
			// Handle ultimate slow effect
			if (self.ultimateSlowed) {
				self.ultimateSlowDuration--;
				if (self.ultimateSlowDuration <= 0) {
					self.ultimateSlowed = false;
					self.speed = self.originalSpeed;
				}
			}
		}
		// Set tint based on effect status
		if (self.isImmune) {
			enemyGraphics.tint = 0xFFFFFF;
		} else if (self.frozen) {
			enemyGraphics.tint = 0x00FFFF; // Cyan for frozen
		} else if (self.drowning) {
			enemyGraphics.tint = 0x0080FF; // Blue for drowning
		} else if (self.burning) {
			// Tint is handled by the looping animation in the ability effect
		} else if (self.dustSlowed) {
			enemyGraphics.tint = 0x8B4513; // Brown for dust storm
		} else if (self.weakened) {
			enemyGraphics.tint = 0xFF4500; // Orange-red for weakened
		} else if (self.poisoned && (self.slowed || self.gumStuck)) {
			// Combine poison (0x00FFb3) and slow/gum (0x9900FF) colors
			// Simple average: R: (0+153)/2=76, G: (255+0)/2=127, B: (170+255)/2=212
			enemyGraphics.tint = 0x4C7FD4;
		} else if (self.poisoned) {
			enemyGraphics.tint = 0x00FFb3;
		} else if (self.slowed || self.gumStuck) {
			enemyGraphics.tint = 0xff0080;
		} else {
			enemyGraphics.tint = 0xFFFFFF;
		}
		if (self.currentTarget) {
			var ox = self.currentTarget.x - self.currentCellX;
			var oy = self.currentTarget.y - self.currentCellY;
			if (ox !== 0 || oy !== 0) {
				var angle = Math.atan2(oy, ox);
				if (enemyGraphics.targetRotation === undefined) {
					enemyGraphics.targetRotation = angle;
					enemyGraphics.rotation = angle;
				} else {
					if (Math.abs(angle - enemyGraphics.targetRotation) > 0.05) {
						tween.stop(enemyGraphics, {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = enemyGraphics.rotation;
						var angleDiff = angle - currentRotation;
						// Normalize angle difference to -PI to PI range for shortest path
						while (angleDiff > Math.PI) {
							angleDiff -= Math.PI * 2;
						}
						while (angleDiff < -Math.PI) {
							angleDiff += Math.PI * 2;
						}
						enemyGraphics.targetRotation = angle;
						tween(enemyGraphics, {
							rotation: currentRotation + angleDiff
						}, {
							duration: 250,
							easing: tween.easeOut
						});
					}
				}
			}
		}
		healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	};
	return self;
});
var Grid = Container.expand(function (gridWidth, gridHeight) {
	var self = Container.call(this);
	self.cells = [];
	self.spawns = [];
	self.goals = [];
	for (var i = 0; i < gridWidth; i++) {
		self.cells[i] = [];
		for (var j = 0; j < gridHeight; j++) {
			self.cells[i][j] = {
				score: 0,
				pathId: 0,
				towersInRange: []
			};
		}
	}
	/*
				Cell Types
				0: Transparent floor
				1: Wall
				2: Spawn
				3: Goal
	*/
	for (var i = 0; i < gridWidth; i++) {
		for (var j = 0; j < gridHeight; j++) {
			var cell = self.cells[i][j];
			var cellType = i === 0 || i === gridWidth - 1 || j <= 4 || j >= gridHeight - 4 ? 1 : 0;
			if (i > 11 - 3 && i <= 11 + 3) {
				if (j === 0) {
					cellType = 2;
					self.spawns.push(cell);
				} else if (j <= 4) {
					cellType = 0;
				} else if (j === gridHeight - 1) {
					cellType = 3;
					self.goals.push(cell);
				} else if (j >= gridHeight - 4) {
					cellType = 0;
				}
			}
			cell.type = cellType;
			cell.x = i;
			cell.y = j;
			cell.upLeft = self.cells[i - 1] && self.cells[i - 1][j - 1];
			cell.up = self.cells[i - 1] && self.cells[i - 1][j];
			cell.upRight = self.cells[i - 1] && self.cells[i - 1][j + 1];
			cell.left = self.cells[i][j - 1];
			cell.right = self.cells[i][j + 1];
			cell.downLeft = self.cells[i + 1] && self.cells[i + 1][j - 1];
			cell.down = self.cells[i + 1] && self.cells[i + 1][j];
			cell.downRight = self.cells[i + 1] && self.cells[i + 1][j + 1];
			cell.neighbors = [cell.upLeft, cell.up, cell.upRight, cell.right, cell.downRight, cell.down, cell.downLeft, cell.left];
			cell.targets = [];
			if (j > 3 && j <= gridHeight - 4) {
				var debugCell = new DebugCell();
				self.addChild(debugCell);
				debugCell.cell = cell;
				debugCell.x = i * CELL_SIZE;
				debugCell.y = j * CELL_SIZE;
				cell.debugCell = debugCell;
			}
		}
	}
	self.getCell = function (x, y) {
		return self.cells[x] && self.cells[x][y];
	};
	self.pathFind = function () {
		var before = new Date().getTime();
		var toProcess = self.goals.concat([]);
		maxScore = 0;
		pathId += 1;
		for (var a = 0; a < toProcess.length; a++) {
			toProcess[a].pathId = pathId;
		}
		function processNode(node, targetValue, targetNode) {
			if (node && node.type != 1) {
				if (node.pathId < pathId || targetValue < node.score) {
					node.targets = [targetNode];
				} else if (node.pathId == pathId && targetValue == node.score) {
					node.targets.push(targetNode);
				}
				if (node.pathId < pathId || targetValue < node.score) {
					node.score = targetValue;
					if (node.pathId != pathId) {
						toProcess.push(node);
					}
					node.pathId = pathId;
					if (targetValue > maxScore) {
						maxScore = targetValue;
					}
				}
			}
		}
		while (toProcess.length) {
			var nodes = toProcess;
			toProcess = [];
			for (var a = 0; a < nodes.length; a++) {
				var node = nodes[a];
				var targetScore = node.score + 14142;
				if (node.up && node.left && node.up.type != 1 && node.left.type != 1) {
					processNode(node.upLeft, targetScore, node);
				}
				if (node.up && node.right && node.up.type != 1 && node.right.type != 1) {
					processNode(node.upRight, targetScore, node);
				}
				if (node.down && node.right && node.down.type != 1 && node.right.type != 1) {
					processNode(node.downRight, targetScore, node);
				}
				if (node.down && node.left && node.down.type != 1 && node.left.type != 1) {
					processNode(node.downLeft, targetScore, node);
				}
				targetScore = node.score + 10000;
				processNode(node.up, targetScore, node);
				processNode(node.right, targetScore, node);
				processNode(node.down, targetScore, node);
				processNode(node.left, targetScore, node);
			}
		}
		for (var a = 0; a < self.spawns.length; a++) {
			if (self.spawns[a].pathId != pathId) {
				console.warn("Spawn blocked");
				return true;
			}
		}
		for (var a = 0; a < enemies.length; a++) {
			var enemy = enemies[a];
			// Skip enemies that haven't entered the viewable area yet
			if (enemy.currentCellY < 4) {
				continue;
			}
			// Skip flying enemies from path check as they can fly over obstacles
			if (enemy.isFlying) {
				continue;
			}
			var target = self.getCell(enemy.cellX, enemy.cellY);
			if (enemy.currentTarget) {
				if (enemy.currentTarget.pathId != pathId) {
					if (!target || target.pathId != pathId) {
						console.warn("Enemy blocked 1 ");
						return true;
					}
				}
			} else if (!target || target.pathId != pathId) {
				console.warn("Enemy blocked 2");
				return true;
			}
		}
		console.log("Speed", new Date().getTime() - before);
	};
	self.renderDebug = function () {
		for (var i = 0; i < gridWidth; i++) {
			for (var j = 0; j < gridHeight; j++) {
				var debugCell = self.cells[i][j].debugCell;
				if (debugCell) {
					debugCell.render(self.cells[i][j]);
				}
			}
		}
	};
	self.updateEnemy = function (enemy) {
		var cell = grid.getCell(enemy.cellX, enemy.cellY);
		if (cell.type == 3) {
			return true;
		}
		if (enemy.isFlying && enemy.shadow) {
			enemy.shadow.x = enemy.x + 20; // Match enemy x-position + offset
			enemy.shadow.y = enemy.y + 20; // Match enemy y-position + offset
			// Match shadow rotation with enemy rotation
			if (enemy.children[0] && enemy.shadow.children[0]) {
				enemy.shadow.children[0].rotation = enemy.children[0].rotation;
			}
		}
		// Check if the enemy has reached the entry area (y position is at least 5)
		var hasReachedEntryArea = enemy.currentCellY >= 4;
		// If enemy hasn't reached the entry area yet, just move down vertically
		if (!hasReachedEntryArea) {
			// Move directly downward
			enemy.currentCellY += enemy.speed;
			// Rotate enemy graphic to face downward (PI/2 radians = 90 degrees)
			var angle = Math.PI / 2;
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update enemy's position
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// If enemy has now reached the entry area, update cell coordinates
			if (enemy.currentCellY >= 4) {
				enemy.cellX = Math.round(enemy.currentCellX);
				enemy.cellY = Math.round(enemy.currentCellY);
			}
			return false;
		}
		// After reaching entry area, handle flying enemies differently
		if (enemy.isFlying) {
			// Flying enemies head straight to the closest goal
			if (!enemy.flyingTarget) {
				// Set flying target to the closest goal
				enemy.flyingTarget = self.goals[0];
				// Find closest goal if there are multiple
				if (self.goals.length > 1) {
					var closestDist = Infinity;
					for (var i = 0; i < self.goals.length; i++) {
						var goal = self.goals[i];
						var dx = goal.x - enemy.cellX;
						var dy = goal.y - enemy.cellY;
						var dist = dx * dx + dy * dy;
						if (dist < closestDist) {
							closestDist = dist;
							enemy.flyingTarget = goal;
						}
					}
				}
			}
			// Move directly toward the goal
			var ox = enemy.flyingTarget.x - enemy.currentCellX;
			var oy = enemy.flyingTarget.y - enemy.currentCellY;
			var dist = Math.sqrt(ox * ox + oy * oy);
			if (dist < enemy.speed) {
				// Reached the goal
				return true;
			}
			var angle = Math.atan2(oy, ox);
			// Rotate enemy graphic to match movement direction
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update the cell position to track where the flying enemy is
			enemy.cellX = Math.round(enemy.currentCellX);
			enemy.cellY = Math.round(enemy.currentCellY);
			enemy.currentCellX += Math.cos(angle) * enemy.speed;
			enemy.currentCellY += Math.sin(angle) * enemy.speed;
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// Update shadow position if this is a flying enemy
			return false;
		}
		// Handle normal pathfinding enemies
		if (!enemy.currentTarget) {
			enemy.currentTarget = cell.targets[0];
		}
		if (enemy.currentTarget) {
			if (cell.score < enemy.currentTarget.score) {
				enemy.currentTarget = cell;
			}
			var ox = enemy.currentTarget.x - enemy.currentCellX;
			var oy = enemy.currentTarget.y - enemy.currentCellY;
			var dist = Math.sqrt(ox * ox + oy * oy);
			if (dist < enemy.speed) {
				enemy.cellX = Math.round(enemy.currentCellX);
				enemy.cellY = Math.round(enemy.currentCellY);
				enemy.currentTarget = undefined;
				return;
			}
			var angle = Math.atan2(oy, ox);
			enemy.currentCellX += Math.cos(angle) * enemy.speed;
			enemy.currentCellY += Math.sin(angle) * enemy.speed;
		}
		enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
		enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
	};
});
var NextWaveButton = Container.expand(function () {
	var self = Container.call(this);
	var buttonBackground = self.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 300;
	buttonBackground.height = 100;
	buttonBackground.tint = 0xffffff;
	var buttonText = new Text2("Next Wave", {
		size: 50,
		fill: 0xff0080,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	self.addChild(buttonText);
	self.enabled = false;
	self.visible = false;
	self.update = function () {
		if (waveIndicator && waveIndicator.gameStarted && currentWave < totalWaves) {
			self.enabled = true;
			self.visible = true;
			buttonBackground.tint = 0x00ffb3;
			self.alpha = 1;
		} else {
			self.enabled = false;
			self.visible = false;
			buttonBackground.tint = 0xffffff;
			self.alpha = 0.7;
		}
	};
	self.down = function () {
		if (!self.enabled) {
			return;
		}
		if (waveIndicator.gameStarted && currentWave < totalWaves) {
			currentWave++; // Increment to the next wave directly
			waveTimer = 0; // Reset wave timer
			waveInProgress = true;
			waveSpawned = false;
			// Get the type of the current wave (which is now the next wave)
			var waveType = waveIndicator.getWaveTypeName(currentWave);
			var enemyCount = waveIndicator.getEnemyCount(currentWave);
			var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) activated!"));
		}
	};
	return self;
});
var Notification = Container.expand(function (message) {
	var self = Container.call(this);
	var notificationGraphics = self.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var isSmallNotification = message === "Cannot build here!";
	// Set fixed size to 1700x600px
	notificationGraphics.width = 1700;
	notificationGraphics.height = 600;
	if (isSmallNotification) {
		notificationGraphics.width = 1100;
		notificationGraphics.height = 300;
	}
	// Parse message to extract wave info for two-line formatting
	var displayMessage = message;
	var isWaveMessage = false;
	var waveInfo = "";
	var waveDetails = "";
	// Check if this is a wave message
	if (message.includes("Wave ") && (message.includes("incoming!") || message.includes("activated!"))) {
		isWaveMessage = true;
		// Extract wave number and type
		var waveMatch = message.match(/Wave (\d+) \(([^)]+)\)/);
		if (waveMatch) {
			var waveNumber = waveMatch[1];
			var waveTypeInfo = waveMatch[2];
			waveInfo = "Wave " + waveNumber;
			waveDetails = waveTypeInfo;
			displayMessage = waveInfo + "\n" + waveDetails;
		}
	}
	var notificationText = new Text2("", {
		size: isWaveMessage ? 90 : 90,
		fill: 0xff0080,
		weight: 800,
		align: 'center'
	});
	notificationText.anchor.set(0.5, 0.5);
	self.addChild(notificationText);
	// Position notification in center of screen
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	self.alpha = 0;
	self.scaleX = 0.3;
	self.scaleY = 0.3;
	// Electronic text animation variables
	var currentCharIndex = 0;
	var displayText = "";
	var electronicTimer = 0;
	var charDelay = 4; // frames between characters for electronic typing effect
	var isAnimatingText = true;
	// Add electronic glitch effect
	var glitchTimer = 0;
	var originalMessage = displayMessage;
	// Entrance animation - scale up and fade in
	tween(self, {
		alpha: 1,
		scaleX: 1.1,
		scaleY: 1.1
	}, {
		duration: 300,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			// Settle to normal size
			tween(self, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 200,
				easing: tween.easeOut
			});
		}
	});
	var fadeOutTime = 240;
	self.update = function () {
		// Electronic text animation
		if (isAnimatingText && electronicTimer % charDelay === 0) {
			if (currentCharIndex < originalMessage.length) {
				displayText += originalMessage[currentCharIndex];
				notificationText.setText(displayText);
				currentCharIndex++;
			} else {
				isAnimatingText = false;
			}
		}
		electronicTimer++;
		// Add subtle glitch effect after text is complete
		if (!isAnimatingText) {
			glitchTimer++;
			if (glitchTimer % 60 === 0) {
				// Glitch every second
				// Briefly change one random character
				if (Math.random() < 0.1) {
					var glitchChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?`~";
					var randomChar = glitchChars[Math.floor(Math.random() * glitchChars.length)];
					var glitchIndex = Math.floor(Math.random() * displayText.length);
					var glitchedText = displayText.substring(0, glitchIndex) + randomChar + displayText.substring(glitchIndex + 1);
					notificationText.setText(glitchedText);
					// Restore original text after 3 frames
					LK.setTimeout(function () {
						notificationText.setText(displayText);
					}, 50);
				}
			}
		}
		if (fadeOutTime > 0) {
			fadeOutTime--;
			if (fadeOutTime <= 60) {
				// Exit animation - scale down and fade out
				if (!self.exitAnimStarted) {
					self.exitAnimStarted = true;
					tween(self, {
						alpha: 0,
						scaleX: 0.8,
						scaleY: 0.8
					}, {
						duration: 300,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							self.destroy();
						}
					});
				}
			}
		} else if (!self.exitAnimStarted) {
			self.destroy();
		}
	};
	return self;
});
var Ship = Container.expand(function (type) {
	var self = Container.call(this);
	self.type = type || 1; // Ship type 1, 2, or 3
	self.speed = 2 + Math.random() * 2; // Random speed between 2-4
	self.direction = Math.random() < 0.5 ? 1 : -1; // 1 for left to right, -1 for right to left
	// Select ship asset based on type
	var shipAsset = 'Ship' + self.type;
	var shipGraphics = self.attachAsset(shipAsset, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Play ship sound based on ship type
	var shipSound = 'Ship' + self.type + 'sound';
	game.playSoundWithVolume(shipSound);
	// Flip ship if moving right to left
	if (self.direction === -1) {
		shipGraphics.scaleX = -1;
	}
	// Calculate game field boundaries
	var gridLeft = 150; // grid.x value
	var gridWidth = 24 * 76; // 24 cells * CELL_SIZE
	var gridRight = gridLeft + gridWidth; // 150 + 1824 = 1974
	// Calculate vertical boundaries based on grid position
	var gridTop = 200 - 76 * 4; // grid.y value (200 - CELL_SIZE * 4)
	var gridHeight = (29 + 6) * 76; // (29 + 6) cells * CELL_SIZE
	var gridBottom = gridTop + gridHeight;
	// Random Y position within the game field boundaries
	self.y = gridTop + Math.random() * gridHeight;
	// Set starting X position based on direction, spawning from field edges
	if (self.direction === 1) {
		// Moving left to right, start from left edge of field
		self.x = gridLeft - shipGraphics.width / 2;
	} else {
		// Moving right to left, start from right edge of field
		self.x = gridRight + shipGraphics.width / 2;
	}
	self.update = function () {
		self.x += self.speed * self.direction;
		// Check if ship has moved off the opposite field edge
		if (self.direction === 1 && self.x > gridRight + shipGraphics.width) {
			self.destroy();
		} else if (self.direction === -1 && self.x < gridLeft - shipGraphics.width) {
			self.destroy();
		}
		// Initialize sound timer if not set
		if (self.soundTimer === undefined) {
			self.soundTimer = 0;
		}
		// Increment sound timer
		self.soundTimer++;
		// Play ship sound every 120 frames (2 seconds at 60 FPS)
		if (self.soundTimer % 120 === 0) {
			var shipSound = 'Ship' + self.type + 'sound';
			game.playSoundWithVolume(shipSound);
		}
	};
	return self;
});
var SourceTower = Container.expand(function (towerType) {
	var self = Container.call(this);
	self.towerType = towerType || 'cannon';
	// Use specific tower asset based on type
	var towerAssetId = 'CannonTower'; // default
	switch (self.towerType) {
		case 'rifle':
			towerAssetId = 'RifleTower';
			break;
		case 'flame':
			towerAssetId = 'FlameTower';
			break;
		case 'Rocket':
			towerAssetId = 'RocketTower';
			break;
		case 'gumbomb':
			towerAssetId = 'GumBombTower';
			break;
		case 'ToxinBomb':
			towerAssetId = 'ToxinBombTower';
			break;
		case 'cannon':
		default:
			towerAssetId = 'CannonTower';
			break;
	}
	// Increase size of base for easier touch
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.3,
		scaleY: 1.3
	});
	// No need to tint as we're using specific tower assets
	var towerCost = getTowerCost(self.towerType);
	// Add shadow for tower type label
	var typeLabelShadow = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	typeLabelShadow.anchor.set(0.5, 0.5);
	typeLabelShadow.x = 4;
	typeLabelShadow.y = -20 + 4;
	self.addChild(typeLabelShadow);
	// Add tower type label
	var displayName = self.towerType === 'rifle' ? 'Rifle' : self.towerType === 'ToxinBomb' ? 'Toxinbomb' : self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1);
	// Set color based on tower type
	var towerColor = 0xFFFFFF; // default white
	switch (self.towerType) {
		case 'cannon':
			towerColor = 0xff0080;
			break;
		case 'rifle':
			towerColor = 0xff0080;
			break;
		case 'flame':
			towerColor = 0xff0080;
			break;
		case 'Rocket':
			towerColor = 0xff0080;
			break;
		case 'gumbomb':
			towerColor = 0xff0080;
			break;
		case 'ToxinBomb':
			towerColor = 0xff0080;
			break;
	}
	var typeLabel = new Text2(displayName, {
		size: 50,
		fill: towerColor,
		weight: 800
	});
	typeLabel.anchor.set(0.5, 0.5);
	typeLabel.y = -20; // Position above center of tower
	self.addChild(typeLabel);
	// Add cost shadow
	var costLabelShadow = new Text2(towerCost, {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	costLabelShadow.anchor.set(0.5, 0.5);
	costLabelShadow.x = 4;
	costLabelShadow.y = 24 + 12;
	self.addChild(costLabelShadow);
	// Add cost label
	var costLabel = new Text2(towerCost, {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	costLabel.anchor.set(0.5, 0.5);
	costLabel.y = 20 + 12;
	self.addChild(costLabel);
	self.update = function () {
		// Check if player can afford this tower
		var canAfford = crystals >= getTowerCost(self.towerType);
		// Set opacity based on affordability
		self.alpha = canAfford ? 1 : 0.5;
	};
	return self;
});
var SpeakingGirl = Container.expand(function () {
	var self = Container.call(this);
	var girlAsset1 = self.attachAsset('Girl1', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 500,
		height: 500
	});
	var girlAsset2 = self.attachAsset('Girl2', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 500,
		height: 500
	});
	var girlAsset3 = self.attachAsset('Girl3', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 500,
		height: 500
	});
	var allGirlAssets = [girlAsset1, girlAsset2, girlAsset3];
	// Girl1 is index 0, Girl2 is 1, Girl3 is 2
	var animationSequence = [0, 1, 0, 2];
	var currentFrameIndexInSequence = 0;
	var animationInterval = null;
	var hasStartedAnimation = false;
	function setFrame(assetIndex) {
		for (var i = 0; i < allGirlAssets.length; i++) {
			allGirlAssets[i].visible = i === assetIndex;
		}
	}
	function animate() {
		currentFrameIndexInSequence = (currentFrameIndexInSequence + 1) % animationSequence.length;
		var assetIndexToShow = animationSequence[currentFrameIndexInSequence];
		setFrame(assetIndexToShow);
	}
	function startSpeakingAnimation() {
		if (!hasStartedAnimation) {
			hasStartedAnimation = true;
			animationInterval = LK.setInterval(animate, 300);
			for (var i = 0; i < game.children.length; i++) {
				if (game.children[i] instanceof Tablet) {
					game.children[i].startAnimation();
					break;
				}
			}
		}
	}
	// Start at right edge of screen, move to left side
	self.x = 2048 - 250; // Start from right edge (250 = half of 500px width)
	self.y = 2732 - 250; // 250 = half of 500px height, so bottom edge inside
	setFrame(0); // Start with Girl1
	// Move from right to left side
	tween(self, {
		x: 0 + 250 // Move to left edge inside screen
	}, {
		duration: 2000,
		// 2 second movement
		easing: tween.easeOut,
		onFinish: function onFinish() {
			// Start animation when reaching left side
			startSpeakingAnimation();
		}
	});
	var originalDestroy = self.destroy;
	self.destroy = function () {
		if (animationInterval) {
			LK.clearInterval(animationInterval);
		}
		tween.stop(self);
		originalDestroy.call(self);
	};
	return self;
});
var Tablet = Container.expand(function () {
	var self = Container.call(this);
	var tabletGraphics = self.attachAsset('Tablet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Position tablet in center of screen
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	// Message to display with electronic character animation - formatted with more lines
	var message = "Hi! I'm the high commander:\n\nWe shall begin a war with\nthe enemies, nothing will\nstand in our ways,\n\nwe will destroy them and\nwe prove our supremacy,\n\nwe will not rest until\nvictory is ours!";
	// Create text with 100px spacing from sides
	var messageText = new Text2("", {
		size: 80,
		fill: 0xff0080,
		weight: 800
	});
	messageText.anchor.set(0.5, 0.5);
	self.addChild(messageText);
	// Animation variables
	var currentChar = 0;
	var displayText = "";
	var animationTimer = 0;
	var charDelay = 3; // Frames between characters (electronic typing effect)
	var isAnimating = false;
	self.startAnimation = function () {
		isAnimating = true;
	};
	self.update = function () {
		if (isAnimating && animationTimer % charDelay === 0) {
			if (currentChar < message.length) {
				displayText += message[currentChar];
				messageText.setText(displayText);
				currentChar++;
			} else {
				isAnimating = false;
				// Auto-destroy after message is complete and a short delay
				tween(self, {
					alpha: 0
				}, {
					duration: 1000,
					delay: 3000,
					// Wait 3 seconds after text is complete
					easing: tween.easeOut,
					onFinish: function onFinish() {
						// Remove girl character when tablet is destroyed
						if (girlCharacter && girlCharacter.parent) {
							girlCharacter.destroy();
							girlCharacter = null;
						}
						self.destroy();
						// Show game started notification
						var notification = game.addChild(new Notification("Game started!\nPrepare for battle!"));
						var originalDestroy = notification.destroy;
						notification.destroy = function () {
							canStartWaves = true;
							canPlaceTowers = true;
							originalDestroy.call(this);
						};
					}
				});
			}
		}
		animationTimer++;
	};
	return self;
});
var Tower = Container.expand(function (id) {
	var self = Container.call(this);
	self.id = id || 'cannon';
	self.level = 1;
	self.maxLevel = 6;
	self.gridX = 0;
	self.gridY = 0;
	self.range = 3 * CELL_SIZE;
	// Standardized method to get the current range of the tower
	self.getRange = function () {
		// Always calculate range based on tower type and level
		switch (self.id) {
			case 'flame':
				// Flame: base 5, +0.8 per level, but final upgrade gets a huge boost
				if (self.level === self.maxLevel) {
					return 12 * CELL_SIZE; // Significantly increased range for max level
				}
				return (5 + (self.level - 1) * 0.8) * CELL_SIZE;
			case 'Rocket':
				// Rocket: base range higher than sniper, +0.8 per level
				if (self.level === self.maxLevel) {
					return 14 * CELL_SIZE; // Higher than sniper's max range
				}
				return (6 + (self.level - 1) * 0.8) * CELL_SIZE;
			case 'rifle':
				// Rifle: base 3 (default), +0.5 per level
				return (3 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'gumbomb':
				// GumBomb: base 3.5, +0.5 per level
				return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'ToxinBomb':
				// ToxinBomb: base 3.2, +0.5 per level
				return (3.2 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'cannon':
				// Cannon: base 3, +0.5 per level
				return (3 + (self.level - 1) * 0.5) * CELL_SIZE;
				break;
			default:
				// Default: base 3, +0.5 per level
				return (3 + (self.level - 1) * 0.5) * CELL_SIZE;
		}
	};
	self.cellsInRange = [];
	self.fireRate = 60;
	self.bulletSpeed = 5;
	self.damage = 7;
	self.lastFired = 0;
	self.targetEnemy = null;
	self.flameEffect = null; // Track active flame effect for flame tower
	self.flameAnimation = null; // Track flame animation visual
	switch (self.id) {
		case 'rifle':
			self.fireRate = Math.floor(60 / 3.5); // 3.5 shots per second = 60/3.5 = 17 frames
			self.damage = 5;
			self.range = 3 * CELL_SIZE; // Default tower range
			self.bulletSpeed = 7;
			break;
		case 'flame':
			self.fireRate = 120; // 0.5 shots per second
			self.damage = 9;
			self.range = 5 * CELL_SIZE;
			self.bulletSpeed = 25;
			break;
		case 'Rocket':
			self.fireRate = Math.floor(60 / 1.0); // 1.0 shots per second = 60 frames
			self.damage = 13;
			self.range = 2 * CELL_SIZE;
			self.bulletSpeed = 8;
			break;
		case 'gumbomb':
			self.fireRate = 50;
			self.damage = 3;
			self.range = 3.5 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
		case 'ToxinBomb':
			self.fireRate = 70;
			self.damage = 18;
			self.range = 3.2 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
	}
	// Use specific tower asset based on type
	var towerAssetId = 'CannonTower'; // default
	switch (self.id) {
		case 'rifle':
			towerAssetId = 'RifleTower';
			break;
		case 'flame':
			towerAssetId = 'FlameTower';
			break;
		case 'Rocket':
			towerAssetId = 'RocketTower';
			break;
		case 'gumbomb':
			towerAssetId = 'GumBombTower';
			break;
		case 'ToxinBomb':
			towerAssetId = 'ToxinBombTower';
			break;
		case 'cannon':
		default:
			towerAssetId = 'CannonTower';
			break;
	}
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No need to tint as we're using specific tower assets
	var levelIndicators = [];
	var maxDots = self.maxLevel;
	var dotSpacing = baseGraphics.width / (maxDots + 1);
	var dotSize = 30;
	for (var i = 0; i < maxDots; i++) {
		var dot = new Container();
		var outlineCircle = dot.attachAsset('towerLevelIndicator', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		outlineCircle.width = dotSize + 4;
		outlineCircle.height = dotSize + 4;
		outlineCircle.tint = 0x000000;
		var towerLevelIndicator = dot.attachAsset('towerLevelIndicator', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		towerLevelIndicator.width = dotSize;
		towerLevelIndicator.height = dotSize;
		towerLevelIndicator.tint = 0xCCCCCC;
		dot.x = dotSpacing * (i + 1) - baseGraphics.width / 2;
		dot.y = -CELL_SIZE * 1.2;
		self.addChild(dot);
		levelIndicators.push(dot);
	}
	var gunContainer = new Container();
	self.addChild(gunContainer);
	var weaponAssetId = 'Weapon1'; // default
	switch (self.id) {
		case 'rifle':
			weaponAssetId = 'Weapon2';
			break;
		case 'flame':
			weaponAssetId = 'Weapon3';
			break;
		case 'Rocket':
			weaponAssetId = 'Weapon4';
			break;
		case 'gumbomb':
			weaponAssetId = 'Weapon5';
			break;
		case 'ToxinBomb':
			weaponAssetId = 'Weapon6';
			break;
		case 'cannon':
		default:
			weaponAssetId = 'Weapon1';
			break;
	}
	var gunGraphics = gunContainer.attachAsset(weaponAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.updateLevelIndicators = function () {
		for (var i = 0; i < maxDots; i++) {
			var dot = levelIndicators[i];
			var towerLevelIndicator = dot.children[1];
			if (i < self.level) {
				towerLevelIndicator.tint = 0xff0080;
			} else {
				switch (self.id) {
					case 'rifle':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'flame':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'Rocket':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'gumbomb':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'ToxinBomb':
						towerLevelIndicator.tint = 0xffffff;
						break;
					default:
						towerLevelIndicator.tint = 0xffffff;
				}
			}
		}
	};
	self.updateLevelIndicators();
	self.refreshCellsInRange = function () {
		for (var i = 0; i < self.cellsInRange.length; i++) {
			var cell = self.cellsInRange[i];
			var towerIndex = cell.towersInRange.indexOf(self);
			if (towerIndex !== -1) {
				cell.towersInRange.splice(towerIndex, 1);
			}
		}
		self.cellsInRange = [];
		var rangeRadius = self.getRange() / CELL_SIZE;
		var centerX = self.gridX + 1;
		var centerY = self.gridY + 1;
		var minI = Math.floor(centerX - rangeRadius - 0.5);
		var maxI = Math.ceil(centerX + rangeRadius + 0.5);
		var minJ = Math.floor(centerY - rangeRadius - 0.5);
		var maxJ = Math.ceil(centerY + rangeRadius + 0.5);
		for (var i = minI; i <= maxI; i++) {
			for (var j = minJ; j <= maxJ; j++) {
				var closestX = Math.max(i, Math.min(centerX, i + 1));
				var closestY = Math.max(j, Math.min(centerY, j + 1));
				var deltaX = closestX - centerX;
				var deltaY = closestY - centerY;
				var distanceSquared = deltaX * deltaX + deltaY * deltaY;
				if (distanceSquared <= rangeRadius * rangeRadius) {
					var cell = grid.getCell(i, j);
					if (cell) {
						self.cellsInRange.push(cell);
						cell.towersInRange.push(self);
					}
				}
			}
		}
		grid.renderDebug();
	};
	self.getTotalValue = function () {
		var baseTowerCost = getTowerCost(self.id);
		var totalInvestment = baseTowerCost;
		var baseUpgradeCost = baseTowerCost; // Upgrade cost now scales with base tower cost
		for (var i = 1; i < self.level; i++) {
			totalInvestment += Math.floor(baseUpgradeCost * Math.pow(2, i - 1));
		}
		return totalInvestment;
	};
	self.upgrade = function () {
		if (self.level < self.maxLevel) {
			// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
			var baseUpgradeCost = getTowerCost(self.id);
			var upgradeCost;
			// Make last upgrade level extra expensive
			if (self.level === self.maxLevel - 1) {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.level - 1) * 3.5 / 2); // Half the cost for final upgrade
			} else {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.level - 1));
			}
			if (crystals >= upgradeCost) {
				setCrystals(crystals - upgradeCost);
				self.level++;
				// No need to update self.range here; getRange() is now the source of truth
				// Apply tower-specific upgrades based on type
				if (self.id === 'rifle') {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade (double the effect)
						self.fireRate = Math.max(4, 12 - self.level * 3); // double the effect, starting from 12
						self.damage = 8 + self.level * 8; // double the effect, starting from 8
						self.bulletSpeed = 7 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(6, 12 - self.level * 1); // Rifle gets faster with upgrades, starting from 12
						self.damage = 8 + self.level * 2; // Starting from 8 damage
						self.bulletSpeed = 7 + self.level * 0.7;
					}
				} else {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade for all other towers (double the effect)
						self.fireRate = Math.max(5, 60 - self.level * 24); // double the effect
						self.damage = 10 + self.level * 20; // double the effect
						self.bulletSpeed = 5 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(20, 60 - self.level * 8);
						self.damage = 10 + self.level * 5;
						self.bulletSpeed = 5 + self.level * 0.5;
					}
				}
				self.refreshCellsInRange();
				self.updateLevelIndicators();
				if (self.level > 1) {
					var levelDot = levelIndicators[self.level - 1].children[1];
					tween(levelDot, {
						scaleX: 1.5,
						scaleY: 1.5
					}, {
						duration: 300,
						easing: tween.elasticOut,
						onFinish: function onFinish() {
							tween(levelDot, {
								scaleX: 1,
								scaleY: 1
							}, {
								duration: 200,
								easing: tween.easeOut
							});
						}
					});
				}
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough crystals to upgrade!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.findTarget = function () {
		var closestEnemy = null;
		var closestScore = Infinity;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			// Check if enemy is in range
			if (distance <= self.getRange()) {
				// Handle flying enemies differently - they can be targeted regardless of path
				if (enemy.isFlying) {
					// For flying enemies, prioritize by distance to the goal
					if (enemy.flyingTarget) {
						var goalX = enemy.flyingTarget.x;
						var goalY = enemy.flyingTarget.y;
						var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY));
						// Use distance to goal as score
						if (distToGoal < closestScore) {
							closestScore = distToGoal;
							closestEnemy = enemy;
						}
					} else {
						// If no flying target yet (shouldn't happen), prioritize by distance to tower
						if (distance < closestScore) {
							closestScore = distance;
							closestEnemy = enemy;
						}
					}
				} else {
					// For ground enemies, use the original path-based targeting
					// Get the cell for this enemy
					var cell = grid.getCell(enemy.cellX, enemy.cellY);
					if (cell && cell.pathId === pathId) {
						// Use the cell's score (distance to exit) for prioritization
						// Lower score means closer to exit
						if (cell.score < closestScore) {
							closestScore = cell.score;
							closestEnemy = enemy;
						}
					}
				}
			}
		}
		if (!closestEnemy) {
			self.targetEnemy = null;
		}
		return closestEnemy;
	};
	self.update = function () {
		// Handle tower boost effect
		if (self.boosted) {
			self.boostDuration--;
			if (self.boostDuration <= 0) {
				self.boosted = false;
				self.damage = self.originalDamage;
			}
		}
		self.targetEnemy = self.findTarget();
		if (!self.targetEnemy) {
			if (self.flameAnimation) {
				self.flameAnimation.destroy();
				self.flameAnimation = null;
			}
			if (self.flameEffect) {
				self.flameEffect.destroy();
				self.flameEffect = null;
			}
		}
		if (self.targetEnemy) {
			var dx = self.targetEnemy.x - self.x;
			var dy = self.targetEnemy.y - self.y;
			var angle = Math.atan2(dy, dx);
			// Smooth gun rotation using tween
			if (gunContainer.targetRotation === undefined) {
				gunContainer.targetRotation = angle;
				gunContainer.rotation = angle;
			} else {
				if (Math.abs(angle - gunContainer.targetRotation) > 0.05) {
					tween.stop(gunContainer, {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = gunContainer.rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					gunContainer.targetRotation = angle;
					tween(gunContainer, {
						rotation: currentRotation + angleDiff
					}, {
						duration: 200,
						easing: tween.easeOut
					});
				}
			}
			// Flame tower has special continuous firing logic
			if (self.id === 'flame') {
				// Continuously apply damage if an enemy is targeted
				if (self.targetEnemy && self.isInRange(self.targetEnemy)) {
					// Apply damage every frame while the enemy is in range and alive
					if (self.targetEnemy.health > 0) {
						var actualDamage = self.damage / 60; // Damage per second (damage/60 FPS)
						if (self.targetEnemy.damageResistance) {
							actualDamage = actualDamage * self.targetEnemy.damageResistance;
						}
						self.targetEnemy.health -= actualDamage;
						// Ensure health doesn't go below zero
						if (self.targetEnemy.health <= 0) {
							self.targetEnemy.health = 0;
						} else {
							// Update enemy health bar using stored original width
							var healthPercentage = self.targetEnemy.health / self.targetEnemy.maxHealth;
							self.targetEnemy.healthBar.width = self.targetEnemy.healthBarOriginalWidth * healthPercentage;
						}
						// --- Flame Visuals ---
						var dx = self.targetEnemy.x - self.x;
						var dy = self.targetEnemy.y - self.y;
						var distance = Math.sqrt(dx * dx + dy * dy);
						// Create flame animation from the gun if not already active
						if (!self.flameAnimation) {
							self.flameAnimation = new Container();
							var flameGraphics = self.flameAnimation.attachAsset('Flame', {
								anchorX: 0,
								// Anchor at the base (left) of the flame
								anchorY: 0.5 // Anchor in the middle vertically
							});
							// The Flame asset needs no rotation as it should extend horizontally from the gun
							flameGraphics.rotation = 0;
							flameGraphics.tint = 0xFF8800;
							gunContainer.addChild(self.flameAnimation);
							// Position at the front edge of the gun barrel
							self.flameAnimation.x = gunGraphics.width / 2 + 20;
							// Set initial scale for appear animation
							flameGraphics.scale.set(0, 0.6);
							// Initialize flame sound timer
							self.flameSoundTimer = 0;
						}
						// Play flame sound repeatedly while burning
						if (!self.flameSoundTimer) {
							self.flameSoundTimer = 0;
						}
						self.flameSoundTimer++;
						// Play flame sound every 30 frames (0.5 seconds at 60 FPS) while actively burning
						if (self.flameSoundTimer % 30 === 0) {
							game.playSoundWithVolume('Flamesound');
						}
						// Update the flame animation every frame to stretch and flicker
						if (self.flameAnimation && self.flameAnimation.children[0]) {
							var flameGraphics = self.flameAnimation.children[0];
							// The flame asset is 300px long (originally height)
							var flameAssetLength = 300;
							var targetScaleX = distance / flameAssetLength;
							// Animate the flame length
							flameGraphics.scale.x += (targetScaleX - flameGraphics.scale.x) * 0.3;
							// Use a sinusoidal flicker for a more natural look on the width
							var flicker = Math.sin(LK.ticks * 0.5) * 0.1;
							flameGraphics.scale.y = 0.6 + flicker;
						}
						// Show visual effect on the enemy
						if (!self.flameEffect) {
							self.flameEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'flame');
							game.addChild(self.flameEffect);
						}
						// Update the position of the flame effect to match the target enemy
						self.flameEffect.x = self.targetEnemy.x;
						self.flameEffect.y = self.targetEnemy.y;
					} else {
						// Target is dead, destroy flame animation and effect
						if (self.flameAnimation) {
							self.flameAnimation.destroy();
							self.flameAnimation = null;
						}
						if (self.flameEffect) {
							self.flameEffect.destroy();
							self.flameEffect = null;
						}
					}
				} else {
					// No target enemy in range, destroy flame animation and effect
					if (self.flameAnimation) {
						self.flameAnimation.destroy();
						self.flameAnimation = null;
					}
					if (self.flameEffect) {
						self.flameEffect.destroy();
						self.flameEffect = null;
					}
				}
			} else {
				// Standard tower firing logic (single bullets)
				if (self.id === 'flame') {
					// Manage flame visibility based on fire rate cooldown
					var flameGraphics = self.flameAnimation ? self.flameAnimation.children[0] : null;
					if (flameGraphics) {
						if (LK.ticks - self.lastFired >= self.fireRate * 0.6) {
							// Show flame for 60% of fire rate
							flameGraphics.visible = true;
						} else {
							flameGraphics.visible = false;
						}
					}
					if (LK.ticks - self.lastFired >= self.fireRate) {
						self.fire();
						self.lastFired = LK.ticks;
					}
				} else {
					if (LK.ticks - self.lastFired >= self.fireRate) {
						self.fire();
						self.lastFired = LK.ticks;
					}
				}
			}
		}
	};
	self.down = function (x, y, obj) {
		var existingMenus = game.children.filter(function (child) {
			return child instanceof UpgradeMenu;
		});
		var hasOwnMenu = false;
		var rangeCircle = null;
		for (var i = 0; i < game.children.length; i++) {
			if (game.children[i].isTowerRange && game.children[i].tower === self) {
				rangeCircle = game.children[i];
				break;
			}
		}
		for (var i = 0; i < existingMenus.length; i++) {
			if (existingMenus[i].tower === self) {
				hasOwnMenu = true;
				break;
			}
		}
		if (hasOwnMenu) {
			for (var i = 0; i < existingMenus.length; i++) {
				if (existingMenus[i].tower === self) {
					hideUpgradeMenu(existingMenus[i]);
				}
			}
			if (rangeCircle) {
				game.removeChild(rangeCircle);
			}
			selectedTower = null;
			grid.renderDebug();
			return;
		}
		for (var i = 0; i < existingMenus.length; i++) {
			existingMenus[i].destroy();
		}
		for (var i = game.children.length - 1; i >= 0; i--) {
			if (game.children[i].isTowerRange) {
				game.removeChild(game.children[i]);
			}
		}
		selectedTower = self;
		var rangeIndicator = new Container();
		rangeIndicator.isTowerRange = true;
		rangeIndicator.tower = self;
		game.addChild(rangeIndicator);
		rangeIndicator.x = self.x;
		rangeIndicator.y = self.y;
		var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		rangeGraphics.width = rangeGraphics.height = self.getRange() * 2;
		rangeGraphics.alpha = 0.3;
		var upgradeMenu = new UpgradeMenu(self);
		game.addChild(upgradeMenu);
		upgradeMenu.x = 2048 / 2;
		// Center the menu on screen using asset height
		tween(upgradeMenu, {
			y: 2732 / 2
		}, {
			duration: 200,
			easing: tween.backOut
		});
		grid.renderDebug();
	};
	self.isInRange = function (enemy) {
		if (!enemy) {
			return false;
		}
		var dx = enemy.x - self.x;
		var dy = enemy.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		return distance <= self.getRange();
	};
	self.fire = function () {
		if (self.targetEnemy) {
			var potentialDamage = 0;
			for (var i = 0; i < self.targetEnemy.bulletsTargetingThis.length; i++) {
				potentialDamage += self.targetEnemy.bulletsTargetingThis[i].damage;
			}
			if (self.targetEnemy.health > potentialDamage) {
				var bulletX = self.x + Math.cos(gunContainer.rotation) * 40;
				var bulletY = self.y + Math.sin(gunContainer.rotation) * 40;
				var bullet = new Bullet(bulletX, bulletY, self.targetEnemy, self.damage, self.bulletSpeed);
				// Set bullet type based on tower type
				bullet.type = self.id;
				// Store reference to source tower for range checking (all tower types)
				bullet.sourceTower = self;
				// For Rocket towers, use Rocket asset
				if (self.id === 'Rocket') {
					// Replace bullet asset with Rocket asset
					bullet.removeChild(bullet.children[0]);
					var rocketGraphics = bullet.attachAsset('Rocket', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					rocketGraphics.tint = 0xff0000;
					rocketGraphics.width = 80;
					rocketGraphics.height = 70;
				}
				// For gumbomb tower, pass level for scaling gum effect
				if (self.id === 'gumbomb') {
					bullet.sourceTowerLevel = self.level;
				}
				// Customize bullet appearance based on tower type
				switch (self.id) {
					case 'rifle':
						// Replace bullet asset with RifleBullet asset
						bullet.removeChild(bullet.children[0]);
						var rifleGraphics = bullet.attachAsset('RifleBullet', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						rifleGraphics.tint = 0xffd900;
						rifleGraphics.width = 5;
						rifleGraphics.height = 10;
						break;
					// Remove flame bullet type creation as flame tower now applies continuous damage
					case 'Rocket':
						// Rocket bullets now use Rocket asset, styling already applied above
						break;
					case 'gumbomb':
						// Replace bullet asset with GumBomb asset
						bullet.removeChild(bullet.children[0]);
						var gumbombGraphics = bullet.attachAsset('gumbomb', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						gumbombGraphics.tint = 0xff0080;
						gumbombGraphics.width = 35;
						gumbombGraphics.height = 35;
						break;
					case 'ToxinBomb':
						// Replace bullet asset with ToxinBomb asset
						bullet.removeChild(bullet.children[0]);
						var toxinGraphics = bullet.attachAsset('ToxinBomb', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						toxinGraphics.tint = 0x01df01;
						toxinGraphics.width = 35;
						toxinGraphics.height = 35;
						break;
				}
				game.addChild(bullet);
				bullets.push(bullet);
				self.targetEnemy.bulletsTargetingThis.push(bullet);
				// Play sound for tower shots
				switch (self.id) {
					case 'cannon':
						game.playSoundWithVolume('Bulletsound');
						break;
					case 'rifle':
						game.playSoundWithVolume('Riflebulletsound');
						break;
					case 'Rocket':
						game.playSoundWithVolume('Rocketsound');
						break;
					case 'gumbomb':
						game.playSoundWithVolume('Gumbombsound');
						break;
					case 'ToxinBomb':
						game.playSoundWithVolume('Toxinbombsound');
						break;
				}
				// --- Fire recoil effect for gunContainer ---
				// Stop any ongoing recoil tweens before starting a new one
				tween.stop(gunContainer, {
					x: true,
					y: true,
					scaleX: true,
					scaleY: true
				});
				// Always use the original resting position for recoil, never accumulate offset
				if (gunContainer._restX === undefined) {
					gunContainer._restX = 0;
				}
				if (gunContainer._restY === undefined) {
					gunContainer._restY = 0;
				}
				if (gunContainer._restScaleX === undefined) {
					gunContainer._restScaleX = 1;
				}
				if (gunContainer._restScaleY === undefined) {
					gunContainer._restScaleY = 1;
				}
				// Reset to resting position before animating (in case of interrupted tweens)
				gunContainer.x = gunContainer._restX;
				gunContainer.y = gunContainer._restY;
				gunContainer.scaleX = gunContainer._restScaleX;
				gunContainer.scaleY = gunContainer._restScaleY;
				// Calculate recoil offset (recoil back along the gun's rotation)
				var recoilDistance = 8;
				var recoilX = -Math.cos(gunContainer.rotation) * recoilDistance;
				var recoilY = -Math.sin(gunContainer.rotation) * recoilDistance;
				// Animate recoil back from the resting position
				tween(gunContainer, {
					x: gunContainer._restX + recoilX,
					y: gunContainer._restY + recoilY
				}, {
					duration: 60,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						// Animate return to original position/scale
						tween(gunContainer, {
							x: gunContainer._restX,
							y: gunContainer._restY
						}, {
							duration: 90,
							easing: tween.cubicIn
						});
					}
				});
			}
		}
	};
	self.placeOnGrid = function (gridX, gridY) {
		self.gridX = gridX;
		self.gridY = gridY;
		self.x = grid.x + gridX * CELL_SIZE + CELL_SIZE / 2;
		self.y = grid.y + gridY * CELL_SIZE + CELL_SIZE / 2;
		for (var i = 0; i < 2; i++) {
			for (var j = 0; j < 2; j++) {
				var cell = grid.getCell(gridX + i, gridY + j);
				if (cell) {
					cell.type = 1;
				}
			}
		}
		self.refreshCellsInRange();
		// Play placement sound for cannon tower
		if (self.id === 'cannon') {
			game.playSoundWithVolume('placmentsound1');
		} else if (self.id === 'rifle') {
			game.playSoundWithVolume('placmentsound2');
		} else if (self.id === 'flame') {
			game.playSoundWithVolume('placmentsound3');
		} else if (self.id === 'Rocket') {
			game.playSoundWithVolume('placmentsound4');
		} else if (self.id === 'gumbomb') {
			game.playSoundWithVolume('placmentsound5');
		} else if (self.id === 'ToxinBomb') {
			game.playSoundWithVolume('placmentsound6');
		}
	};
	return self;
});
var TowerPreview = Container.expand(function () {
	var self = Container.call(this);
	var towerRange = 3;
	var rangeInPixels = towerRange * CELL_SIZE;
	self.towerType = 'cannon';
	self.hasEnoughGold = true;
	var rangeIndicator = new Container();
	self.addChild(rangeIndicator);
	var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	rangeGraphics.alpha = 0.3;
	var previewGraphics = self.attachAsset('towerpreview', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	previewGraphics.width = CELL_SIZE * 2;
	previewGraphics.height = CELL_SIZE * 2;
	self.canPlace = false;
	self.gridX = 0;
	self.gridY = 0;
	self.blockedByEnemy = false;
	self.update = function () {
		var previousHasEnoughGold = self.hasEnoughGold;
		self.hasEnoughGold = crystals >= getTowerCost(self.towerType);
		// Only update appearance if the affordability status has changed
		if (previousHasEnoughGold !== self.hasEnoughGold) {
			self.updateAppearance();
		}
	};
	self.updateAppearance = function () {
		// Use Tower class to get the source of truth for range
		var tempTower = new Tower(self.towerType);
		var previewRange = tempTower.getRange();
		// Clean up tempTower to avoid memory leaks
		if (tempTower && tempTower.destroy) {
			tempTower.destroy();
		}
		// Set range indicator using unified range logic
		rangeGraphics.width = rangeGraphics.height = previewRange * 2;
		switch (self.towerType) {
			case 'rifle':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'flame':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'Rocket':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'gumbomb':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'ToxinBomb':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'cannon':
				previewGraphics.tint = 0xFFFFFF;
				break;
			default:
				previewGraphics.tint = 0xFFFFFF;
		}
		if (!self.canPlace || !self.hasEnoughGold) {
			previewGraphics.tint = 0xffffff;
		}
	};
	self.updatePlacementStatus = function () {
		var validGridPlacement = true;
		if (self.gridY <= 4 || self.gridY + 1 >= grid.cells[0].length - 4) {
			validGridPlacement = false;
		} else {
			for (var i = 0; i < 2; i++) {
				for (var j = 0; j < 2; j++) {
					var cell = grid.getCell(self.gridX + i, self.gridY + j);
					if (!cell || cell.type !== 0) {
						validGridPlacement = false;
						break;
					}
				}
				if (!validGridPlacement) {
					break;
				}
			}
		}
		self.blockedByEnemy = false;
		if (validGridPlacement) {
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				if (enemy.currentCellY < 4) {
					continue;
				}
				// Only check non-flying enemies, flying enemies can pass over towers
				if (!enemy.isFlying) {
					if (enemy.cellX >= self.gridX && enemy.cellX < self.gridX + 2 && enemy.cellY >= self.gridY && enemy.cellY < self.gridY + 2) {
						self.blockedByEnemy = true;
						break;
					}
					if (enemy.currentTarget) {
						var targetX = enemy.currentTarget.x;
						var targetY = enemy.currentTarget.y;
						if (targetX >= self.gridX && targetX < self.gridX + 2 && targetY >= self.gridY && targetY < self.gridY + 2) {
							self.blockedByEnemy = true;
							break;
						}
					}
				}
			}
		}
		self.canPlace = validGridPlacement && !self.blockedByEnemy;
		self.hasEnoughGold = crystals >= getTowerCost(self.towerType);
		self.updateAppearance();
	};
	self.checkPlacement = function () {
		self.updatePlacementStatus();
	};
	self.snapToGrid = function (x, y) {
		var gridPosX = x - grid.x;
		var gridPosY = y - grid.y;
		self.gridX = Math.floor(gridPosX / CELL_SIZE);
		self.gridY = Math.floor(gridPosY / CELL_SIZE);
		self.x = grid.x + self.gridX * CELL_SIZE + CELL_SIZE / 2;
		self.y = grid.y + self.gridY * CELL_SIZE + CELL_SIZE / 2;
		self.checkPlacement();
	};
	return self;
});
var UpgradeMenu = Container.expand(function (tower) {
	var self = Container.call(this);
	self.tower = tower;
	var menuBackground = self.attachAsset('Notification2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Use asset dimensions instead of hardcoded values
	menuBackground.tint = 0xffffff;
	menuBackground.alpha = 0.9;
	// Set starting position offscreen using actual asset height
	self.y = 2732 + menuBackground.height / 2;
	// Define all elements
	var displayName = self.tower.id === 'rifle' ? 'Rifle' : self.tower.id === 'ToxinBomb' ? 'Toxinbomb' : self.tower.id.charAt(0).toUpperCase() + self.tower.id.slice(1);
	var fullTowerName = displayName + ' Tower';
	var towerTypeText = new Text2('', {
		size: 80,
		fill: 0xff0080,
		weight: 800
	});
	var currentNameText = '';
	var fullStatsText = 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s';
	var statsText = new Text2('', {
		size: 70,
		fill: 0xff0080,
		weight: 400
	});
	var currentStatsText = '';
	// Animation variables
	var nameAnimation = {
		text: fullTowerName,
		index: 0,
		timer: 0
	};
	var statsAnimation = {
		text: fullStatsText,
		index: 0,
		timer: 0
	};
	var animationPhase = 'name'; // name, stats, hold
	var holdTimer = 0;
	var holdDuration = 120; // 2 seconds
	var animationDelay = 2; // frames
	var upgradeButton = new Container();
	var buttonBackground = upgradeButton.attachAsset('Upgradebutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var isMaxLevel = self.tower.level >= self.tower.maxLevel;
	// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
	var baseUpgradeCost = getTowerCost(self.tower.id);
	var upgradeCost;
	if (isMaxLevel) {
		upgradeCost = 0;
	} else if (self.tower.level === self.tower.maxLevel - 1) {
		upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
	} else {
		upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1));
	}
	buttonBackground.tint = isMaxLevel ? 0x888888 : crystals >= upgradeCost ? 0x00ff00 : 0xff0000;
	var buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' crystal', {
		size: 60,
		fill: 0xff0080,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	var sellButton = new Container();
	var sellButtonBackground = sellButton.attachAsset('Sellbutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	sellButtonBackground.tint = 0xffffff;
	var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
	var sellValue = getTowerSellValue(totalInvestment);
	var sellButtonText = new Text2('Sell: +' + sellValue + ' crystal', {
		size: 60,
		fill: 0xff0080,
		weight: 800
	});
	sellButtonText.anchor.set(0.5, 0.5);
	sellButton.addChild(sellButtonText);
	var closeButton = new Container();
	var closeBackground = closeButton.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBackground.width = 90;
	closeBackground.height = 90;
	closeBackground.tint = 0x00ffb3;
	var closeText = new Text2('X', {
		size: 68,
		fill: 0xff0080,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	// Add all elements to self
	self.addChild(statsText);
	self.addChild(towerTypeText);
	self.addChild(upgradeButton);
	self.addChild(sellButton);
	self.addChild(closeButton);
	// Position all elements
	// Tower info
	towerTypeText.anchor.set(0.5, 0.5);
	towerTypeText.x = 0;
	towerTypeText.y = -175;
	statsText.anchor.set(0.5, 0.5);
	statsText.x = 0;
	statsText.y = 10;
	// Buttons
	var buttonYPos = menuBackground.height / 2 - 100 - buttonBackground.height / 2;
	upgradeButton.y = buttonYPos;
	sellButton.y = buttonYPos;
	var buttonSpacing = 20;
	sellButton.x = -sellButtonBackground.width / 2 - buttonSpacing;
	upgradeButton.x = buttonBackground.width / 2 + buttonSpacing;
	// Close button
	closeButton.x = menuBackground.width / 2 - 100;
	closeButton.y = -menuBackground.height / 2 + 250;
	upgradeButton.down = function (x, y, obj) {
		if (self.tower.level >= self.tower.maxLevel) {
			var notification = game.addChild(new Notification("Tower is already at max level!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
			return;
		}
		if (self.tower.upgrade()) {
			// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
			var baseUpgradeCost = getTowerCost(self.tower.id);
			if (self.tower.level >= self.tower.maxLevel) {
				upgradeCost = 0;
			} else if (self.tower.level === self.tower.maxLevel - 1) {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
			} else {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1));
			}
			// Update stats text and restart animation
			fullStatsText = 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s';
			statsAnimation.text = fullStatsText;
			statsAnimation.index = 0;
			statsAnimation.timer = 0;
			statsText.setText('');
			currentStatsText = '';
			animationPhase = 'name';
			nameAnimation.index = 0;
			nameAnimation.timer = 0;
			towerTypeText.setText('');
			currentNameText = '';
			buttonText.setText('Upgrade: ' + upgradeCost + ' crystal');
			var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
			var sellValue = Math.floor(totalInvestment * 0.6);
			sellButtonText.setText('Sell: +' + sellValue + ' crystal');
			if (self.tower.level >= self.tower.maxLevel) {
				buttonBackground.tint = 0x888888;
				buttonText.setText('Max Level');
			}
			var rangeCircle = null;
			for (var i = 0; i < game.children.length; i++) {
				if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
					rangeCircle = game.children[i];
					break;
				}
			}
			if (rangeCircle) {
				var rangeGraphics = rangeCircle.children[0];
				rangeGraphics.width = rangeGraphics.height = self.tower.getRange() * 2;
			} else {
				var newRangeIndicator = new Container();
				newRangeIndicator.isTowerRange = true;
				newRangeIndicator.tower = self.tower;
				game.addChildAt(newRangeIndicator, 0);
				newRangeIndicator.x = self.tower.x;
				newRangeIndicator.y = self.tower.y;
				var rangeGraphics = newRangeIndicator.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				rangeGraphics.width = rangeGraphics.height = self.tower.getRange() * 2;
				rangeGraphics.alpha = 0.3;
			}
			tween(self, {
				scaleX: 1.05,
				scaleY: 1.05
			}, {
				duration: 100,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(self, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 100,
						easing: tween.easeIn
					});
				}
			});
		}
	};
	sellButton.down = function (x, y, obj) {
		var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
		var sellValue = getTowerSellValue(totalInvestment);
		setCrystals(crystals + sellValue);
		var notification = game.addChild(new Notification("Tower sold for " + sellValue + " crystal!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		var gridX = self.tower.gridX;
		var gridY = self.tower.gridY;
		for (var i = 0; i < 2; i++) {
			for (var j = 0; j < 2; j++) {
				var cell = grid.getCell(gridX + i, gridY + j);
				if (cell) {
					cell.type = 0;
					var towerIndex = cell.towersInRange.indexOf(self.tower);
					if (towerIndex !== -1) {
						cell.towersInRange.splice(towerIndex, 1);
					}
				}
			}
		}
		if (selectedTower === self.tower) {
			selectedTower = null;
		}
		var towerIndex = towers.indexOf(self.tower);
		if (towerIndex !== -1) {
			towers.splice(towerIndex, 1);
		}
		towerLayer.removeChild(self.tower);
		grid.pathFind();
		grid.renderDebug();
		self.destroy();
		for (var i = 0; i < game.children.length; i++) {
			if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
				game.removeChild(game.children[i]);
				break;
			}
		}
	};
	closeButton.down = function (x, y, obj) {
		LK.getSound('Closebuttonsound1').play();
		hideUpgradeMenu(self);
		selectedTower = null;
		grid.renderDebug();
	};
	self.update = function () {
		// Text animation
		if (animationPhase === 'name') {
			nameAnimation.timer++;
			if (nameAnimation.timer % animationDelay === 0 && nameAnimation.index < nameAnimation.text.length) {
				currentNameText += nameAnimation.text[nameAnimation.index];
				towerTypeText.setText(currentNameText);
				nameAnimation.index++;
			}
			if (nameAnimation.index >= nameAnimation.text.length) {
				animationPhase = 'stats';
			}
		} else if (animationPhase === 'stats') {
			statsAnimation.timer++;
			if (statsAnimation.timer % animationDelay === 0 && statsAnimation.index < statsAnimation.text.length) {
				currentStatsText += statsAnimation.text[statsAnimation.index];
				statsText.setText(currentStatsText);
				statsAnimation.index++;
			}
			if (statsAnimation.index >= statsAnimation.text.length) {
				animationPhase = 'hold';
				holdTimer = 0;
			}
		} else if (animationPhase === 'hold') {
			holdTimer++;
			if (holdTimer >= holdDuration) {
				animationPhase = 'name';
				nameAnimation.index = 0;
				nameAnimation.timer = 0;
				towerTypeText.setText('');
				currentNameText = '';
				statsAnimation.index = 0;
				statsAnimation.timer = 0;
				statsText.setText('');
				currentStatsText = '';
			}
		}
		if (self.tower.level >= self.tower.maxLevel) {
			if (buttonText.text !== 'Max Level') {
				buttonText.setText('Max Level');
				buttonBackground.tint = 0xffffff;
			}
			return;
		}
		// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
		var baseUpgradeCost = getTowerCost(self.tower.id);
		var currentUpgradeCost;
		if (self.tower.level >= self.tower.maxLevel) {
			currentUpgradeCost = 0;
		} else if (self.tower.level === self.tower.maxLevel - 1) {
			currentUpgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
		} else {
			currentUpgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1));
		}
		var canAfford = crystals >= currentUpgradeCost;
		buttonBackground.tint = canAfford ? 0x00ff00 : 0xff0000;
		var newText = 'Upgrade: ' + currentUpgradeCost + ' crystal';
		if (buttonText.text !== newText) {
			buttonText.setText(newText);
		}
	};
	return self;
});
var WaveIndicator = Container.expand(function () {
	var self = Container.call(this);
	self.gameStarted = false;
	self.waveMarkers = [];
	self.waveTypes = [];
	self.enemyCounts = [];
	self.indicatorWidth = 0;
	self.lastBossType = null; // Track the last boss type to avoid repeating
	var blockWidth = 400;
	var totalBlocksWidth = blockWidth * totalWaves;
	var startMarker = new Container();
	var startBlock = startMarker.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	startBlock.width = blockWidth - 10;
	startBlock.height = 70 * 2;
	startBlock.tint = 0xffffff;
	// Add shadow for start text
	var startTextShadow = new Text2("Start Game", {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	startTextShadow.anchor.set(0.5, 0.5);
	startTextShadow.x = 4;
	startTextShadow.y = 4;
	startMarker.addChild(startTextShadow);
	var startText = new Text2("Start Game", {
		size: 50,
		fill: 0xff0080,
		weight: 800
	});
	startText.anchor.set(0.5, 0.5);
	startMarker.addChild(startText);
	startMarker.x = -self.indicatorWidth;
	self.addChild(startMarker);
	self.waveMarkers.push(startMarker);
	startMarker.down = function () {
		if (!self.gameStarted && canStartWaves) {
			self.gameStarted = true;
			currentWave = 0;
			waveTimer = nextWaveTime;
			startBlock.tint = 0x00FF00;
			startText.setText("Started!");
			startTextShadow.setText("Started!");
			// Make sure shadow position remains correct after text change
			startTextShadow.x = 4;
			startTextShadow.y = 4;
			var notification = game.addChild(new Notification("Game started!\nWave 1 incoming!"));
			notification.x = 2048 / 2;
			notification.y = 2732 / 2;
		}
	};
	for (var i = 0; i < totalWaves; i++) {
		var marker = new Container();
		var block = marker.attachAsset('Notification1', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		block.width = blockWidth - 10;
		block.height = 70 * 2;
		// --- Begin new unified wave logic ---
		var waveType = "normal";
		var enemyType = "normal";
		var enemyCount = 10;
		var isBossWave = (i + 1) % 10 === 0;
		// Ensure all types appear in early waves
		if (i === 0) {
			block.tint = 0xffffff;
			waveType = "Easy";
			enemyType = "normal";
			enemyCount = 10;
		} else if (i === 1) {
			block.tint = 0xffffff;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if (i === 2) {
			block.tint = 0xffffff;
			waveType = "Unstoppable";
			enemyType = "immune";
			enemyCount = 10;
		} else if (i === 3) {
			block.tint = 0xffffff;
			waveType = "Air";
			enemyType = "flying";
			enemyCount = 10;
		} else if (i === 4) {
			block.tint = 0xffffff;
			waveType = "Group";
			enemyType = "swarm";
			enemyCount = 30;
		} else if (isBossWave) {
			// Boss waves: cycle through all boss types, last boss is always flying
			var bossTypes = ['normal', 'fast', 'immune', 'flying'];
			var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
			if (i === totalWaves - 1) {
				// Last boss is always flying
				enemyType = 'flying';
				waveType = "Boss Air";
				block.tint = 0xffffff;
			} else {
				enemyType = bossTypes[bossTypeIndex % bossTypes.length];
				switch (enemyType) {
					case 'normal':
						block.tint = 0xffffff;
						waveType = "Boss Easy";
						break;
					case 'fast':
						block.tint = 0xffffff;
						waveType = "Boss Fast";
						break;
					case 'immune':
						block.tint = 0xffffff;
						waveType = "Boss Unstoppable";
						break;
					case 'flying':
						block.tint = 0xffffff;
						waveType = "Boss Air";
						break;
				}
			}
			enemyCount = 1;
			// Make the wave indicator for boss waves stand out
			// Set boss wave color to the color of the wave type
			switch (enemyType) {
				case 'normal':
					block.tint = 0xffffff;
					break;
				case 'fast':
					block.tint = 0xffffff;
					break;
				case 'immune':
					block.tint = 0xffffff;
					break;
				case 'flying':
					block.tint = 0xffffff;
					break;
				default:
					block.tint = 0xffffff;
					break;
			}
		} else if ((i + 1) % 5 === 0) {
			// Every 5th non-boss wave is fast
			block.tint = 0xffffff;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if ((i + 1) % 4 === 0) {
			// Every 4th non-boss wave is immune
			block.tint = 0xffffff;
			waveType = "Unstoppable";
			enemyType = "immune";
			enemyCount = 10;
		} else if ((i + 1) % 7 === 0) {
			// Every 7th non-boss wave is flying
			block.tint = 0xffffff;
			waveType = "Air";
			enemyType = "flying";
			enemyCount = 10;
		} else if ((i + 1) % 3 === 0) {
			// Every 3rd non-boss wave is swarm
			block.tint = 0xffffff;
			waveType = "Group";
			enemyType = "swarm";
			enemyCount = 30;
		} else {
			block.tint = 0xffffff;
			waveType = "Easy";
			enemyType = "normal";
			enemyCount = 10;
		}
		// --- End new unified wave logic ---
		// Add tween animation to transition block color from red to white
		tween(block, {
			tint: 0xFFFFFF
		}, {
			duration: 2000,
			easing: tween.easeInOut
		});
		// Mark boss waves with a special visual indicator
		if (isBossWave && enemyType !== 'swarm') {
			// Add a crown or some indicator to the wave marker for boss waves
			var bossIndicator = marker.attachAsset('towerLevelIndicator', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			bossIndicator.width = 30;
			bossIndicator.height = 30;
			bossIndicator.tint = 0xFFD700; // Gold color
			bossIndicator.y = -block.height / 2 - 15;
			// Change the wave type text to indicate boss
			waveType = "BOSS";
		}
		// Store the wave type and enemy count
		self.waveTypes[i] = enemyType;
		self.enemyCounts[i] = enemyCount;
		self.waveDisplayNames = self.waveDisplayNames || [];
		self.waveDisplayNames[i] = waveType;
		// Add shadow for wave type - 30% smaller than before
		var waveTypeShadow = new Text2("Wave " + (i + 1), {
			size: 56,
			fill: 0x000000,
			weight: 800
		});
		waveTypeShadow.anchor.set(0.5, 0.5);
		waveTypeShadow.x = 0 + 2;
		waveTypeShadow.y = -20 + 2;
		marker.addChild(waveTypeShadow);
		// Add wave type text - 30% smaller than before
		var waveTypeText = new Text2("Wave " + (i + 1), {
			size: 56,
			fill: 0xff0080,
			weight: 800
		});
		waveTypeText.anchor.set(0.5, 0.5);
		waveTypeText.x = 0;
		waveTypeText.y = -20;
		marker.addChild(waveTypeText);
		// Add shadow for wave number - 20% larger than before
		var waveNumShadow = new Text2(waveType, {
			size: 48,
			fill: 0x000000,
			weight: 800
		});
		waveNumShadow.anchor.set(0.5, 0.5);
		waveNumShadow.x = 0 + 2;
		waveNumShadow.y = 20 + 2;
		marker.addChild(waveNumShadow);
		// Main wave number text - 20% larger than before
		var waveNum = new Text2(waveType, {
			size: 48,
			fill: 0xff0080,
			weight: 800
		});
		waveNum.anchor.set(0.5, 0.5);
		waveNum.x = 0;
		waveNum.y = 20;
		marker.addChild(waveNum);
		marker.x = -self.indicatorWidth + (i + 1) * blockWidth;
		self.addChild(marker);
		self.waveMarkers.push(marker);
	}
	// Get wave type for a specific wave number
	self.getWaveType = function (waveNumber) {
		if (waveNumber < 1 || waveNumber > totalWaves) {
			return "normal";
		}
		// If this is a boss wave (waveNumber % 10 === 0), and the type is the same as lastBossType
		// then we should return a different boss type
		var waveType = self.waveTypes[waveNumber - 1];
		return waveType;
	};
	// Get enemy count for a specific wave number
	self.getEnemyCount = function (waveNumber) {
		if (waveNumber < 1 || waveNumber > totalWaves) {
			return 10;
		}
		return self.enemyCounts[waveNumber - 1];
	};
	// Get display name for a wave type
	self.getWaveTypeName = function (waveNumber) {
		if (waveNumber < 1 || waveNumber > totalWaves) {
			return "Normal";
		}
		// Return the stored display name
		return self.waveDisplayNames[waveNumber - 1] || "Normal";
	};
	self.positionIndicator = new Container();
	var indicator = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	indicator.width = blockWidth - 10;
	indicator.height = 16;
	indicator.tint = 0x00ffb3;
	indicator.y = -65;
	var indicator2 = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	indicator2.width = blockWidth - 10;
	indicator2.height = 16;
	indicator2.tint = 0x00ffb3;
	indicator2.y = 65;
	var leftWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	leftWall.width = 16;
	leftWall.height = 146;
	leftWall.tint = 0x00ffb3;
	leftWall.x = -(blockWidth - 16) / 2;
	var rightWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	rightWall.width = 16;
	rightWall.height = 146;
	rightWall.tint = 0x00ffb3;
	rightWall.x = (blockWidth - 16) / 2;
	self.addChild(self.positionIndicator);
	self.update = function () {
		var progress = waveTimer / nextWaveTime;
		var moveAmount = (progress + currentWave) * blockWidth;
		for (var i = 0; i < self.waveMarkers.length; i++) {
			var marker = self.waveMarkers[i];
			marker.x = -moveAmount + i * blockWidth;
		}
		self.positionIndicator.x = 0;
		for (var i = 0; i < totalWaves + 1; i++) {
			var marker = self.waveMarkers[i];
			if (i === 0) {
				continue;
			}
			var block = marker.children[0];
			if (i - 1 < currentWave) {
				block.alpha = .5;
			}
		}
		self.handleWaveProgression = function () {
			if (!self.gameStarted) {
				return;
			}
			if (currentWave < totalWaves) {
				waveTimer++;
				if (waveTimer >= nextWaveTime) {
					waveTimer = 0;
					currentWave++;
					waveInProgress = true;
					waveSpawned = false;
					if (currentWave != 1) {
						var waveType = self.getWaveTypeName(currentWave);
						var enemyCount = self.getEnemyCount(currentWave);
						var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) incoming!"));
						notification.x = 2048 / 2;
						notification.y = 2732 / 2;
					}
				}
			}
		};
		self.handleWaveProgression();
	};
	return self;
});
var WeatherSystem = Container.expand(function () {
	var self = Container.call(this);
	self.currentWeather = null;
	self.weatherParticles = [];
	self.weatherOverlay = null;
	self.lastWeatherType = null;
	// Weather types: sunny, rainy, snowy, foggy, stormy
	self.getWeatherType = function (waveNumber) {
		if (waveNumber < 1) {
			return 'sunny';
		}
		var weatherCycle = Math.floor((waveNumber - 1) / 10) % 5;
		var weatherTypes = ['sunny', 'rainy', 'snowy', 'foggy', 'stormy'];
		return weatherTypes[weatherCycle];
	};
	self.update = function () {
		var weatherType = self.getWeatherType(currentWave);
		// Change weather if needed
		if (weatherType !== self.currentWeather) {
			self.clearWeather();
			self.currentWeather = weatherType;
			self.applyWeather(weatherType);
		}
		// Update particles
		for (var i = self.weatherParticles.length - 1; i >= 0; i--) {
			var particle = self.weatherParticles[i];
			if (particle && particle.update) {
				particle.update();
			}
			if (!particle || !particle.parent || particle.shouldRemove) {
				if (particle && particle.parent) {
					particle.destroy();
				}
				self.weatherParticles.splice(i, 1);
			}
		}
		// Spawn new particles based on weather
		if (self.currentWeather === 'rainy') {
			if (Math.random() < 0.3) {
				// 30% chance per frame
				self.spawnRainDrop();
			}
		} else if (self.currentWeather === 'snowy') {
			if (Math.random() < 0.2) {
				// 20% chance per frame
				self.spawnSnowflake();
			}
		} else if (self.currentWeather === 'stormy') {
			if (Math.random() < 0.35) {
				// 35% chance per frame
				self.spawnStormParticle();
			}
			if (Math.random() < 0.01) {
				// 1% chance for lightning
				self.createLightning();
			}
		}
	};
	self.clearWeather = function () {
		// Clear all particles
		for (var i = 0; i < self.weatherParticles.length; i++) {
			if (self.weatherParticles[i] && self.weatherParticles[i].parent) {
				self.weatherParticles[i].destroy();
			}
		}
		self.weatherParticles = [];
		// Remove overlay
		if (self.weatherOverlay) {
			tween(self.weatherOverlay, {
				alpha: 0
			}, {
				duration: 1000,
				onFinish: function onFinish() {
					if (self.weatherOverlay && self.weatherOverlay.parent) {
						self.weatherOverlay.destroy();
					}
					self.weatherOverlay = null;
				}
			});
		}
	};
	self.applyWeather = function (weatherType) {
		switch (weatherType) {
			case 'sunny':
				self.applySunnyWeather();
				break;
			case 'rainy':
				self.applyRainyWeather();
				break;
			case 'snowy':
				self.applySnowyWeather();
				break;
			case 'foggy':
				self.applyFoggyWeather();
				break;
			case 'stormy':
				self.applyStormyWeather();
				break;
		}
	};
	self.applySunnyWeather = function () {
		// Create sun rays effect
		for (var i = 0; i < 8; i++) {
			(function () {
				var sunRay = self.attachAsset('cell', {
					anchorX: 0.5,
					anchorY: 0,
					width: 150,
					height: 2048,
					tint: 0xFFFF88,
					alpha: 0
				});
				sunRay.x = 300 + i * 200;
				sunRay.y = -500;
				sunRay.rotation = 0.3 + i * 0.1;
				sunRay.blendMode = 1;
				tween(sunRay, {
					alpha: 0.15
				}, {
					duration: 2000,
					easing: tween.easeOut
				});
				// Gentle animation
				var _animateSunRay = function animateSunRay() {
					tween(sunRay, {
						alpha: 0.1 + Math.random() * 0.1,
						rotation: sunRay.rotation + (Math.random() - 0.5) * 0.1
					}, {
						duration: 3000 + Math.random() * 2000,
						easing: tween.easeInOut,
						onFinish: _animateSunRay
					});
				};
				_animateSunRay();
				self.weatherParticles.push(sunRay);
			})();
		}
		// Add warm overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0xFFFF00,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.05
		}, {
			duration: 2000
		});
	};
	self.applyRainyWeather = function () {
		// Add dark overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0x4444AA,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.2
		}, {
			duration: 2000
		});
	};
	self.spawnRainDrop = function () {
		var rainDrop = self.attachAsset('cell', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 3,
			height: 20,
			tint: 0x6699FF,
			alpha: 0.6,
			x: Math.random() * 2048,
			y: -50
		});
		rainDrop.velocity = 15 + Math.random() * 10;
		rainDrop.update = function () {
			rainDrop.y += rainDrop.velocity;
			if (rainDrop.y > 2782) {
				rainDrop.shouldRemove = true;
				// Create splash effect
				var splash = self.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 20,
					height: 10,
					tint: 0x6699FF,
					alpha: 0.5,
					x: rainDrop.x,
					y: 2732
				});
				tween(splash, {
					width: 40,
					height: 20,
					alpha: 0
				}, {
					duration: 300,
					onFinish: function onFinish() {
						if (splash.parent) {
							splash.destroy();
						}
					}
				});
			}
		};
		self.weatherParticles.push(rainDrop);
	};
	self.applySnowyWeather = function () {
		// Add light blue overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0xCCDDFF,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.15
		}, {
			duration: 2000
		});
	};
	self.spawnSnowflake = function () {
		var snowflake = self.attachAsset('rangeCircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 8 + Math.random() * 8,
			height: 8 + Math.random() * 8,
			tint: 0xFFFFFF,
			alpha: 0.8,
			x: Math.random() * 2048,
			y: -50
		});
		snowflake.velocity = 2 + Math.random() * 2;
		snowflake.swaySpeed = 0.02 + Math.random() * 0.02;
		snowflake.swayAmount = 30 + Math.random() * 20;
		snowflake.baseX = snowflake.x;
		snowflake.time = Math.random() * Math.PI * 2;
		snowflake.update = function () {
			snowflake.y += snowflake.velocity;
			snowflake.time += snowflake.swaySpeed;
			snowflake.x = snowflake.baseX + Math.sin(snowflake.time) * snowflake.swayAmount;
			snowflake.rotation += 0.02;
			if (snowflake.y > 2782) {
				snowflake.shouldRemove = true;
			}
		};
		self.weatherParticles.push(snowflake);
	};
	self.applyFoggyWeather = function () {
		// Create multiple fog layers
		for (var i = 0; i < 5; i++) {
			(function (index) {
				var fog = self.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 800,
					height: 600,
					tint: 0xCCCCCC,
					alpha: 0,
					x: Math.random() * 2048,
					y: Math.random() * 2732
				});
				fog.blendMode = 1;
				tween(fog, {
					alpha: 0.3
				}, {
					duration: 3000,
					easing: tween.easeOut
				});
				// Animate fog movement
				var _animateFog = function animateFog() {
					var targetX = Math.random() * 2048;
					var targetY = Math.random() * 2732;
					tween(fog, {
						x: targetX,
						y: targetY,
						scaleX: 0.8 + Math.random() * 0.4,
						scaleY: 0.8 + Math.random() * 0.4
					}, {
						duration: 20000 + Math.random() * 10000,
						easing: tween.easeInOut,
						onFinish: _animateFog
					});
				};
				_animateFog();
				self.weatherParticles.push(fog);
			})();
		}
	};
	self.applyStormyWeather = function () {
		// Add dark storm overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0x333366,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.3
		}, {
			duration: 2000
		});
	};
	self.spawnStormParticle = function () {
		// Mix of heavy rain and wind particles
		var particle = self.attachAsset('cell', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 4,
			height: 25,
			tint: 0x8899CC,
			alpha: 0.7,
			x: Math.random() * 2248 - 100,
			// Can start off-screen
			y: -50,
			rotation: -0.3 // Angled rain
		});
		particle.velocityX = 5 + Math.random() * 3;
		particle.velocityY = 20 + Math.random() * 10;
		particle.update = function () {
			particle.x += particle.velocityX;
			particle.y += particle.velocityY;
			if (particle.y > 2782 || particle.x > 2148) {
				particle.shouldRemove = true;
			}
		};
		self.weatherParticles.push(particle);
	};
	self.createLightning = function () {
		// Flash effect
		var flash = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0xFFFFFF,
			alpha: 0
		});
		tween(flash, {
			alpha: 0.6
		}, {
			duration: 50,
			onFinish: function onFinish() {
				tween(flash, {
					alpha: 0
				}, {
					duration: 100,
					onFinish: function onFinish() {
						if (flash.parent) {
							flash.destroy();
						}
					}
				});
			}
		});
		// Lightning bolt
		var bolt = self.attachAsset('cell', {
			anchorX: 0.5,
			anchorY: 0,
			width: 10,
			height: 2732,
			tint: 0xCCCCFF,
			alpha: 0,
			x: 200 + Math.random() * 1648,
			y: 0
		});
		bolt.blendMode = 1;
		// Create jagged lightning effect
		var segments = 8;
		for (var i = 0; i < segments; i++) {
			(function (index) {
				var segment = self.attachAsset('cell', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 5 + Math.random() * 15,
					height: 2732 / segments,
					tint: 0xFFFFFF,
					alpha: 0,
					x: bolt.x + (Math.random() - 0.5) * 100,
					y: index * (2732 / segments)
				});
				segment.blendMode = 1;
				tween(segment, {
					alpha: 0.9
				}, {
					duration: 50,
					delay: index * 10,
					onFinish: function onFinish() {
						tween(segment, {
							alpha: 0
						}, {
							duration: 200,
							onFinish: function onFinish() {
								if (segment.parent) {
									segment.destroy();
								}
							}
						});
					}
				});
			})();
		}
		tween(bolt, {
			alpha: 0.8
		}, {
			duration: 50,
			onFinish: function onFinish() {
				tween(bolt, {
					alpha: 0
				}, {
					duration: 300,
					onFinish: function onFinish() {
						if (bolt.parent) {
							bolt.destroy();
						}
					}
				});
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x00ffdd
});
/**** 
* Game Code
****/ 
// Initialize sound system FIRST before any other game code
game.soundVolume = storage.soundVolume !== undefined ? storage.soundVolume : 1.0; // Load from storage or default to full volume
// Create the sound playing helper function
game.playSoundWithVolume = function (soundName) {
	var sound = LK.getSound(soundName);
	if (sound) {
		// Get the original volume from the asset definition
		var originalVolume = 1.0; // Default volume
		switch (soundName) {
			case 'Bulletsound':
				originalVolume = 0.3;
				break;
			case 'Flamesound':
				originalVolume = 0.5;
				break;
			case 'Gumbombsound':
				originalVolume = 0.4;
				break;
			case 'Riflebulletsound':
				originalVolume = 0.3;
				break;
			case 'Rocketsound':
				originalVolume = 0.3;
				break;
			case 'Ship1sound':
				originalVolume = 1.0;
				break;
			case 'Ship2sound':
				originalVolume = 1.0;
				break;
			case 'Ship3sound':
				originalVolume = 0.2;
				break;
			case 'Toxinbombsound':
				originalVolume = 1.0;
				break;
			case 'placmentsound1':
			case 'placmentsound2':
			case 'placmentsound3':
			case 'placmentsound4':
			case 'placmentsound5':
			case 'placmentsound6':
				originalVolume = 1.0;
				break;
		}
		// Apply both the original volume and the user's sound volume setting
		var finalVolume = originalVolume * game.soundVolume;
		// Play the sound with the calculated volume
		sound.play({
			volume: finalVolume
		});
	}
};
// Game state variables
// Define all available abilities with their effects
var abilityDefinitions = {
	'ability_0': {
		name: 'Healing Wave',
		description: 'Heal 25% of max health',
		icon: 'Ability1',
		color: 0x00FF00,
		effect: function effect() {
			lives = Math.min(100, lives + 25);
			updateUI();
			var notification = game.addChild(new Notification("Healing Wave activated! +25 health"));
			// Add a green screen flash for healing
			var flash = LK.getAsset('cell', {
				width: 2048,
				height: 2732,
				x: 0,
				y: 0,
				alpha: 0,
				tint: 0x00FF00
			});
			game.addChild(flash);
			tween(flash, {
				alpha: 0.5
			}, {
				duration: 200,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(flash, {
						alpha: 0
					}, {
						duration: 300,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							if (flash.parent) {
								flash.destroy();
							}
						}
					});
				}
			});
			// Add rising green healing particles across the screen
			for (var i = 0; i < 30; i++) {
				(function () {
					var particle = game.attachAsset('rangeCircle', {
						anchorX: 0.5,
						anchorY: 0.5,
						tint: 0x32CD32,
						// LimeGreen
						width: 15 + Math.random() * 20,
						height: 15 + Math.random() * 20,
						alpha: 0.8,
						blendMode: 1,
						x: Math.random() * 2048,
						y: 2732 + Math.random() * 200
					});
					tween(particle, {
						y: particle.y - 800 - Math.random() * 500,
						alpha: 0
					}, {
						duration: 1500 + Math.random() * 1000,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							if (particle.parent) {
								particle.destroy();
							}
						}
					});
				})();
			}
		}
	},
	'ability_1': {
		name: 'Weakness Curse',
		description: 'Enemies take 50% more damage for 10 seconds',
		icon: 'Ability2',
		color: 0xFF4500,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].weakened) {
					enemies[i].weakened = true;
					enemies[i].weakenDuration = 600; // 10 seconds at 60 FPS
					enemies[i].originalDamageResistance = enemies[i].damageResistance || 1;
					enemies[i].damageResistance = enemies[i].originalDamageResistance * 1.5; // Take 50% more damage
					// Add weakness animation on each enemy
					(function (currentEnemy) {
						var originalScaleX = currentEnemy.scaleX || 1;
						var originalScaleY = currentEnemy.scaleY || 1;
						tween(currentEnemy, {
							tint: 0xFF0000,
							scaleX: originalScaleX * 1.3,
							scaleY: originalScaleY * 1.3
						}, {
							duration: 200,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (currentEnemy && currentEnemy.parent) {
									tween(currentEnemy, {
										tint: 0xFF4500,
										scaleX: originalScaleX,
										scaleY: originalScaleY
									}, {
										duration: 500,
										easing: tween.easeOut
									});
								}
							}
						});
						// Add dripping curse particles
						var curseParticles = new Container();
						currentEnemy.addChild(curseParticles);
						for (var p = 0; p < 10; p++) {
							(function () {
								var particle = curseParticles.attachAsset('rangeCircle', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: 0x8A2BE2,
									// BlueViolet for curse
									width: 8 + Math.random() * 8,
									height: 8 + Math.random() * 8,
									alpha: 0.9,
									x: (Math.random() - 0.5) * currentEnemy.children[0].width,
									y: -currentEnemy.children[0].height / 2 + (Math.random() - 0.5) * 20
								});
								var duration = 800 + Math.random() * 500;
								var delay = Math.random() * 9500; // Drip throughout the 10s duration
								tween(particle, {
									y: particle.y + 60,
									alpha: 0
								}, {
									duration: duration,
									delay: delay,
									onFinish: function onFinish() {
										if (particle.parent) {
											particle.destroy();
										}
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (curseParticles.parent) {
								curseParticles.destroy();
							}
						}, 10000);
					})(enemies[i]);
				}
			}
			var notification = game.addChild(new Notification("Weakness Curse activated! Enemies weakened!"));
		}
	},
	'ability_2': {
		name: 'Lightning Storm',
		description: 'Deals 15% damage to all enemies based on their difficulty',
		icon: 'Ability3',
		color: 0xFFFF00,
		effect: function effect() {
			for (var i = enemies.length - 1; i >= 0; i--) {
				if (!enemies[i]) {
					continue;
				} // Safety check
				var damage = enemies[i].maxHealth * 0.15;
				if (enemies[i].type === 'easy') {
					damage *= 1.5;
				} else if (enemies[i].type === 'medium') {
					damage *= 1.0;
				} else if (enemies[i].type === 'hard') {
					damage *= 0.7;
				}
				enemies[i].health -= damage;
				if (enemies[i].health <= 0) {
					enemies[i].health = 0;
				} else {
					var healthPercentage = enemies[i].health / enemies[i].maxHealth;
					enemies[i].healthBar.width = enemies[i].healthBarOriginalWidth * healthPercentage;
				}
				// Use an IIFE to create a new scope for each enemy, fixing closure bugs
				(function (currentEnemy) {
					if (currentEnemy && currentEnemy.parent && currentEnemy.children[0]) {
						// Add electricity particle effects
						var lightningEffectContainer = new Container();
						currentEnemy.addChild(lightningEffectContainer);
						for (var k = 0; k < 7; k++) {
							// Create 7 lightning bolts
							(function () {
								// IIFE for each bolt's closure
								var bolt = lightningEffectContainer.attachAsset('cell', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: Math.random() < 0.5 ? 0xADD8E6 : 0xFFFFFF,
									// Light Blue or White
									width: 2 + Math.random() * 4,
									height: 30 + Math.random() * 50,
									alpha: 0
								});
								bolt.x = (Math.random() - 0.5) * 70;
								bolt.y = (Math.random() - 0.5) * 70;
								bolt.rotation = (Math.random() - 0.5) * Math.PI;
								tween(bolt, {
									alpha: 0.9
								}, {
									duration: 100,
									delay: Math.random() * 100,
									onFinish: function onFinish() {
										tween(bolt, {
											alpha: 0
										}, {
											duration: 150,
											onFinish: function onFinish() {
												if (bolt.parent) {
													bolt.destroy();
												}
											}
										});
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (lightningEffectContainer.parent) {
								lightningEffectContainer.destroy();
							}
						}, 600);
						// Add lightning strike tint animation on each enemy
						var enemyGraphics = currentEnemy.children[0];
						var originalTint = enemyGraphics.tint;
						tween(enemyGraphics, {
							tint: 0x87CEEB // Sky Blue for lightning strike
						}, {
							duration: 100,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (enemyGraphics && enemyGraphics.parent) {
									tween(enemyGraphics, {
										tint: 0xFFFFFF // White flash
									}, {
										duration: 50,
										easing: tween.easeIn,
										onFinish: function onFinish() {
											if (enemyGraphics && enemyGraphics.parent) {
												tween(enemyGraphics, {
													tint: 0x87CEEB // Sky Blue for lightning strike
												}, {
													duration: 50,
													easing: tween.easeOut,
													onFinish: function onFinish() {
														if (enemyGraphics && enemyGraphics.parent) {
															tween(enemyGraphics, {
																tint: originalTint
															}, {
																duration: 100,
																easing: tween.easeIn
															});
														}
													}
												});
											}
										}
									});
								}
							}
						});
					}
				})(enemies[i]);
			}
			var notification = game.addChild(new Notification("Lightning Storm! All enemies shocked!"));
		}
	},
	'ability_3': {
		name: 'Dust Storm',
		description: 'Slows all enemies by 70% for 3 seconds',
		icon: 'Ability4',
		color: 0x8B4513,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].dustSlowed) {
					enemies[i].dustSlowed = true;
					enemies[i].dustSlowDuration = 180; // 3 seconds at 60 FPS
					if (!enemies[i].originalSpeed) {
						enemies[i].originalSpeed = enemies[i].speed;
					}
					enemies[i].speed = enemies[i].originalSpeed * 0.3; // 70% slower
					// Add dust swirl animation on each enemy
					var currentEnemy = enemies[i]; // Store reference to avoid closure issues
					tween(currentEnemy, {
						tint: 0x8B4513
					}, {
						duration: 300
					});
					// Add dust particles swirling around the enemy
					var dustContainer = new Container();
					currentEnemy.addChild(dustContainer);
					for (var p = 0; p < 8; p++) {
						(function () {
							var particle = dustContainer.attachAsset('rangeCircle', {
								anchorX: 0.5,
								anchorY: 0.5,
								tint: 0xCD853F,
								// Peru color for dust
								width: 10 + Math.random() * 15,
								height: 10 + Math.random() * 15,
								alpha: 0.8
							});
							var angle = Math.random() * Math.PI * 2;
							var startRadius = 20;
							particle.x = Math.cos(angle) * startRadius;
							particle.y = Math.sin(angle) * startRadius;
							var endRadius = 40 + Math.random() * 20;
							var duration = 1500 + Math.random() * 1000;
							tween(particle, {
								x: Math.cos(angle) * endRadius,
								y: Math.sin(angle) * endRadius,
								alpha: 0,
								rotation: particle.rotation + Math.PI
							}, {
								duration: duration,
								onFinish: function onFinish() {
									if (particle.parent) {
										particle.destroy();
									}
								}
							});
						})();
					}
					LK.setTimeout(function () {
						if (dustContainer.parent) {
							dustContainer.destroy();
						}
					}, 3000); // Effect duration is 3 seconds
				}
			}
			var notification = game.addChild(new Notification("Dust Storm! Enemies slowed by dust!"));
		}
	},
	'ability_4': {
		name: 'Water Flood',
		description: 'Enemies drown slowly, losing 8% health per second for 5 seconds',
		icon: 'Ability5',
		color: 0x0080FF,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].drowning) {
					enemies[i].drowning = true;
					enemies[i].drownDuration = 300; // 5 seconds at 60 FPS
					enemies[i].drownDamage = enemies[i].maxHealth * 0.08 / 60; // 8% per second
					// Add water splash and drowning animation
					var currentEnemy = enemies[i]; // Store reference to avoid closure issues
					tween(currentEnemy, {
						tint: 0x0080FF
					}, {
						duration: 300
					});
					// Add bubbles rising from the enemy
					var bubbleContainer = new Container();
					currentEnemy.addChild(bubbleContainer);
					for (var b = 0; b < 5; b++) {
						(function () {
							var bubble = bubbleContainer.attachAsset('rangeCircle', {
								anchorX: 0.5,
								anchorY: 0.5,
								tint: 0xADD8E6,
								// Light blue for bubbles
								width: 5 + Math.random() * 10,
								height: 5 + Math.random() * 10,
								y: 0,
								x: (Math.random() - 0.5) * 20,
								alpha: 0.7
							});
							var duration = 1000 + Math.random() * 1000;
							var delay = Math.random() * 4000; // Bubbles appear throughout the 5s duration
							tween(bubble, {
								y: -40,
								alpha: 0
							}, {
								duration: duration,
								delay: delay,
								onFinish: function onFinish() {
									if (bubble.parent) {
										bubble.destroy();
									}
								}
							});
						})();
					}
					LK.setTimeout(function () {
						if (bubbleContainer.parent) {
							bubbleContainer.destroy();
						}
					}, 5000); // Effect duration is 5 seconds
				}
			}
			var notification = game.addChild(new Notification("Water Flood! Enemies are drowning!"));
		}
	},
	'ability_5': {
		name: 'Fire Ring',
		description: 'Creates fire around enemies, dealing 10% damage for 4 seconds',
		icon: 'Ability6',
		color: 0xFF0000,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].burning) {
					enemies[i].burning = true;
					enemies[i].burnDuration = 240; // 4 seconds at 60 FPS
					enemies[i].burnDamage = enemies[i].maxHealth * 0.10 / 60; // 10% per second
					// Add fire ring animation around each enemy
					(function (currentEnemy) {
						var fireIntensity = 0;
						var _burnAnimation = function burnAnimation() {
							if (!currentEnemy || !currentEnemy.parent || !currentEnemy.burning) {
								if (currentEnemy && currentEnemy.parent) {
									tween(currentEnemy, {
										tint: 0xFFFFFF,
										scaleX: 1,
										scaleY: 1
									}, {
										duration: 200
									});
								}
								return;
							}
							fireIntensity++;
							var flameColor = fireIntensity % 2 === 0 ? 0xFF0000 : 0xFF4500;
							var scale = 1 + (fireIntensity % 2 === 0 ? 0.1 : 0.05);
							tween(currentEnemy, {
								tint: flameColor,
								scaleX: scale,
								scaleY: scale
							}, {
								duration: 250,
								easing: tween.easeInOut,
								onFinish: _burnAnimation
							});
						};
						_burnAnimation();
						// Add rising embers/sparks
						var fireParticles = new Container();
						currentEnemy.addChild(fireParticles);
						for (var p = 0; p < 8; p++) {
							(function () {
								var particle = fireParticles.attachAsset('rangeCircle', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: Math.random() < 0.5 ? 0xFF4500 : 0xFFD700,
									// Orange-red to gold
									width: 5 + Math.random() * 10,
									height: 5 + Math.random() * 10,
									alpha: 0.9,
									blendMode: 1,
									x: (Math.random() - 0.5) * currentEnemy.children[0].width,
									y: (Math.random() - 0.5) * 20
								});
								var duration = 600 + Math.random() * 400;
								var delay = Math.random() * 3800;
								tween(particle, {
									y: particle.y - 40 - Math.random() * 20,
									alpha: 0
								}, {
									duration: duration,
									delay: delay,
									onFinish: function onFinish() {
										if (particle.parent) {
											particle.destroy();
										}
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (fireParticles.parent) {
								fireParticles.destroy();
							}
						}, 4000);
					})(enemies[i]);
				}
			}
			var notification = game.addChild(new Notification("Fire Ring! Enemies are burning!"));
		}
	},
	'ability_6': {
		name: 'Ice Freeze',
		description: 'Freezes all enemies for 3 seconds',
		icon: 'Ability7',
		color: 0x00FFFF,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].frozen) {
					enemies[i].frozen = true;
					enemies[i].freezeDuration = 180; // 3 seconds at 60 FPS
					if (!enemies[i].originalSpeed) {
						enemies[i].originalSpeed = enemies[i].speed;
					}
					enemies[i].speed = 0; // Completely frozen
					// Add ice freeze animation
					var currentEnemy = enemies[i]; // Store reference to avoid closure issues
					tween(currentEnemy, {
						tint: 0x00FFFF,
						scaleX: 0.9,
						scaleY: 0.9
					}, {
						duration: 400,
						easing: tween.easeOut
					});
					// Add ice shards that form around the enemy
					var iceContainer = new Container();
					currentEnemy.addChild(iceContainer);
					for (var s = 0; s < 8; s++) {
						(function () {
							var shard = iceContainer.attachAsset('cell', {
								anchorX: 0.5,
								anchorY: 0.5
							});
							shard.tint = 0xB0E0E6; // Powder blue
							shard.width = 15;
							shard.height = 5;
							shard.rotation = Math.random() * Math.PI * 2;
							var angle = Math.random() * Math.PI * 2;
							var radius = 20 + Math.random() * 10;
							shard.x = Math.cos(angle) * radius;
							shard.y = Math.sin(angle) * radius;
							shard.alpha = 0;
							tween(shard, {
								alpha: 1.0
							}, {
								duration: 400
							});
						})();
					}
					LK.setTimeout(function () {
						if (iceContainer.parent) {
							tween(iceContainer, {
								alpha: 0
							}, {
								duration: 300,
								onFinish: function onFinish() {
									if (iceContainer.parent) {
										iceContainer.destroy();
									}
								}
							});
						}
					}, 2700); // Start fading out before freeze ends
				}
			}
			var notification = game.addChild(new Notification("Ice Freeze! All enemies frozen!"));
		}
	},
	'ability_7': {
		name: 'Shield Boost',
		description: 'Gain 15 health and towers deal 25% more damage for 8 seconds',
		icon: 'Ability8',
		color: 0xFFD700,
		effect: function effect() {
			lives = Math.min(100, lives + 15);
			updateUI();
			// Boost all towers
			for (var i = 0; i < towers.length; i++) {
				if (towers[i] && !towers[i].boosted) {
					towers[i].boosted = true;
					towers[i].boostDuration = 480; // 8 seconds at 60 FPS
					towers[i].originalDamage = towers[i].damage;
					towers[i].damage = Math.floor(towers[i].damage * 1.25);
					// Add golden glow animation to boosted towers
					(function (currentTower) {
						tween(currentTower, {
							tint: 0xFFD700,
							scaleX: 1.15,
							scaleY: 1.15
						}, {
							duration: 300,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (currentTower && currentTower.parent) {
									tween(currentTower, {
										scaleX: 1,
										scaleY: 1
									}, {
										duration: 200,
										easing: tween.easeIn
									});
								}
							}
						});
						// Add shimmering shield particles
						var shieldParticles = new Container();
						currentTower.addChild(shieldParticles);
						for (var p = 0; p < 12; p++) {
							(function () {
								var particle = shieldParticles.attachAsset('rangeCircle', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: 0xFFD700,
									// Gold
									width: 8 + Math.random() * 12,
									height: 8 + Math.random() * 12,
									alpha: 0,
									blendMode: 1
								});
								var angle = Math.random() * Math.PI * 2;
								var startRadius = 30 + Math.random() * 20;
								var endRadius = 60 + Math.random() * 30;
								particle.x = Math.cos(angle) * startRadius;
								particle.y = Math.sin(angle) * startRadius;
								tween(particle, {
									alpha: 0.8
								}, {
									duration: 400,
									delay: Math.random() * 1000,
									onFinish: function onFinish() {
										tween(particle, {
											x: Math.cos(angle) * endRadius,
											y: Math.sin(angle) * endRadius,
											alpha: 0
										}, {
											duration: 800 + Math.random() * 500,
											delay: Math.random() * 6000,
											onFinish: function onFinish() {
												if (particle.parent) {
													particle.destroy();
												}
											}
										});
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (shieldParticles.parent) {
								shieldParticles.destroy();
							}
						}, 8000); // 8 seconds
					})(towers[i]);
				}
			}
			var notification = game.addChild(new Notification("Shield Boost! Health gained and towers boosted!"));
		}
	},
	'ability_8': {
		name: 'Ultimate Storm',
		description: 'Combines multiple effects: heal, damage enemies, slow them',
		icon: 'Ability9',
		color: 0xFF00FF,
		effect: function effect() {
			// Heal player
			lives = Math.min(100, lives + 20);
			updateUI();
			// Damage and slow all enemies
			for (var i = 0; i < enemies.length; i++) {
				if (!enemies[i]) {
					continue;
				} // Safety check
				// Deal damage
				var damage = enemies[i].maxHealth * 0.20;
				enemies[i].health -= damage;
				if (enemies[i].health <= 0) {
					enemies[i].health = 0;
				} else {
					var healthPercentage = enemies[i].health / enemies[i].maxHealth;
					enemies[i].healthBar.width = enemies[i].healthBarOriginalWidth * healthPercentage;
				}
				// Apply slow
				if (!enemies[i].ultimateSlowed) {
					enemies[i].ultimateSlowed = true;
					enemies[i].ultimateSlowDuration = 300; // 5 seconds
					if (!enemies[i].originalSpeed) {
						enemies[i].originalSpeed = enemies[i].speed;
					}
					enemies[i].speed = enemies[i].originalSpeed * 0.4; // 60% slower
				}
				// Add ultimate storm animation - combination of all effects
				(function (currentEnemy) {
					var stormPhase = 0;
					var _ultimateStormAnimation = function ultimateStormAnimation() {
						stormPhase++;
						if (!currentEnemy || !currentEnemy.parent) {
							return;
						}
						if (stormPhase === 1) {
							// Lightning phase (Blue/White)
							tween(currentEnemy, {
								tint: 0x87CEEB,
								scaleX: 1.2,
								scaleY: 1.2
							}, {
								duration: 150,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (currentEnemy && currentEnemy.parent) {
										tween(currentEnemy, {
											tint: 0xFFFFFF
										}, {
											duration: 150,
											easing: tween.easeIn,
											onFinish: _ultimateStormAnimation
										});
									} else {
										_ultimateStormAnimation();
									}
								}
							});
						} else if (stormPhase === 2) {
							// Fire phase (Red/Orange)
							tween(currentEnemy, {
								tint: 0xFF0000,
								scaleX: 1.1,
								scaleY: 1.1
							}, {
								duration: 150,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (currentEnemy && currentEnemy.parent) {
										tween(currentEnemy, {
											tint: 0xFF4500
										}, {
											duration: 150,
											easing: tween.easeIn,
											onFinish: _ultimateStormAnimation
										});
									} else {
										_ultimateStormAnimation();
									}
								}
							});
						} else if (stormPhase === 3) {
							// Ice phase (Cyan)
							tween(currentEnemy, {
								tint: 0x00FFFF,
								scaleX: 0.9,
								scaleY: 0.9
							}, {
								duration: 200,
								easing: tween.easeOut,
								onFinish: _ultimateStormAnimation
							});
						} else {
							// Final phase - return to normal with magical glow
							tween(currentEnemy, {
								tint: 0xFF00FF,
								scaleX: 1,
								scaleY: 1
							}, {
								duration: 300,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (currentEnemy && currentEnemy.parent) {
										tween(currentEnemy, {
											tint: 0xFFFFFF
										}, {
											duration: 500,
											easing: tween.easeIn
										});
									}
								}
							});
						}
					};
					// Start ultimate storm animation
					_ultimateStormAnimation();
					// Add multi-colored particle explosion
					var stormParticles = new Container();
					currentEnemy.addChild(stormParticles);
					var colors = [0x87CEEB, 0xFFFFFF, 0xFF0000, 0xFF4500, 0x00FFFF, 0xFF00FF];
					for (var p = 0; p < 25; p++) {
						(function () {
							var particle = stormParticles.attachAsset('rangeCircle', {
								anchorX: 0.5,
								anchorY: 0.5,
								tint: colors[Math.floor(Math.random() * colors.length)],
								width: 10 + Math.random() * 15,
								height: 10 + Math.random() * 15,
								alpha: 1.0,
								blendMode: 1
							});
							var angle = Math.random() * Math.PI * 2;
							var startRadius = 10;
							var endRadius = 60 + Math.random() * 40;
							particle.x = Math.cos(angle) * startRadius;
							particle.y = Math.sin(angle) * startRadius;
							var duration = 500 + Math.random() * 400;
							tween(particle, {
								x: Math.cos(angle) * endRadius,
								y: Math.sin(angle) * endRadius,
								alpha: 0,
								rotation: particle.rotation + Math.PI * 2
							}, {
								duration: duration,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (particle.parent) {
										particle.destroy();
									}
								}
							});
						})();
					}
					LK.setTimeout(function () {
						if (stormParticles.parent) {
							stormParticles.destroy();
						}
					}, 1200);
				})(enemies[i]);
			}
			var notification = game.addChild(new Notification("ULTIMATE STORM! All effects activated!"));
		}
	}
};
var canStartWaves = false;
var canPlaceTowers = false;
var gameStarted = false;
var showingIntro = true;
var showingScores = false;
var scoreBackground = null;
var scoreMenu = null;
var showingAbilities = false;
var abilitiesMenu = null;
var showingSettings = false;
var settingBackground = null;
var settingMenu = null;
var brightnessOverlay = null;
var isDraggingLightButton = false;
var isDraggingMusicButton = false;
var isDraggingSoundButton = false;
var girlCharacter = null;
var showingTutorial = false;
var tutorialScreen = null;
// High scores management
function getHighScores() {
	return storage.highScores || [];
}
function addHighScore(score) {
	var highScores = getHighScores();
	highScores.push(score);
	// Sort in descending order
	highScores.sort(function (a, b) {
		return b - a;
	});
	// Keep only top 10
	if (highScores.length > 10) {
		highScores = highScores.slice(0, 10);
	}
	storage.highScores = highScores;
	return highScores;
}
function showAbilities() {
	if (showingAbilities) {
		return;
	}
	showingAbilities = true;
	abilitiesMenu = new AbilitiesMenu();
	abilitiesMenu.x = 2048 / 2 - 60;
	abilitiesMenu.y = 2732 / 2;
	game.addChild(abilitiesMenu);
	abilitiesMenu.scale.set(0.5);
	abilitiesMenu.alpha = 0;
	tween(abilitiesMenu, {
		scaleX: 1,
		scaleY: 1,
		alpha: 1
	}, {
		duration: 300,
		easing: tween.easeOut
	});
}
function hideAbilities() {
	if (!showingAbilities || !abilitiesMenu) {
		return;
	}
	showingAbilities = false;
	tween(abilitiesMenu, {
		scaleX: 0.5,
		scaleY: 0.5,
		alpha: 0
	}, {
		duration: 300,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			if (abilitiesMenu) {
				abilitiesMenu.destroy();
				abilitiesMenu = null;
			}
		}
	});
}
function showSettings() {
	if (showingSettings) {
		return;
	}
	showingSettings = true;
	settingBackground = game.attachAsset('SettingBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var startX = 2048 + settingBackground.width / 2;
	var targetX = 2048 / 2;
	settingBackground.x = startX;
	settingBackground.y = 2732 / 2;
	game.addChild(settingBackground);
	settingMenu = new Container();
	settingMenu.x = startX;
	settingMenu.y = 2732 / 2;
	game.addChild(settingMenu);
	var closeButton = new Container();
	closeButton.attachAsset('CloseButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.y = settingBackground.height / 2 - 150;
	settingMenu.addChild(closeButton);
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideSettings();
	};
	// Calculate vertical positions to center all three volume settings in the settingBackground
	var totalHeight = 400; // Total height span for all three settings (200px spacing between each)
	var musicY = -totalHeight / 2; // -200
	var soundY = 0; // Center
	var lightY = totalHeight / 2; // 200
	// Calculate horizontal positions to center all elements in the settingBackground
	var totalWidth = 700; // Approximate total width of icon + bar + percentage text
	var iconX = -totalWidth / 2 - 200; // Center the icons horizontally, moved 200px left
	var barX = iconX + 150;
	// Music Setting
	var musicIcon = settingMenu.attachAsset('MusicIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	musicIcon.x = iconX;
	musicIcon.y = musicY;
	var musicBar = settingMenu.attachAsset('MusicBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	musicBar.name = "musicBar";
	musicBar.x = barX;
	musicBar.y = musicY;
	var musicButton = settingMenu.attachAsset('MusicButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	musicButton.name = "musicButton";
	musicButton.y = musicY;
	// Position music button based on current music volume
	var currentMusicVolume = game.musicVolume || 1.0;
	var musicTrackWidth = musicBar.width - musicButton.width;
	musicButton.x = musicBar.x + musicButton.width / 2 + musicTrackWidth * currentMusicVolume;
	// Add music volume percentage text
	var musicPercentage = new Text2(Math.round((game.musicVolume || 1.0) * 100) + "%", {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	musicPercentage.anchor.set(0.5, 0.5);
	musicPercentage.x = musicBar.x + musicBar.width + 80;
	musicPercentage.y = musicY;
	musicPercentage.name = "musicPercentage";
	settingMenu.addChild(musicPercentage);
	musicButton.down = function () {
		isDraggingMusicButton = true;
	};
	// Sound Setting
	var soundIcon = settingMenu.attachAsset('SoundIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	soundIcon.x = iconX;
	soundIcon.y = soundY;
	var soundBar = settingMenu.attachAsset('SoundBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	soundBar.name = "soundBar";
	soundBar.x = barX;
	soundBar.y = soundY;
	var soundButton = settingMenu.attachAsset('SoundButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	soundButton.name = "soundButton";
	soundButton.y = soundY;
	// Add sound volume percentage text
	var soundPercentage = new Text2(Math.round(game.soundVolume * 100) + "%", {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	soundPercentage.anchor.set(0.5, 0.5);
	soundPercentage.x = soundBar.x + soundBar.width + 80;
	soundPercentage.y = soundY;
	soundPercentage.name = "soundPercentage";
	settingMenu.addChild(soundPercentage);
	// Position sound button based on current sound volume
	var currentSoundVolume = game.soundVolume || 1.0;
	var soundTrackWidth = soundBar.width - soundButton.width;
	soundButton.x = soundBar.x + soundButton.width / 2 + soundTrackWidth * currentSoundVolume;
	soundButton.down = function () {
		isDraggingSoundButton = true;
	};
	// Light Setting
	var lightIcon = settingMenu.attachAsset('LightIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	lightIcon.x = iconX;
	lightIcon.y = lightY;
	var lightBar = settingMenu.attachAsset('LightBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	lightBar.name = "lightBar";
	lightBar.x = barX;
	lightBar.y = lightY;
	var lightButton = settingMenu.attachAsset('LightButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	lightButton.name = "lightButton";
	lightButton.y = lightY;
	lightButton.x = lightBar.x + lightButton.width / 2;
	// Add light percentage text
	var lightPercentage = new Text2("0%", {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	lightPercentage.anchor.set(0.5, 0.5);
	lightPercentage.x = lightBar.x + lightBar.width + 80;
	lightPercentage.y = lightY;
	lightPercentage.name = "lightPercentage";
	settingMenu.addChild(lightPercentage);
	lightButton.down = function () {
		isDraggingLightButton = true;
	};
	tween(settingBackground, {
		x: targetX
	}, {
		duration: 500,
		easing: tween.easeOut
	});
	tween(settingMenu, {
		x: targetX
	}, {
		duration: 500,
		easing: tween.easeOut
	});
}
function hideSettings() {
	if (!showingSettings) {
		return;
	}
	showingSettings = false;
	var targetX = 2048 + 1600 / 2;
	if (settingBackground) {
		tween(settingBackground, {
			x: targetX
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				if (settingBackground) {
					game.removeChild(settingBackground);
					settingBackground = null;
				}
			}
		});
	}
	if (settingMenu) {
		tween(settingMenu, {
			x: targetX
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				if (settingMenu) {
					game.removeChild(settingMenu);
					settingMenu = null;
				}
			}
		});
	}
}
function showHighScores() {
	if (showingScores) {
		return;
	}
	showingScores = true;
	// Create score background
	scoreBackground = game.attachAsset('Scorebackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	scoreBackground.x = 2048 / 2;
	scoreBackground.y = 2732 / 2;
	game.addChild(scoreBackground);
	// Create score menu container
	scoreMenu = new Container();
	scoreMenu.x = 2048 / 2;
	scoreMenu.y = 2732 / 2;
	game.addChild(scoreMenu);
	// Add title
	var titleShadow = new Text2("HIGH SCORES", {
		size: 80,
		fill: 0x000000,
		weight: 800
	});
	titleShadow.anchor.set(0.5, 0.5);
	titleShadow.x = 4;
	titleShadow.y = -400 + 4;
	scoreMenu.addChild(titleShadow);
	var title = new Text2("HIGH SCORES", {
		size: 80,
		fill: 0x00ffb3,
		weight: 800
	});
	title.anchor.set(0.5, 0.5);
	title.y = -400;
	scoreMenu.addChild(title);
	// Get and display high scores
	var highScores = getHighScores();
	for (var i = 0; i < 10; i++) {
		var rank = i + 1;
		var scoreValue = i < highScores.length ? highScores[i] : 0;
		var yPos = -280 + i * 60;
		// Score rank and value shadow
		var scoreShadow = new Text2(rank + ". " + scoreValue, {
			size: 60,
			fill: 0x000000,
			weight: 800
		});
		scoreShadow.anchor.set(0.5, 0.5);
		scoreShadow.x = 4;
		scoreShadow.y = yPos + 4;
		scoreMenu.addChild(scoreShadow);
		// Score rank and value
		var scoreColor = i < 3 ? 0xFFD700 : 0x00ffb3; // Gold for top 3
		var scoreText = new Text2(rank + ". " + scoreValue, {
			size: 60,
			fill: scoreColor,
			weight: 800
		});
		scoreText.anchor.set(0.5, 0.5);
		scoreText.y = yPos;
		scoreMenu.addChild(scoreText);
	}
	// Add close button
	var closeButton = new Container();
	var closeButtonBg = closeButton.attachAsset('ScoreCloseButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.y = 450;
	scoreMenu.addChild(closeButton);
	// Close button handler
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideHighScores();
	};
}
function hideHighScores() {
	if (!showingScores) {
		return;
	}
	showingScores = false;
	if (scoreBackground) {
		game.removeChild(scoreBackground);
		scoreBackground = null;
	}
	if (scoreMenu) {
		game.removeChild(scoreMenu);
		scoreMenu = null;
	}
}
function showTutorial() {
	if (showingTutorial) {
		return;
	}
	showingTutorial = true;
	// Create tutorial screen container
	tutorialScreen = new Container();
	tutorialScreen.x = 2048 / 2;
	tutorialScreen.y = 2732 / 2;
	game.addChild(tutorialScreen);
	// Add background using proper Tutorialbackground asset
	var tutorialBg = tutorialScreen.attachAsset('Tutorialbackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	tutorialBg.width = 2048;
	tutorialBg.height = 2732;
	// Add title
	var title = new Text2("HOW TO PLAY", {
		size: 80,
		fill: 0xff0080,
		weight: 800
	});
	title.anchor.set(0.5, 0.5);
	title.y = -tutorialBg.height / 2 + 100;
	tutorialScreen.addChild(title);
	// Tutorial content
	var tutorialContent = [{
		title: "1. PLACING TOWERS",
		desc: "Drag towers from bottom bar\nto the grid. Each tower costs\ncrystals shown below it."
	}, {
		title: "2. UPGRADE & SELL",
		desc: "Tap on a placed tower to\nupgrade (costs more crystals)\nor sell (get 80% back)."
	}, {
		title: "3. TOWER TYPES",
		desc: "Cannon: Basic damage\nRifle: Fast shooting\nFlame: Continuous damage\nRocket: Splash damage\nGumbomb: Slows enemies\nToxinbomb: Poison damage"
	}, {
		title: "4. START WAVES",
		desc: "Click 'Start Game' to begin.\nEnemies spawn from top and\nmove to bottom. Stop them!"
	}, {
		title: "5. ABILITIES",
		desc: "Click ability button (bottom left)\nto use special powers. Each\ncosts crystals but helps a lot!"
	}, {
		title: "6. ENEMY TYPES",
		desc: "Normal: Standard enemies\nFast: Move quickly\nImmune: Can't be slowed\nFlying: Go over towers\nSwarm: Many weak enemies\nBoss: Strong, every 10 waves"
	}, {
		title: "7. WIN CONDITION",
		desc: "Survive all 100 waves to win!\nLose all health and game over.\nEarn crystals by defeating enemies."
	}];
	// Per-section manual positions for title and description
	var tutorialSectionPositions = [
	// 1. PLACING TOWERS
	{
		titleX: 0,
		titleY: -1200,
		descX: 0,
		descY: -1120
	},
	// 2. UPGRADE & SELL
	{
		titleX: 0,
		titleY: -910,
		descX: 0,
		descY: -830
	},
	// 3. TOWER TYPES
	{
		titleX: 0,
		titleY: -590,
		descX: 0,
		descY: -510
	},
	// 4. START WAVES (moved down 50px from type 3)
	{
		titleX: 0,
		titleY: -120,
		descX: 0,
		descY: -40
	},
	// 5. ABILITIES
	{
		titleX: 0,
		titleY: 150,
		descX: 0,
		descY: 230
	},
	// 6. ENEMY TYPES
	{
		titleX: 0,
		titleY: 440,
		descX: 0,
		descY: 520
	},
	// 7. WIN CONDITION (moved down 50px from type 6)
	{
		titleX: 0,
		titleY: 910,
		descX: 0,
		descY: 990
	}];
	// Display tutorial content with manual positions
	for (var i = 0; i < tutorialContent.length; i++) {
		var section = tutorialContent[i];
		var pos = tutorialSectionPositions[i] || {
			titleX: 0,
			titleY: 0,
			descX: 0,
			descY: 60
		};
		// Create a container for each section to ensure proper layering
		var sectionContainer = new Container();
		tutorialScreen.addChild(sectionContainer);
		// Section title - ensure it's added first and positioned correctly
		var sectionTitle = new Text2(section.title, {
			size: 60,
			fill: 0x00ffb3,
			weight: 800
		});
		sectionTitle.anchor.set(0.5, 0); // Anchor at top center
		sectionTitle.x = pos.titleX;
		sectionTitle.y = pos.titleY;
		sectionContainer.addChild(sectionTitle);
		// Section description - add after title to ensure proper layering
		var sectionDesc = new Text2(section.desc, {
			size: 55,
			fill: 0xFFD700,
			weight: 600,
			align: 'center'
		});
		sectionDesc.anchor.set(0.5, 0); // Anchor at top center
		sectionDesc.x = pos.descX;
		sectionDesc.y = pos.descY;
		sectionContainer.addChild(sectionDesc);
	}
	// Add close button using proper Tutorialclosebutton asset
	var closeButton = tutorialScreen.attachAsset('Tutorialclosebutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.x = 0;
	closeButton.y = tutorialBg.height / 2 - 100;
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideTutorial();
	};
	// Entrance animation
	tutorialScreen.scaleX = 0.5;
	tutorialScreen.scaleY = 0.5;
	tutorialScreen.alpha = 0;
	tween(tutorialScreen, {
		scaleX: 1,
		scaleY: 1,
		alpha: 1
	}, {
		duration: 300,
		easing: tween.easeOut
	});
}
function hideTutorial() {
	if (!showingTutorial) {
		return;
	}
	showingTutorial = false;
	tween(tutorialScreen, {
		scaleX: 0.5,
		scaleY: 0.5,
		alpha: 0
	}, {
		duration: 300,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			if (tutorialScreen) {
				tutorialScreen.destroy();
				tutorialScreen = null;
			}
		}
	});
}
// Add intro background image to cover the entire game area
var introBackground = game.attachAsset('Introbackground', {
	anchorX: 0,
	anchorY: 0,
	width: 2048,
	height: 2732
});
// Position background at top-left corner
introBackground.x = 0;
introBackground.y = 0;
// Send background to the back
game.addChildAt(introBackground, 0);
// Play intro music immediately when intro starts
LK.playMusic('Intromusic');
// Position buttons vertically below the center of the screen
var buttonCenterX = 2048 / 2;
var buttonSpacing = 280; // Increased vertical spacing between buttons
var startY = 2732 / 2 + 400; // Start position for the first button, to place the group below center
// Add StartButton at the top
var startButton = game.attachAsset('StartButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
startButton.x = buttonCenterX;
startButton.y = startY;
game.addChild(startButton);
// Add Tutorial Button below start button
var tutorialButton = game.attachAsset('Tutorialbutton', {
	anchorX: 0.5,
	anchorY: 0.5
});
tutorialButton.x = buttonCenterX;
tutorialButton.y = startY + buttonSpacing;
game.addChild(tutorialButton);
// Add ScoreButton below tutorial button
var scoreButton = game.attachAsset('ScoreButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
scoreButton.x = buttonCenterX;
scoreButton.y = startY + buttonSpacing * 2;
game.addChild(scoreButton);
// Add SettingButton at the bottom
var settingButton = game.attachAsset('SettingButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
settingButton.x = buttonCenterX;
settingButton.y = startY + buttonSpacing * 3;
game.addChild(settingButton);
// Add game background image (initially hidden)
var gameBackground = game.attachAsset('gamebackground', {
	anchorX: 0,
	anchorY: 0,
	width: 2048,
	height: 2732
});
gameBackground.x = 0;
gameBackground.y = 0;
gameBackground.visible = false;
game.addChildAt(gameBackground, 0);
// Function to start the game
function startGame() {
	showingIntro = false;
	gameStarted = true;
	// Hide intro elements
	introBackground.visible = false;
	startButton.visible = false;
	scoreButton.visible = false;
	settingButton.visible = false;
	tutorialButton.visible = false;
	// Show game elements
	gameBackground.visible = true;
	debugLayer.visible = true;
	towerLayer.visible = true;
	enemyLayer.visible = true;
	crystalIcon.visible = true;
	crystalLabelText.visible = true;
	crystalNumberText.visible = true;
	healthBarContainer.visible = true;
	scoreLabelText.visible = true;
	scoreNumberText.visible = true;
	waveIndicator.visible = true;
	nextWaveButtonContainer.visible = true;
	towerPreview.visible = false;
	// Stop intro music and play game music only if music is on
	LK.stopMusic();
	// Add a small delay to ensure intro music is fully stopped before starting new music
	LK.setTimeout(function () {
		if (musicOn) {
			LK.playMusic('Gamemusic1');
		}
	}, 100);
}
// Add click handlers for buttons
startButton.down = function () {
	if (showingTutorial) {
		return;
	}
	LK.getSound('Startbuttonsound1').play();
	startGame();
};
scoreButton.down = function () {
	if (showingTutorial) {
		return;
	}
	showHighScores();
};
settingButton.down = function () {
	if (showingIntro && !showingScores && !showingTutorial) {
		showSettings();
	}
};
tutorialButton.down = function () {
	if (showingIntro && !showingScores && !showingSettings && !showingTutorial) {
		showTutorial();
	}
};
var isHidingUpgradeMenu = false;
function hideUpgradeMenu(menu) {
	if (isHidingUpgradeMenu) {
		return;
	}
	isHidingUpgradeMenu = true;
	// Get menu background height from the asset
	var menuHeight = 500; // Default fallback
	if (menu.children[0]) {
		menuHeight = menu.children[0].height;
	}
	tween(menu, {
		y: 2732 + menuHeight / 2
	}, {
		duration: 150,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			menu.destroy();
			isHidingUpgradeMenu = false;
		}
	});
}
var CELL_SIZE = 76;
var pathId = 1;
var maxScore = 0;
var enemies = [];
var towers = [];
var bullets = [];
var defenses = [];
var selectedTower = null;
var crystals = 500;
var lives = 100;
var score = 0;
var currentWave = 0;
var lastWave = 0;
var totalWaves = 100;
var waveTimer = 0;
var waveInProgress = false;
var waveSpawned = false;
var nextWaveTime = 12000 / 2;
var sourceTower = null;
var enemiesToSpawn = 10; // Default number of enemies per wave
var ships = [];
var lastShip3Spawn = 0;
var ship3SpawnInterval = 2400; // 40 seconds at 60 FPS
var crystalLabelText = new Text2('Crystal: ', {
	size: 60,
	fill: 0xff0080,
	weight: 800
});
crystalLabelText.anchor.set(1, 0.9);
var crystalNumberText = new Text2(crystals.toString(), {
	size: 60,
	fill: 0x00ffb3,
	weight: 800
});
crystalNumberText.anchor.set(0, 0.9);
var healthBarBG = LK.getAsset('healthBarOutline', {
	anchorX: 0.5,
	anchorY: 1
});
var healthBarFill = LK.getAsset('gameHealthBar', {
	anchorX: 0,
	anchorY: 1.1
});
healthBarFill.x = -healthBarBG.width / 2 + (healthBarBG.width - healthBarFill.width) / 2;
healthBarFill.originalWidth = healthBarFill.width;
var healthText = new Text2('100/100', {
	size: 50,
	fill: 0x00ffb3,
	weight: 800
});
healthText.anchor.set(0.5, 0.9);
var healthBarContainer = new Container();
healthBarContainer.addChild(healthBarBG);
healthBarContainer.addChild(healthBarFill);
healthBarContainer.addChild(healthText);
var scoreLabelText = new Text2('Score: ', {
	size: 60,
	fill: 0xff0080,
	weight: 800
});
scoreLabelText.anchor.set(1, 0.9);
var scoreNumberText = new Text2(score.toString(), {
	size: 60,
	fill: 0x00ffb3,
	weight: 800
});
scoreNumberText.anchor.set(0, 0.9);
var topMargin = 50;
var centerX = 2048 / 2;
var spacing = 350;
var crystalIcon = LK.getAsset('Crystal', {
	anchorX: 1.0,
	anchorY: 0.9,
	scaleX: 0.4,
	scaleY: 0.6
});
LK.gui.top.addChild(crystalIcon);
LK.gui.top.addChild(crystalLabelText);
LK.gui.top.addChild(crystalNumberText);
LK.gui.top.addChild(healthBarContainer);
LK.gui.top.addChild(scoreLabelText);
LK.gui.top.addChild(scoreNumberText);
// Hide UI elements during intro
crystalIcon.visible = false;
crystalLabelText.visible = false;
crystalNumberText.visible = false;
healthBarContainer.visible = false;
scoreLabelText.visible = false;
scoreNumberText.visible = false;
healthBarContainer.x = 0;
healthBarContainer.y = topMargin;
// Position Crystal UI elements
var crystalTextX = -380;
crystalLabelText.x = crystalTextX;
crystalLabelText.y = topMargin;
crystalNumberText.x = crystalTextX;
crystalNumberText.y = topMargin;
crystalIcon.x = crystalTextX - 250;
crystalIcon.y = topMargin;
// Position Score UI elements
var scoreTextX = 450;
scoreLabelText.x = scoreTextX;
scoreLabelText.y = topMargin;
scoreNumberText.x = scoreTextX;
scoreNumberText.y = topMargin;
// Add mute button to top right corner with music state tracking
var musicOn = true; // Track current music state
var muteButton = LK.getAsset('Mutebutton1', {
	anchorX: 1.0,
	anchorY: -0.1,
	width: 100,
	height: 100
});
muteButton.x = 2048 - 50; // 50px from right edge
muteButton.y = 0; // 0px from top edge
game.addChild(muteButton);
// Add mute button click handler
muteButton.down = function () {
	musicOn = !musicOn; // Toggle music state
	if (musicOn) {
		// Music is now on - show Mutebutton1 and resume music
		game.removeChild(muteButton);
		muteButton = LK.getAsset('Mutebutton1', {
			anchorX: 1.0,
			anchorY: -0.1,
			width: 100,
			height: 100
		});
		muteButton.x = 2048 - 50;
		muteButton.y = 0;
		game.addChild(muteButton);
		// Animate button appearance
		muteButton.alpha = 0;
		tween(muteButton, {
			alpha: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		// Resume appropriate music based on game state
		if (showingIntro) {
			LK.playMusic('Intromusic');
		} else if (gameStarted) {
			// Resume game music based on current wave
			var musicToPlay;
			if (currentWave > 0 && currentWave % 10 === 0) {
				// isBossWave
				var bossMusics = ['Bossmusic1', 'Bossmusic2', 'Bossmusic3', 'Bossmusic4', 'Bossmusic5'];
				var musicIndex = (currentWave / 10 - 1) % bossMusics.length;
				musicToPlay = bossMusics[musicIndex];
			} else {
				// is normal wave, or wave 0
				var gameMusics = ['Gamemusic1', 'Gamemusic2', 'gamemusic3', 'Gamemusic4', 'Gamemusic5'];
				var musicIndex = Math.floor(currentWave / 10) % gameMusics.length;
				musicToPlay = gameMusics[musicIndex];
			}
			LK.playMusic(musicToPlay);
		}
	} else {
		// Music is now off - show Mutebutton2 and stop music
		game.removeChild(muteButton);
		muteButton = LK.getAsset('Mutebutton2', {
			anchorX: 1.0,
			anchorY: -0.1,
			width: 100,
			height: 100
		});
		muteButton.x = 2048 - 50;
		muteButton.y = 0;
		game.addChild(muteButton);
		// Animate button appearance
		muteButton.alpha = 0;
		tween(muteButton, {
			alpha: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		// Stop all music
		LK.stopMusic();
	}
	// Re-assign the click handler to the new button
	muteButton.down = arguments.callee;
};
function updateUI() {
	crystalNumberText.setText(crystals.toString());
	healthText.setText(lives + '/100');
	// Update health bar fill width based on current lives (assuming max 100 lives)
	var healthPercentage = lives / 100;
	healthBarFill.width = healthBarFill.originalWidth * healthPercentage;
	scoreNumberText.setText(score.toString());
}
function setCrystals(value) {
	crystals = value;
	updateUI();
}
var debugLayer = new Container();
var towerLayer = new Container();
// Create three separate layers for enemy hierarchy
var enemyLayerBottom = new Container(); // For normal enemies
var enemyLayerMiddle = new Container(); // For shadows
var enemyLayerTop = new Container(); // For flying enemies
var enemyLayer = new Container(); // Main container to hold all enemy layers
// Add layers in correct order (bottom first, then middle for shadows, then top)
enemyLayer.addChild(enemyLayerBottom);
enemyLayer.addChild(enemyLayerMiddle);
enemyLayer.addChild(enemyLayerTop);
var grid = new Grid(24, 29 + 6);
grid.x = 150;
grid.y = 200 - CELL_SIZE * 4;
grid.pathFind();
grid.renderDebug();
debugLayer.addChild(grid);
game.addChild(debugLayer);
game.addChild(towerLayer);
game.addChild(enemyLayer);
// Initialize weather system
var weatherSystem = new WeatherSystem();
game.addChild(weatherSystem);
brightnessOverlay = LK.getAsset('cell', {
	width: 2048,
	height: 2732
});
brightnessOverlay.tint = 0x000000;
brightnessOverlay.alpha = 0;
brightnessOverlay.x = 0;
brightnessOverlay.y = 0;
game.addChild(brightnessOverlay);
// Hide game elements during intro
debugLayer.visible = false;
towerLayer.visible = false;
enemyLayer.visible = false;
var offset = 0;
var towerPreview = new TowerPreview();
game.addChild(towerPreview);
towerPreview.visible = false;
var isDragging = false;
function wouldBlockPath(gridX, gridY) {
	var cells = [];
	for (var i = 0; i < 2; i++) {
		for (var j = 0; j < 2; j++) {
			var cell = grid.getCell(gridX + i, gridY + j);
			if (cell) {
				cells.push({
					cell: cell,
					originalType: cell.type
				});
				cell.type = 1;
			}
		}
	}
	var blocked = grid.pathFind();
	for (var i = 0; i < cells.length; i++) {
		cells[i].cell.type = cells[i].originalType;
	}
	grid.pathFind();
	grid.renderDebug();
	return blocked;
}
function getTowerCost(towerType) {
	var cost = 10;
	switch (towerType) {
		case 'rifle':
			cost = 20;
			break;
		case 'flame':
			cost = 60;
			break;
		case 'Rocket':
			cost = 80;
			break;
		case 'gumbomb':
			cost = 30;
			break;
		case 'ToxinBomb':
			cost = 100;
			break;
	}
	return cost;
}
function getTowerSellValue(totalValue) {
	return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.8) : totalValue;
}
function placeTower(gridX, gridY, towerType) {
	var towerCost = getTowerCost(towerType);
	if (crystals >= towerCost) {
		var tower = new Tower(towerType || 'cannon');
		tower.placeOnGrid(gridX, gridY);
		towerLayer.addChild(tower);
		towers.push(tower);
		setCrystals(crystals - towerCost);
		grid.pathFind();
		grid.renderDebug();
		return true;
	} else {
		var notification = game.addChild(new Notification("Not enough crystals!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		return false;
	}
}
game.down = function (x, y, obj) {
	// Handle tutorial menu during intro
	if (showingIntro && showingTutorial) {
		// Check if click is outside tutorial area
		var menuLeft = 2048 / 2 - 900;
		var menuRight = 2048 / 2 + 900;
		var menuTop = 2732 / 2 - 1200;
		var menuBottom = 2732 / 2 + 1200;
		if (x < menuLeft || x > menuRight || y < menuTop || y > menuBottom) {
			hideTutorial();
		}
		return;
	}
	// Handle high scores menu during intro
	if (showingIntro && showingScores) {
		// Check if click is outside score menu area
		var menuLeft = 2048 / 2 - 800;
		var menuRight = 2048 / 2 + 800;
		var menuTop = 2732 / 2 - 1100;
		var menuBottom = 2732 / 2 + 1100;
		if (x < menuLeft || x > menuRight || y < menuTop || y > menuBottom) {
			hideHighScores();
		}
		return;
	}
	// Don't process game input during intro
	if (showingIntro || !gameStarted) {
		return;
	}
	var upgradeMenuVisible = game.children.some(function (child) {
		return child instanceof UpgradeMenu;
	});
	if (upgradeMenuVisible) {
		return;
	}
	for (var i = 0; i < sourceTowers.length; i++) {
		var tower = sourceTowers[i];
		if (x >= tower.x - tower.width / 2 && x <= tower.x + tower.width / 2 && y >= tower.y - tower.height / 2 && y <= tower.y + tower.height / 2) {
			if (!canPlaceTowers) {
				return;
			}
			towerPreview.visible = true;
			isDragging = true;
			towerPreview.towerType = tower.towerType;
			towerPreview.updateAppearance();
			// Apply the same offset as in move handler to ensure consistency when starting drag
			towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
			break;
		}
	}
};
game.move = function (x, y, obj) {
	if (isDraggingMusicButton) {
		if (settingMenu) {
			var musicBar = null;
			var musicButton = null;
			var musicPercentage = null;
			for (var i = 0; i < settingMenu.children.length; i++) {
				if (settingMenu.children[i].name === "musicBar") {
					musicBar = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "musicButton") {
					musicButton = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "musicPercentage") {
					musicPercentage = settingMenu.children[i];
				}
			}
			if (musicBar && musicButton) {
				var localPos = settingMenu.toLocal({
					x: x,
					y: y
				});
				var minX = musicBar.x + musicButton.width / 2;
				var maxX = musicBar.x + musicBar.width - musicButton.width / 2;
				var newX = Math.max(minX, Math.min(maxX, localPos.x));
				musicButton.x = newX;
				var trackWidth = maxX - minX;
				var percentage = trackWidth > 0 ? (newX - minX) / trackWidth : 0;
				// Store current music volume and apply to currently playing music
				if (typeof game.musicVolume === 'undefined') {
					game.musicVolume = 1.0;
				}
				game.musicVolume = percentage;
				// Update percentage display
				if (musicPercentage) {
					musicPercentage.setText(Math.round(percentage * 100) + "%");
				}
				// Stop current music and restart with new volume
				LK.stopMusic();
				if (musicOn && percentage > 0) {
					// Determine which music should be playing and restart with new volume
					if (showingIntro) {
						LK.playMusic('Intromusic', {
							fade: {
								start: 0,
								end: percentage,
								duration: 100
							}
						});
					} else if (gameStarted) {
						// Resume game music based on current wave with new volume
						var musicToPlay;
						if (currentWave > 0 && currentWave % 10 === 0) {
							// isBossWave
							var bossMusics = ['Bossmusic1', 'Bossmusic2', 'Bossmusic3', 'Bossmusic4', 'Bossmusic5'];
							var musicIndex = (currentWave / 10 - 1) % bossMusics.length;
							musicToPlay = bossMusics[musicIndex];
						} else {
							// is normal wave, or wave 0
							var gameMusics = ['Gamemusic1', 'Gamemusic2', 'gamemusic3', 'Gamemusic4', 'Gamemusic5'];
							var musicIndex = Math.floor(currentWave / 10) % gameMusics.length;
							musicToPlay = gameMusics[musicIndex];
						}
						LK.playMusic(musicToPlay, {
							fade: {
								start: 0,
								end: percentage,
								duration: 100
							}
						});
					}
				}
			}
		}
		return;
	}
	if (isDraggingSoundButton) {
		if (settingMenu) {
			var soundBar = null;
			var soundButton = null;
			var soundPercentage = null;
			for (var i = 0; i < settingMenu.children.length; i++) {
				if (settingMenu.children[i].name === "soundBar") {
					soundBar = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "soundButton") {
					soundButton = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "soundPercentage") {
					soundPercentage = settingMenu.children[i];
				}
			}
			if (soundBar && soundButton) {
				var localPos = settingMenu.toLocal({
					x: x,
					y: y
				});
				var minX = soundBar.x + soundButton.width / 2;
				var maxX = soundBar.x + soundBar.width - soundButton.width / 2;
				var newX = Math.max(minX, Math.min(maxX, localPos.x));
				soundButton.x = newX;
				var trackWidth = maxX - minX;
				var percentage = trackWidth > 0 ? (newX - minX) / trackWidth : 0;
				// Update the global sound volume
				game.soundVolume = percentage;
				// Save sound volume to storage
				storage.soundVolume = percentage;
				// Update percentage display
				if (soundPercentage) {
					soundPercentage.setText(Math.round(percentage * 100) + "%");
				}
				// Play a test sound when dragging to give immediate feedback
				if (percentage > 0) {
					game.playSoundWithVolume('Bulletsound');
				}
			}
		}
		return;
	}
	if (isDraggingLightButton) {
		if (settingMenu) {
			var lightBar = null;
			var lightButton = null;
			var lightPercentage = null;
			for (var i = 0; i < settingMenu.children.length; i++) {
				if (settingMenu.children[i].name === "lightBar") {
					lightBar = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "lightButton") {
					lightButton = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "lightPercentage") {
					lightPercentage = settingMenu.children[i];
				}
			}
			if (lightBar && lightButton) {
				var localPos = settingMenu.toLocal({
					x: x,
					y: y
				});
				var minX = lightBar.x + lightButton.width / 2;
				var maxX = lightBar.x + lightBar.width - lightButton.width / 2;
				var newX = Math.max(minX, Math.min(maxX, localPos.x));
				lightButton.x = newX;
				var trackWidth = maxX - minX;
				var percentage = trackWidth > 0 ? (newX - minX) / trackWidth : 0;
				if (brightnessOverlay) {
					brightnessOverlay.alpha = percentage * 0.7; // Max dim alpha 0.7
				}
				// Update percentage display
				if (lightPercentage) {
					lightPercentage.setText(Math.round(percentage * 100) + "%");
				}
			}
		}
		return;
	}
	// Don't process game input during intro
	if (showingIntro || !gameStarted) {
		return;
	}
	if (isDragging) {
		// Shift the y position upward by 1.5 tiles to show preview above finger
		towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
	}
};
game.up = function (x, y, obj) {
	if (isDraggingLightButton) {
		isDraggingLightButton = false;
		return;
	}
	if (isDraggingMusicButton) {
		isDraggingMusicButton = false;
		return;
	}
	if (isDraggingSoundButton) {
		isDraggingSoundButton = false;
		return;
	}
	// Don't process game input during intro
	if (showingIntro || !gameStarted) {
		return;
	}
	var clickedOnTower = false;
	for (var i = 0; i < towers.length; i++) {
		var tower = towers[i];
		var towerLeft = tower.x - tower.width / 2;
		var towerRight = tower.x + tower.width / 2;
		var towerTop = tower.y - tower.height / 2;
		var towerBottom = tower.y + tower.height / 2;
		if (x >= towerLeft && x <= towerRight && y >= towerTop && y <= towerBottom) {
			clickedOnTower = true;
			break;
		}
	}
	var upgradeMenus = game.children.filter(function (child) {
		return child instanceof UpgradeMenu;
	});
	if (upgradeMenus.length > 0 && !isDragging && !clickedOnTower) {
		var clickedOnMenu = false;
		for (var i = 0; i < upgradeMenus.length; i++) {
			var menu = upgradeMenus[i];
			var menuWidth = 2048;
			var menuHeight = 450;
			var menuLeft = menu.x - menuWidth / 2;
			var menuRight = menu.x + menuWidth / 2;
			var menuTop = menu.y - menuHeight / 2;
			var menuBottom = menu.y + menuHeight / 2;
			if (x >= menuLeft && x <= menuRight && y >= menuTop && y <= menuBottom) {
				clickedOnMenu = true;
				break;
			}
		}
		if (!clickedOnMenu) {
			for (var i = 0; i < upgradeMenus.length; i++) {
				var menu = upgradeMenus[i];
				hideUpgradeMenu(menu);
			}
			for (var i = game.children.length - 1; i >= 0; i--) {
				if (game.children[i].isTowerRange) {
					game.removeChild(game.children[i]);
				}
			}
			selectedTower = null;
			grid.renderDebug();
		}
	}
	if (isDragging) {
		isDragging = false;
		if (towerPreview.canPlace) {
			if (!wouldBlockPath(towerPreview.gridX, towerPreview.gridY)) {
				placeTower(towerPreview.gridX, towerPreview.gridY, towerPreview.towerType);
			} else {
				var notification = game.addChild(new Notification("Tower would block the path!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
			}
		} else if (towerPreview.blockedByEnemy) {
			var notification = game.addChild(new Notification("Cannot build: Enemy in the way!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
		} else if (towerPreview.visible) {
			var notification = game.addChild(new Notification("Cannot build here!"));
			notification.x = 2048 / 2;
			notification.y = grid.y + grid.cells[0].length * CELL_SIZE - CELL_SIZE * 6;
		}
		towerPreview.visible = false;
		if (isDragging) {
			var upgradeMenus = game.children.filter(function (child) {
				return child instanceof UpgradeMenu;
			});
			for (var i = 0; i < upgradeMenus.length; i++) {
				upgradeMenus[i].destroy();
			}
		}
	}
};
var waveIndicator = new WaveIndicator();
waveIndicator.x = 2048 / 2;
waveIndicator.y = 2732 - 80;
waveIndicator.visible = false;
game.addChild(waveIndicator);
var nextWaveButtonContainer = new Container();
var nextWaveButton = new NextWaveButton();
nextWaveButton.x = 2048 - 200;
nextWaveButton.y = 2732 - 100 + 20;
nextWaveButtonContainer.addChild(nextWaveButton);
var inGameSettingButton = nextWaveButtonContainer.attachAsset('SettingButton', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 0.6,
	scaleY: 0.6
});
var abilityButton = nextWaveButtonContainer.attachAsset('AbilityButton', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 0.6,
	scaleY: 0.6
});
abilityButton.x = 80; // Move 30px to the right
abilityButton.y = 2550 - 150 + 30; // Move 230px down 
abilityButton.down = function () {
	if (!gameStarted || showingIntro || !canStartWaves) {
		var notification = game.addChild(new Notification("Cannot use abilities\nuntil game starts!"));
		return;
	}
	LK.getSound('Abilitybuttonsound1').play();
	showAbilities();
};
inGameSettingButton.x = 2048 - 70; // Move 50px further to the right 
inGameSettingButton.y = 2420;
inGameSettingButton.down = function () {
	showSettings();
};
nextWaveButtonContainer.visible = false;
game.addChild(nextWaveButtonContainer);
var towerTypes = ['cannon', 'rifle', 'flame', 'Rocket', 'gumbomb', 'ToxinBomb'];
var sourceTowers = [];
var towerSpacing = 300; // Increase spacing for larger towers
var startX = 2048 / 2 - towerTypes.length * towerSpacing / 2 + towerSpacing / 2;
var towerY = 2732 - CELL_SIZE * 3 - 90;
for (var i = 0; i < towerTypes.length; i++) {
	var tower = new SourceTower(towerTypes[i]);
	tower.x = startX + i * towerSpacing;
	tower.y = towerY;
	towerLayer.addChild(tower);
	sourceTowers.push(tower);
}
sourceTower = null;
enemiesToSpawn = 10;
game.update = function () {
	// Only run game logic if the game has started
	if (!gameStarted || showingIntro) {
		return;
	}
	// Add static flag to track if intro sequence has been shown
	if (typeof game.introSequenceShown === 'undefined') {
		game.introSequenceShown = false;
	}
	if (!game.introSequenceShown) {
		game.introSequenceShown = true;
		girlCharacter = new SpeakingGirl();
		game.addChild(girlCharacter);
		// Spawn tablet after girl with slight delay
		LK.setTimeout(function () {
			var tablet = new Tablet();
			game.addChild(tablet);
		}, 500); // 500ms delay after girl spawns
	}
	// Weather system update
	if (weatherSystem) {
		weatherSystem.update();
	}
	if (currentWave !== lastWave) {
		if (musicOn && (typeof game.musicVolume === 'undefined' || game.musicVolume > 0)) {
			// Only play music if music is enabled and volume is greater than 0
			var musicVolume = typeof game.musicVolume !== 'undefined' ? game.musicVolume : 1.0;
			var musicToPlay = null;
			if (currentWave > 0 && currentWave % 10 === 0) {
				// isBossWave
				var bossMusics = ['Bossmusic1', 'Bossmusic2', 'Bossmusic3', 'Bossmusic4', 'Bossmusic5'];
				var musicIndex = (currentWave / 10 - 1) % bossMusics.length;
				musicToPlay = bossMusics[musicIndex];
			} else if (currentWave > 1 && (currentWave - 1) % 10 === 0) {
				// isPostBossWave
				var gameMusics = ['Gamemusic1', 'Gamemusic2', 'gamemusic3', 'Gamemusic4', 'Gamemusic5'];
				var musicIndex = Math.floor((currentWave - 1) / 10) % gameMusics.length;
				musicToPlay = gameMusics[musicIndex];
			}
			if (musicToPlay) {
				LK.playMusic(musicToPlay, {
					fade: {
						start: 0,
						end: musicVolume,
						duration: 100
					}
				});
			}
		}
		lastWave = currentWave;
	}
	if (waveInProgress) {
		if (!waveSpawned) {
			waveSpawned = true;
			// Get wave type and enemy count from the wave indicator
			var waveType = waveIndicator.getWaveType(currentWave);
			var enemyCount = waveIndicator.getEnemyCount(currentWave);
			// Check if this is a boss wave
			var isBossWave = currentWave % 10 === 0 && currentWave > 0;
			if (isBossWave && waveType !== 'swarm') {
				// Boss waves have just 1 enemy regardless of what the wave indicator says
				enemyCount = 1;
				// Show boss announcement
				var notification = game.addChild(new Notification("⚠️ BOSS WAVE! ⚠️"));
				notification.x = 2048 / 2;
				notification.y = 2732 / 2;
			}
			// Spawn the appropriate number of enemies
			for (var i = 0; i < enemyCount; i++) {
				var enemy = new Enemy(waveType);
				// Add enemy to the appropriate layer based on type
				if (enemy.isFlying) {
					// Add flying enemy to the top layer
					enemyLayerTop.addChild(enemy);
					// If it's a flying enemy, add its shadow to the middle layer
					if (enemy.shadow) {
						enemyLayerMiddle.addChild(enemy.shadow);
					}
				} else {
					// Add normal/ground enemies to the bottom layer
					enemyLayerBottom.addChild(enemy);
				}
				// Enemy scaling is now handled in Enemy constructor based on currentWave
				// This ensures consistent scaling every 5 waves for all enemy types
				// All enemy types now spawn in the middle 6 tiles at the top spacing
				var gridWidth = 24;
				var midPoint = Math.floor(gridWidth / 2); // 12
				// Find a column that isn't occupied by another enemy that's not yet in view
				var availableColumns = [];
				for (var col = midPoint - 3; col < midPoint + 3; col++) {
					var columnOccupied = false;
					// Check if any enemy is already in this column but not yet in view
					for (var e = 0; e < enemies.length; e++) {
						if (enemies[e].cellX === col && enemies[e].currentCellY < 4) {
							columnOccupied = true;
							break;
						}
					}
					if (!columnOccupied) {
						availableColumns.push(col);
					}
				}
				// If all columns are occupied, use original random method
				var spawnX;
				if (availableColumns.length > 0) {
					// Choose a random unoccupied column
					spawnX = availableColumns[Math.floor(Math.random() * availableColumns.length)];
				} else {
					// Fallback to random if all columns are occupied
					spawnX = midPoint - 3 + Math.floor(Math.random() * 6); // x from 9 to 14
				}
				var spawnY = -1 - Math.random() * 5; // Random distance above the grid for spreading
				enemy.cellX = spawnX;
				enemy.cellY = 5; // Position after entry
				enemy.currentCellX = spawnX;
				enemy.currentCellY = spawnY;
				enemy.waveNumber = currentWave;
				enemies.push(enemy);
			}
		}
		var currentWaveEnemiesRemaining = false;
		for (var i = 0; i < enemies.length; i++) {
			if (enemies[i].waveNumber === currentWave) {
				currentWaveEnemiesRemaining = true;
				break;
			}
		}
		if (waveSpawned && !currentWaveEnemiesRemaining) {
			waveInProgress = false;
			waveSpawned = false;
		}
	}
	for (var a = enemies.length - 1; a >= 0; a--) {
		var enemy = enemies[a];
		if (enemy.health <= 0) {
			for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
				var bullet = enemy.bulletsTargetingThis[i];
				bullet.targetEnemy = null;
			}
			// Boss enemies give more crystals and score - increased rewards
			var crystalsEarned = enemy.isBoss ? Math.floor(25 + (enemy.waveNumber - 1) * 1.5) : Math.floor(3 + (enemy.waveNumber - 1) * 0.4);
			var crystalIndicator = new CrystalIndicator(crystalsEarned, enemy.x, enemy.y);
			game.addChild(crystalIndicator);
			setCrystals(crystals + crystalsEarned);
			// Give more score for defeating a boss
			var scoreValue = enemy.isBoss ? 100 : 5;
			score += scoreValue;
			// Add a notification for boss defeat
			if (enemy.isBoss) {
				var notification = game.addChild(new Notification("Boss defeated! +" + crystalsEarned + " crystal!"));
				notification.x = 2048 / 2;
				notification.y = 2732 / 2;
			}
			updateUI();
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			continue;
		}
		if (grid.updateEnemy(enemy)) {
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			lives = Math.max(0, lives - 1);
			updateUI();
			if (lives <= 0) {
				// Save high score before showing game over
				addHighScore(score);
				LK.showGameOver();
			}
		}
	}
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (!bullets[i].parent) {
			if (bullets[i].targetEnemy) {
				var targetEnemy = bullets[i].targetEnemy;
				var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
				if (bulletIndex !== -1) {
					targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
				}
			}
			bullets.splice(i, 1);
		}
	}
	if (towerPreview.visible) {
		towerPreview.checkPlacement();
	}
	if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) {
		// Save high score before showing you win
		addHighScore(score);
		LK.showYouWin();
	}
	// Ship spawning logic
	// Spawn ship1 or ship2 randomly, on average every 20 seconds
	if (Math.random() < 1 / 1200) {
		// 1200 ticks = 20 seconds at 60 FPS
		// Randomly select ship type (1 or 2)
		var shipType = Math.floor(Math.random() * 2) + 1;
		var ship = new Ship(shipType);
		// Add ship to game at a lower layer so it appears behind game elements
		game.addChildAt(ship, 1); // Just above background
		ships.push(ship);
	}
	// Spawn ship3 every 40 seconds
	if (LK.ticks - lastShip3Spawn >= ship3SpawnInterval) {
		lastShip3Spawn = LK.ticks;
		var ship = new Ship(3);
		// Add ship to game at a lower layer so it appears behind game elements
		game.addChildAt(ship, 1); // Just above background
		ships.push(ship);
	}
	// Update and cleanup ships
	for (var i = ships.length - 1; i >= 0; i--) {
		if (!ships[i].parent) {
			ships.splice(i, 1);
		}
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var AbilitiesMenu = Container.expand(function () {
	var self = Container.call(this);
	var menuBackground = self.attachAsset('AbilitiesBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	menuBackground.alpha = 0.95;
	var closeButton = self.attachAsset('Abilitiesclosebutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.x = 33;
	closeButton.y = menuBackground.height / 2 - 60;
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideAbilities();
	};
	var gridContainer = new Container();
	self.addChild(gridContainer);
	var gridCols = 3;
	var gridRows = 3;
	var cellWidth = 350;
	var cellHeight = 300;
	var padding = 50;
	var gridTotalWidth = gridCols * cellWidth + (gridCols - 1) * padding;
	var gridTotalHeight = gridRows * cellHeight + (gridRows - 1) * padding;
	// Center the grid horizontally and vertically within the background, then move 160px right and 50px down
	gridContainer.x = -gridTotalWidth / 2 + 210; // 150 + 50 + 10 = 210
	gridContainer.y = -gridTotalHeight / 2; // -50 + 50 = 0
	var title = new Text2("Abilities", {
		size: 80,
		fill: 0xff7b00,
		weight: 800
	});
	title.anchor.set(0.5, 0.5);
	title.x = 43;
	title.y = -menuBackground.height / 2 + 80;
	self.addChild(title);
	// Create description tooltip that will be shared by all cells
	var descriptionTooltip = null;
	for (var row = 0; row < gridRows; row++) {
		for (var col = 0; col < gridCols; col++) {
			(function (r, c) {
				var abilityIndex = r * gridCols + c;
				var abilityId = 'ability_' + abilityIndex;
				var abilityCost = (abilityIndex + 1) * 100;
				var abilityDef = abilityDefinitions[abilityId];
				var cell = new Container();
				cell.x = c * (cellWidth + padding);
				cell.y = r * (cellHeight + padding);
				gridContainer.addChild(cell);
				// Set initial animation state for entrance effect
				cell.alpha = 0;
				cell.scaleX = 0.3;
				cell.scaleY = 0.3;
				cell.y += 50; // Start slightly below final position
				// Calculate staggered delay based on position (diagonal wave effect)
				var animationDelay = (r + c) * 100; // 100ms delay per diagonal step
				// Animate entrance with staggered timing
				tween(cell, {
					alpha: 1,
					scaleX: 1,
					scaleY: 1,
					y: r * (cellHeight + padding)
				}, {
					duration: 400,
					delay: animationDelay,
					easing: tween.easeOut
				});
				var abilityIcon = cell.attachAsset(abilityDef.icon, {
					anchorX: 0.5,
					anchorY: 0.5
				});
				abilityIcon.y = 50;
				abilityIcon.tint = abilityDef.color;
				// Add ability name
				var abilityName = new Text2(abilityDef.name, {
					size: 48,
					fill: 0x00ffb3,
					weight: 600
				});
				abilityName.anchor.set(0.5, 0.5);
				abilityName.y = 50; // Center in the middle of the ability icon
				cell.addChild(abilityName);
				// Position buttons below the icon
				var buttonY = 250;
				// --- Use Button ---
				var useButton = new Container();
				useButton.y = buttonY;
				cell.addChild(useButton);
				var useBg = useButton.attachAsset('ScoreButton', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 200,
					height: 100
				});
				var useText = new Text2("USE\n" + abilityCost + " C", {
					size: 36,
					fill: 0xffffff,
					align: 'center',
					weight: 600
				});
				useText.anchor.set(0.5, 0.5);
				useButton.addChild(useText);
				// --- Button Handlers ---
				useButton.down = function () {
					var canUseNow = gameStarted && !showingIntro && canStartWaves;
					if (!canUseNow) {
						var notification = game.addChild(new Notification("Cannot use abilities until game starts!"));
						return;
					}
					if (crystals >= abilityCost) {
						LK.getSound('Useabilitysound1').play();
						setCrystals(crystals - abilityCost);
						abilityDef.effect();
						hideAbilities();
					} else {
						var notification = game.addChild(new Notification("Not enough crystals!"));
					}
				};
				// --- Update visuals based on state ---
				cell.update = function () {
					var canUseNow = gameStarted && !showingIntro && canStartWaves;
					var canAfford = crystals >= abilityCost;
					if (canUseNow) {
						useBg.tint = canAfford ? 0x00ff00 : 0xff0000; // Green if affordable, red if not
					} else {
						useBg.tint = 0x808080; // Gray if not usable
					}
					abilityIcon.alpha = canAfford ? 1.0 : 0.6;
				};
				cell.update(); // Initial call to set state
				// Hover functionality removed - descriptions only show on click
				cell.down = function () {
					// Show bigger description notification when clicking on cell
					var descriptionNotification = game.addChild(new Container());
					var notificationBg = descriptionNotification.attachAsset('notification3', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					notificationBg.tint = 0x000000;
					notificationBg.alpha = 0.9;
					var descText = new Text2(abilityDef.description, {
						size: 48,
						fill: 0xffffff,
						weight: 600,
						align: 'center'
					});
					descText.anchor.set(0.5, 0.5);
					descriptionNotification.addChild(descText);
					descriptionNotification.x = 2048 / 2;
					descriptionNotification.y = 2732 / 2;
					descriptionNotification.alpha = 0;
					descriptionNotification.scaleX = 0.5;
					descriptionNotification.scaleY = 0.5;
					// Animate in
					tween(descriptionNotification, {
						alpha: 1,
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 300,
						easing: tween.easeOut
					});
					// Auto hide after 3 seconds
					LK.setTimeout(function () {
						tween(descriptionNotification, {
							alpha: 0,
							scaleX: 0.5,
							scaleY: 0.5
						}, {
							duration: 300,
							easing: tween.easeIn,
							onFinish: function onFinish() {
								descriptionNotification.destroy();
							}
						});
					}, 3000);
				};
			})(row, col);
		}
	}
	self.update = function () {
		for (var i = 0; i < gridContainer.children.length; i++) {
			var cell = gridContainer.children[i];
			if (cell.update) {
				cell.update();
			}
		}
	};
	// Tooltip functionality removed
	return self;
});
var Bullet = Container.expand(function (startX, startY, targetEnemy, damage, speed) {
	var self = Container.call(this);
	self.targetEnemy = targetEnemy;
	self.damage = damage || 10;
	self.speed = speed || 5;
	self.x = startX;
	self.y = startY;
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.update = function () {
		if (!self.targetEnemy || !self.targetEnemy.parent) {
			self.destroy();
			return;
		}
		// Check if bullet has exceeded its source tower's range (for all tower types)
		if (self.sourceTower) {
			var towerDx = self.x - self.sourceTower.x;
			var towerDy = self.y - self.sourceTower.y;
			var distanceFromTower = Math.sqrt(towerDx * towerDx + towerDy * towerDy);
			if (distanceFromTower > self.sourceTower.getRange()) {
				self.destroy();
				return;
			}
		}
		var dx = self.targetEnemy.x - self.x;
		var dy = self.targetEnemy.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance < self.speed) {
			// Apply damage to target enemy with resistance scaling
			var actualDamage = self.damage;
			if (self.targetEnemy.damageResistance) {
				actualDamage = self.damage * self.targetEnemy.damageResistance;
			}
			self.targetEnemy.health -= actualDamage;
			// Play damage sound based on enemy type
			var enemyAssetId = null;
			if (self.targetEnemy.children && self.targetEnemy.children[0]) {
				// Get the asset ID from the enemy's graphics to determine sound
				var enemyGraphics = self.targetEnemy.children[0];
				// Check enemy type based on wave progression and type
				if (self.targetEnemy.type === 'immune') {
					// Big Robot enemies (immune type)
					game.playSoundWithVolume('Bigrobots_damage_sound1');
				} else if (self.targetEnemy.type === 'normal') {
					// Cyborg enemies (normal type)
					game.playSoundWithVolume('Cyborg_Damage_sound1');
				} else if (self.targetEnemy.type === 'swarm') {
					// CyberSnake enemies (swarm type)
					game.playSoundWithVolume('Cybersnake_damage_sound1');
				} else if (self.targetEnemy.type === 'flying') {
					// Flying enemies - determine specific type
					var waveGroup = Math.floor((self.targetEnemy.waveNumber - 1) / 10);
					var flyingAssets = ['Firo', 'Eye', 'Electro'];
					var assetIndex = waveGroup % flyingAssets.length;
					var flyingAsset = flyingAssets[assetIndex];
					if (flyingAsset === 'Eye') {
						game.playSoundWithVolume('Eye_Damage_sound1');
					} else if (flyingAsset === 'Firo') {
						game.playSoundWithVolume('Firo_Damage_sound1');
					} else if (flyingAsset === 'Electro') {
						game.playSoundWithVolume('Electro_Damage_sound1');
					}
				} else if (self.targetEnemy.type === 'fast') {
					// Fast enemies use Robot1, Spider1, Spider2
					game.playSoundWithVolume('Robot_Damage_sound1');
				}
			}
			if (self.targetEnemy.health <= 0) {
				self.targetEnemy.health = 0;
			} else {
				// Update enemy health bar using stored original width
				var healthPercentage = self.targetEnemy.health / self.targetEnemy.maxHealth;
				self.targetEnemy.healthBar.width = self.targetEnemy.healthBarOriginalWidth * healthPercentage;
			}
			// Apply special effects based on bullet type
			if (self.type === 'cannon') {
				// Create fire explosion effect for cannon bullets
				var explosionEffect = new Container();
				explosionEffect.x = self.targetEnemy.x;
				explosionEffect.y = self.targetEnemy.y;
				game.addChild(explosionEffect);
				// Create multiple fire particles for the explosion
				for (var fireParticle = 0; fireParticle < 8; fireParticle++) {
					var particle = explosionEffect.attachAsset('rangeCircle', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					particle.width = particle.height = 20 + Math.random() * 30;
					particle.tint = fireParticle % 2 === 0 ? 0xFF4500 : 0xFF8C00; // Orange-red fire colors
					particle.alpha = 0.8;
					particle.blendMode = 1; // Add blend mode for fire effect
					particle.x = (Math.random() - 0.5) * 40;
					particle.y = (Math.random() - 0.5) * 40;
					particle.scaleX = 0.1;
					particle.scaleY = 0.1;
					// Animate each particle exploding outward
					tween(particle, {
						scaleX: 1.5,
						scaleY: 1.5,
						x: particle.x + (Math.random() - 0.5) * 60,
						y: particle.y + (Math.random() - 0.5) * 60,
						alpha: 0
					}, {
						duration: 300 + Math.random() * 200,
						easing: tween.easeOut
					});
				}
				// Create central explosion flash
				var centralFlash = explosionEffect.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				centralFlash.width = centralFlash.height = 80;
				centralFlash.tint = 0xFFFFAA; // Bright yellow-white center
				centralFlash.alpha = 1;
				centralFlash.blendMode = 1;
				centralFlash.scaleX = 0.1;
				centralFlash.scaleY = 0.1;
				// Animate central flash
				tween(centralFlash, {
					scaleX: 2,
					scaleY: 2,
					alpha: 0
				}, {
					duration: 400,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						explosionEffect.destroy();
					}
				});
			} else if (self.type === 'Rocket') {
				// Create visual splash effect
				var splashEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'splash');
				game.addChild(splashEffect);
				// Splash damage to nearby enemies - 200x200 area means 100 pixel radius
				var splashRadius = 100;
				for (var i = 0; i < enemies.length; i++) {
					var otherEnemy = enemies[i];
					if (otherEnemy !== self.targetEnemy) {
						var splashDx = otherEnemy.x - self.targetEnemy.x;
						var splashDy = otherEnemy.y - self.targetEnemy.y;
						var splashDistance = Math.sqrt(splashDx * splashDx + splashDy * splashDy);
						if (splashDistance <= splashRadius) {
							// Apply splash damage (50% of original damage)
							otherEnemy.health -= self.damage * 0.5;
							if (otherEnemy.health <= 0) {
								otherEnemy.health = 0;
							} else {
								// Update enemy health bar using stored original width
								var healthPercentage = otherEnemy.health / otherEnemy.maxHealth;
								otherEnemy.healthBar.width = otherEnemy.healthBarOriginalWidth * healthPercentage;
							}
						}
					}
				}
			} else if (self.type === 'gumbomb') {
				// Prevent gum effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create visual gumbomb explosion effect
					var gumEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'gumbomb');
					game.addChild(gumEffect);
					// Apply gum stuck effect - enemies become completely immobilized
					if (!self.targetEnemy.gumStuck) {
						self.targetEnemy.originalSpeed = self.targetEnemy.speed;
						self.targetEnemy.speed = 0; // Completely stuck
						self.targetEnemy.gumStuck = true;
						self.targetEnemy.gumDuration = 240; // 4 seconds at 60 FPS
						// Create purple gum effect beneath the enemy
						var gumStuckGraphics = LK.getAsset('gumStuckEffect', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						gumStuckGraphics.x = self.targetEnemy.x;
						gumStuckGraphics.y = self.targetEnemy.y + self.targetEnemy.children[0].height / 2;
						gumStuckGraphics.alpha = 0;
						gumStuckGraphics.scaleX = 0.1;
						gumStuckGraphics.scaleY = 0.1;
						self.targetEnemy.gumStuckEffect = gumStuckGraphics;
						enemyLayerBottom.addChildAt(gumStuckGraphics, 0);
						// Explosion animation - scale up and fade in quickly
						tween(gumStuckGraphics, {
							alpha: 0.7,
							scaleX: 1.2,
							scaleY: 1.2
						}, {
							duration: 200,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								// Settle to normal size
								tween(gumStuckGraphics, {
									scaleX: 1,
									scaleY: 1
								}, {
									duration: 300,
									easing: tween.elasticOut
								});
								// Set up tween to destroy gum area after 4 seconds
								tween(gumStuckGraphics, {
									alpha: 0
								}, {
									duration: 4000,
									onFinish: function onFinish() {
										if (gumStuckGraphics && gumStuckGraphics.parent) {
											gumStuckGraphics.parent.removeChild(gumStuckGraphics);
										}
									}
								});
							}
						});
					} else {
						self.targetEnemy.gumDuration = 240; // Reset duration to 4 seconds
					}
				}
			} else if (self.type === 'ToxinBomb') {
				// Prevent toxin effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create ToxinBombEffect explosion effect using ToxinBombEffect asset
					var explosionEffect = new Container();
					explosionEffect.x = self.targetEnemy.x;
					explosionEffect.y = self.targetEnemy.y;
					game.addChild(explosionEffect);
					// Create the main toxin explosion using ToxinBombEffect asset
					var toxinExplosion = explosionEffect.attachAsset('ToxinBombEffect', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					toxinExplosion.width = toxinExplosion.height = 150;
					toxinExplosion.tint = 0x00FFb3; // Green toxin color
					toxinExplosion.alpha = 0.9;
					toxinExplosion.scaleX = 0.1;
					toxinExplosion.scaleY = 0.1;
					// Animate the toxin explosion expanding and fading
					tween(toxinExplosion, {
						scaleX: 1.8,
						scaleY: 1.8,
						alpha: 0.3
					}, {
						duration: 400,
						easing: tween.easeOut
					});
					// Create additional smaller toxin particles around the main explosion
					for (var toxinParticle = 0; toxinParticle < 6; toxinParticle++) {
						var particle = explosionEffect.attachAsset('ToxinBombEffect', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						particle.width = particle.height = 40 + Math.random() * 30;
						particle.tint = 0x00FFb3; // Consistent green toxin color
						particle.alpha = 0.7;
						particle.x = (Math.random() - 0.5) * 80;
						particle.y = (Math.random() - 0.5) * 80;
						particle.scaleX = 0.1;
						particle.scaleY = 0.1;
						// Animate each particle expanding outward
						tween(particle, {
							scaleX: 1.2,
							scaleY: 1.2,
							x: particle.x + (Math.random() - 0.5) * 100,
							y: particle.y + (Math.random() - 0.5) * 100,
							alpha: 0
						}, {
							duration: 500 + Math.random() * 200,
							easing: tween.easeOut
						});
					}
					// Destroy the explosion effect after animation completes
					tween(explosionEffect, {
						alpha: 1
					}, {
						duration: 600,
						onFinish: function onFinish() {
							explosionEffect.destroy();
						}
					});
					// Apply toxin effect
					self.targetEnemy.poisoned = true;
					self.targetEnemy.poisonDamage = self.damage * 0.2; // 20% of original damage per tick
					self.targetEnemy.poisonDuration = 300; // 5 seconds at 60 FPS
				}
			}
			// Flame tower does not use bullets, so destroy any 'flame' type bullets immediately
			if (self.type === 'flame') {
				self.destroy();
			} else {
				self.destroy();
			}
		} else {
			var angle = Math.atan2(dy, dx);
			// Rotate bullet to face movement direction
			if (self.children[0]) {
				// Check if this is a RifleBullet which needs rotation offset
				var rotationOffset = 0;
				if (self.type === 'rifle') {
					rotationOffset = Math.PI / 2; // Compensate for upward-pointing asset
				}
				var targetAngle = angle + rotationOffset;
				if (self.children[0].targetRotation === undefined) {
					self.children[0].targetRotation = targetAngle;
					self.children[0].rotation = targetAngle;
				} else {
					if (Math.abs(targetAngle - self.children[0].targetRotation) > 0.05) {
						tween.stop(self.children[0], {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = self.children[0].rotation;
						var angleDiff = targetAngle - currentRotation;
						// Normalize angle difference to -PI to PI range for shortest path
						while (angleDiff > Math.PI) {
							angleDiff -= Math.PI * 2;
						}
						while (angleDiff < -Math.PI) {
							angleDiff += Math.PI * 2;
						}
						self.children[0].targetRotation = targetAngle;
						tween(self.children[0], {
							rotation: currentRotation + angleDiff
						}, {
							duration: 100,
							easing: tween.easeOut
						});
					}
				}
			}
			self.x += Math.cos(angle) * self.speed;
			self.y += Math.sin(angle) * self.speed;
		}
	};
	return self;
});
var CrystalIndicator = Container.expand(function (value, x, y) {
	var self = Container.call(this);
	var shadowText = new Text2("+" + value, {
		size: 45,
		fill: 0x000000,
		weight: 800
	});
	shadowText.anchor.set(0.5, 0.5);
	shadowText.x = 2;
	shadowText.y = 2;
	self.addChild(shadowText);
	var crystalText = new Text2("+" + value, {
		size: 45,
		fill: 0xff0080,
		weight: 800
	});
	crystalText.anchor.set(0.5, 0.5);
	self.addChild(crystalText);
	self.x = x;
	self.y = y;
	self.alpha = 0;
	self.scaleX = 0.5;
	self.scaleY = 0.5;
	tween(self, {
		alpha: 1,
		scaleX: 1.2,
		scaleY: 1.2,
		y: y - 40
	}, {
		duration: 50,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(self, {
				alpha: 0,
				scaleX: 1.5,
				scaleY: 1.5,
				y: y - 80
			}, {
				duration: 600,
				easing: tween.easeIn,
				delay: 800,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		}
	});
	return self;
});
var DebugCell = Container.expand(function () {
	var self = Container.call(this);
	var cellGraphics = self.attachAsset('cell', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	cellGraphics.tint = Math.random() * 0xffffff;
	var debugArrows = [];
	// Numbers removed - using animated orange lines only
	self.update = function () {};
	self.down = function () {
		return;
		if (self.cell.type == 0 || self.cell.type == 1) {
			self.cell.type = self.cell.type == 1 ? 0 : 1;
			if (grid.pathFind()) {
				self.cell.type = self.cell.type == 1 ? 0 : 1;
				grid.pathFind();
				var notification = game.addChild(new Notification("Path is blocked!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
			}
			grid.renderDebug();
		}
	};
	self.removeArrows = function () {
		while (debugArrows.length) {
			self.removeChild(debugArrows.pop());
		}
	};
	self.render = function (data) {
		switch (data.type) {
			case 0:
			case 2:
				{
					if (data.pathId != pathId) {
						self.removeArrows();
						cellGraphics.tint = 0x880000;
						return;
					}
					var towerInRangeHighlight = false;
					if (selectedTower && data.towersInRange && data.towersInRange.indexOf(selectedTower) !== -1) {
						towerInRangeHighlight = true;
						cellGraphics.tint = 0xe14de9; // pink color with transparency
						cellGraphics.alpha = 0.5; // Almost max transparent
					} else {
						cellGraphics.tint = 0x4db3e9; // Sky blue color with transparency
						cellGraphics.alpha = 0.5; // Almost max transparent
					}
					while (debugArrows.length > data.targets.length) {
						self.removeChild(debugArrows.pop());
					}
					for (var a = 0; a < data.targets.length; a++) {
						var destination = data.targets[a];
						var ox = destination.x - data.x;
						var oy = destination.y - data.y;
						// Change lines pointing up to point down
						if (oy < 0) {
							oy = -oy; // Flip the y direction for upward pointing lines
						}
						var angle = Math.atan2(oy, ox);
						if (!debugArrows[a]) {
							// Create arrow container
							debugArrows[a] = new Container();
							// Create arrow shaft using shape asset
							var arrowShaft = LK.getAsset('cell', {
								anchorX: 0,
								anchorY: 0.5
							});
							arrowShaft.width = 40;
							arrowShaft.height = 8;
							arrowShaft.tint = 0xff0080;
							debugArrows[a].addChild(arrowShaft);
							// Create arrow head using shape asset
							var arrowHead = LK.getAsset('cell', {
								anchorX: 0,
								anchorY: 0.5
							});
							arrowHead.width = 20;
							arrowHead.height = 16;
							arrowHead.tint = 0xff0080;
							arrowHead.x = 35; // Position at end of shaft
							arrowHead.y = 0;
							debugArrows[a].addChild(arrowHead);
							self.addChildAt(debugArrows[a], 1);
						}
						// Fix rotation calculation - ensure correct direction mapping
						debugArrows[a].rotation = angle;
						// Position the line at center of cell for better visibility
						debugArrows[a].x = 0;
						debugArrows[a].y = 0;
						// Animate the violet arrow with flowing effect
						var arrow = debugArrows[a];
						arrow.animationPhase = (arrow.animationPhase || 0) + 0.1;
						// Create flowing effect by animating scale - maintain consistent base scale
						var flowScale = 1.0 + 0.3 * Math.sin(arrow.animationPhase * 1.2);
						arrow.scaleX = flowScale;
						// Reset scale Y to ensure proper aspect ratio
						arrow.scaleY = 1.0;
					}
					break;
				}
			case 1:
				{
					self.removeArrows();
					// Replace the cell with DebugWall image asset
					if (cellGraphics) {
						self.removeChild(cellGraphics);
					}
					cellGraphics = self.attachAsset('DebugWall', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					cellGraphics.alpha = 0.9; // Make wall more visible
					break;
				}
			case 3:
				{
					self.removeArrows();
					cellGraphics.tint = 0xff0080; // pink
					cellGraphics.alpha = 5;
					break;
				}
		}
	};
});
// This update method was incorrectly placed here and should be removed
var EffectIndicator = Container.expand(function (x, y, type) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	var effectGraphics = self.attachAsset('rangeCircle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	effectGraphics.blendMode = 1;
	switch (type) {
		case 'splash':
			effectGraphics.tint = 0x33CC00;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5;
			break;
		case 'slow':
			effectGraphics.tint = 0x9900FF;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'gumbomb':
			effectGraphics.tint = 0x9900FF;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 2; // Larger explosion effect
			break;
		case 'toxin':
			effectGraphics.tint = 0x00FFb3;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'flame':
			effectGraphics.tint = 0xFF8800; // Mix of yellow, orange, red
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
	}
	effectGraphics.alpha = 0.7;
	self.alpha = 0;
	// Animate the effect
	tween(self, {
		alpha: 0.8,
		scaleX: 1.5,
		scaleY: 1.5
	}, {
		duration: 200,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(self, {
				alpha: 0,
				scaleX: 2,
				scaleY: 2
			}, {
				duration: 300,
				easing: tween.easeIn,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		}
	});
	return self;
});
// Base enemy class for common functionality
var Enemy = Container.expand(function (type) {
	var self = Container.call(this);
	self.type = type || 'normal';
	self.speed = .01;
	self.cellX = 0;
	self.cellY = 0;
	self.currentCellX = 0;
	self.currentCellY = 0;
	self.currentTarget = undefined;
	self.maxHealth = 100;
	self.health = self.maxHealth;
	self.bulletsTargetingThis = [];
	self.waveNumber = currentWave;
	self.isFlying = false;
	self.isImmune = false;
	self.isBoss = false;
	// Check if this is a boss wave
	// Check if this is a boss wave
	// Apply different stats based on enemy type - increased health
	switch (self.type) {
		case 'fast':
			self.speed *= 2; // Twice as fast
			self.maxHealth = 45; // Increased from 30
			break;
		case 'immune':
			self.isImmune = true;
			self.maxHealth = 40; // Increased from 25
			break;
		case 'flying':
			self.isFlying = true;
			self.maxHealth = 40; // Increased from 25
			break;
		case 'swarm':
			self.maxHealth = 25; // Increased from 15
			break;
		case 'normal':
		default:
			self.maxHealth = 35; // Increased from 20
			break;
	}
	if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') {
		self.isBoss = true;
		// Boss enemies have 8x health and are larger
		self.maxHealth *= 8;
		// Slightly slower speed for bosses but not as much
		self.speed = self.speed * 0.8;
	}
	// Apply wave-based difficulty scaling every 5 waves
	var difficultyWaves = Math.floor((currentWave - 1) / 5);
	if (difficultyWaves > 0) {
		// Increase health by 75% every 5 waves (was 50%)
		var healthMultiplier = 1 + difficultyWaves * 0.75;
		self.maxHealth = Math.round(self.maxHealth * healthMultiplier);
		// Increase speed by 30% every 5 waves (was 20%)
		var speedMultiplier = 1 + difficultyWaves * 0.3;
		self.speed = self.speed * speedMultiplier;
		// Add damage resistance - enemies take 10% less damage every 5 waves
		self.damageResistance = 1 - Math.min(0.5, difficultyWaves * 0.1); // Cap at 50% resistance
	}
	self.health = self.maxHealth;
	// Get appropriate asset for this enemy type
	var assetId = 'enemy';
	if (self.type !== 'normal') {
		assetId = 'enemy_' + self.type;
	}
	// For flying enemies, use different assets based on wave progression
	if (self.type === 'flying') {
		// Use different flying enemy assets based on wave number
		var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change flying enemy type
		var flyingAssets = ['Firo', 'Eye', 'Electro'];
		var assetIndex = waveGroup % flyingAssets.length;
		assetId = flyingAssets[assetIndex];
	} else {
		// For ground enemies, use different Cyborg assets based on wave number
		var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change ground enemy type
		var groundAssets = ['Cyborg', 'Cyborg2', 'Cyborg3'];
		var assetIndex = waveGroup % groundAssets.length;
		if (self.type === 'normal') {
			assetId = groundAssets[assetIndex];
		} else if (self.type === 'fast') {
			// For fast enemies, use Robot1, Spider1, and Spider2 assets based on wave progression
			var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change fast enemy type
			var fastAssets = ['Robot1', 'Spider1', 'Spider2'];
			var assetIndex = waveGroup % fastAssets.length;
			assetId = fastAssets[assetIndex];
		} else if (self.type === 'immune') {
			// For immune enemies, use Big_Robot1, Big_Robot2, and Big_Robot3 assets based on wave progression
			var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change immune enemy type
			var immuneAssets = ['Big_Robot1', 'Big_Robot2', 'Big_Robot3'];
			var assetIndex = waveGroup % immuneAssets.length;
			assetId = immuneAssets[assetIndex];
		} else if (self.type === 'swarm') {
			// For swarm enemies, use CyberSnake1, CyberSnake2, and CyberSnake3 assets based on wave progression
			var waveGroup = Math.floor((currentWave - 1) / 10); // Every 10 waves change swarm enemy type
			var swarmAssets = ['CyberSnake1', 'CyberSnake2', 'CyberSnake3'];
			var assetIndex = waveGroup % swarmAssets.length;
			assetId = swarmAssets[assetIndex];
		} else {
			// For other non-normal ground enemies, still use the original prefixed system but could be enhanced later
			assetId = 'enemy_' + self.type;
		}
	}
	var enemyGraphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Scale up boss enemies
	if (self.isBoss) {
		enemyGraphics.scaleX = 1.8;
		enemyGraphics.scaleY = 1.8;
	}
	// Fall back to regular enemy asset if specific type asset not found
	// Apply tint to differentiate enemy types
	/*switch (self.type) {
		case 'fast':
			enemyGraphics.tint = 0x00AAFF; // Blue for fast enemies
			break;
		case 'immune':
			enemyGraphics.tint = 0xAA0000; // Red for immune enemies
			break;
		case 'flying':
			enemyGraphics.tint = 0xFFFF00; // Yellow for flying enemies
			break;
		case 'swarm':
			enemyGraphics.tint = 0xFF00FF; // Pink for swarm enemies
			break;
	}*/
	// Create shadow for flying enemies
	if (self.isFlying) {
		// Create a shadow container that will be added to the shadow layer
		self.shadow = new Container();
		// Clone the enemy graphics for the shadow - use the same asset as the main enemy
		var shadowAssetId = assetId;
		// For flying enemies, make sure we use the correct asset for the shadow
		if (self.type === 'flying') {
			var waveGroup = Math.floor((currentWave - 1) / 10);
			var flyingAssets = ['Firo', 'Eye', 'Electro'];
			var assetIndex = waveGroup % flyingAssets.length;
			shadowAssetId = flyingAssets[assetIndex];
		}
		var shadowGraphics = self.shadow.attachAsset(shadowAssetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow effect
		shadowGraphics.tint = 0x000000; // Black shadow
		shadowGraphics.alpha = 0.3; // Semi-transparent
		// If this is a boss, scale up the shadow to match
		if (self.isBoss) {
			shadowGraphics.scaleX = 1.8;
			shadowGraphics.scaleY = 1.8;
		}
		// Position shadow slightly offset
		self.shadow.x = 20; // Offset right
		self.shadow.y = 20; // Offset down
		// Ensure shadow has the same rotation as the enemy
		shadowGraphics.rotation = enemyGraphics.rotation;
	}
	var healthBarOutline = self.attachAsset('EnemyHealthBarOutline', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var healthBar = self.attachAsset('Enemyhealthbar', {
		anchorX: 0,
		anchorY: 0.5
	});
	healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	healthBar.x = -healthBar.width / 2;
	self.healthBar = healthBar;
	self.healthBarOriginalWidth = healthBar.width; // Store original width
	self.update = function () {
		if (self.health <= 0) {
			self.health = 0;
			self.healthBar.width = 0;
		} else {
			// Update health bar width based on current health
			var healthPercentage = self.health / self.maxHealth;
			self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
		}
		// Handle slow effect
		if (self.isImmune) {
			// Immune enemies cannot be slowed, gum stuck, or poisoned, clear any such effects
			self.slowed = false;
			self.slowEffect = false;
			self.gumStuck = false;
			if (self.gumStuckEffect && self.gumStuckEffect.parent) {
				game.removeChild(self.gumStuckEffect);
			}
			self.gumStuckEffect = null;
			self.poisoned = false;
			self.poisonEffect = false;
			// Reset speed to original if needed
			if (self.originalSpeed !== undefined) {
				self.speed = self.originalSpeed;
			}
		} else {
			// Handle gum stuck effect
			if (self.gumStuck) {
				// Visual indication of gum stuck status
				if (!self.gumStuckEffect) {
					self.gumStuckEffect = true;
				}
				self.gumDuration--;
				if (self.gumDuration <= 0) {
					self.speed = self.originalSpeed;
					self.gumStuck = false;
					self.gumStuckEffect = false;
					// Remove gum effect visual with fade out animation
					if (self.gumStuckEffect && self.gumStuckEffect.parent) {
						tween(self.gumStuckEffect, {
							alpha: 0,
							scaleX: 1.5,
							scaleY: 1.5
						}, {
							duration: 300,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (self.gumStuckEffect && self.gumStuckEffect.parent) {
									game.removeChild(self.gumStuckEffect);
								}
								self.gumStuckEffect = null;
							}
						});
					} else {
						self.gumStuckEffect = null;
					}
					// Only reset tint if not poisoned
					if (!self.poisoned) {
						enemyGraphics.tint = 0xFFFFFF; // Reset tint
					}
				} else {
					// Update gum effect position to follow enemy
					if (self.gumStuckEffect && self.gumStuckEffect.parent) {
						self.gumStuckEffect.x = self.x;
						self.gumStuckEffect.y = self.y + enemyGraphics.height / 2;
					}
				}
			}
			// Handle poison effect
			if (self.poisoned) {
				// Visual indication of poisoned status
				if (!self.poisonEffect) {
					self.poisonEffect = true;
				}
				// Apply poison damage every 30 frames (twice per second)
				if (LK.ticks % 30 === 0) {
					var actualPoisonDamage = self.poisonDamage;
					if (self.damageResistance) {
						actualPoisonDamage = self.poisonDamage * self.damageResistance;
					}
					self.health -= actualPoisonDamage;
					if (self.health <= 0) {
						self.health = 0;
					}
					// Update enemy health bar using stored original width
					var healthPercentage = self.health / self.maxHealth;
					self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
				}
				self.poisonDuration--;
				if (self.poisonDuration <= 0) {
					self.poisoned = false;
					self.poisonEffect = false;
					// Only reset tint if not slowed
					if (!self.slowed) {
						enemyGraphics.tint = 0xFFFFFF; // Reset tint
					}
				}
			}
			// Handle weakness effect
			if (self.weakened) {
				self.weakenDuration--;
				if (self.weakenDuration <= 0) {
					self.weakened = false;
					self.damageResistance = self.originalDamageResistance || 1;
				}
			}
			// Handle dust slow effect
			if (self.dustSlowed) {
				self.dustSlowDuration--;
				if (self.dustSlowDuration <= 0) {
					self.dustSlowed = false;
					self.speed = self.originalSpeed;
				}
			}
			// Handle drowning effect
			if (self.drowning) {
				// Apply drowning damage every frame
				self.health -= self.drownDamage;
				if (self.health <= 0) {
					self.health = 0;
				} else {
					var healthPercentage = self.health / self.maxHealth;
					self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
				}
				self.drownDuration--;
				if (self.drownDuration <= 0) {
					self.drowning = false;
				}
			}
			// Handle burning effect
			if (self.burning) {
				// Apply burn damage every frame
				self.health -= self.burnDamage;
				if (self.health <= 0) {
					self.health = 0;
				} else {
					var healthPercentage = self.health / self.maxHealth;
					self.healthBar.width = self.healthBarOriginalWidth * healthPercentage;
				}
				self.burnDuration--;
				if (self.burnDuration <= 0) {
					self.burning = false;
				}
			}
			// Handle freeze effect
			if (self.frozen) {
				self.freezeDuration--;
				if (self.freezeDuration <= 0) {
					self.frozen = false;
					self.speed = self.originalSpeed;
					// Add ice shattering effect
					(function (enemy) {
						var shatterContainer = new Container();
						shatterContainer.x = enemy.x;
						shatterContainer.y = enemy.y;
						game.addChild(shatterContainer); // Add to game layer, not enemy
						for (var s = 0; s < 12; s++) {
							(function () {
								var shard = shatterContainer.attachAsset('cell', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: 0xB0E0E6,
									// Powder blue
									width: 15 + Math.random() * 10,
									height: 5 + Math.random() * 5,
									rotation: Math.random() * Math.PI * 2,
									alpha: 1.0
								});
								var angle = Math.random() * Math.PI * 2;
								var distance = 40 + Math.random() * 30;
								tween(shard, {
									x: Math.cos(angle) * distance,
									y: Math.sin(angle) * distance,
									alpha: 0,
									rotation: shard.rotation + (Math.random() - 0.5) * Math.PI
								}, {
									duration: 300 + Math.random() * 200,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										if (shard.parent) {
											shard.destroy();
										}
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (shatterContainer.parent) {
								shatterContainer.destroy();
							}
						}, 600);
					})(self);
				}
			}
			// Handle ultimate slow effect
			if (self.ultimateSlowed) {
				self.ultimateSlowDuration--;
				if (self.ultimateSlowDuration <= 0) {
					self.ultimateSlowed = false;
					self.speed = self.originalSpeed;
				}
			}
		}
		// Set tint based on effect status
		if (self.isImmune) {
			enemyGraphics.tint = 0xFFFFFF;
		} else if (self.frozen) {
			enemyGraphics.tint = 0x00FFFF; // Cyan for frozen
		} else if (self.drowning) {
			enemyGraphics.tint = 0x0080FF; // Blue for drowning
		} else if (self.burning) {
			// Tint is handled by the looping animation in the ability effect
		} else if (self.dustSlowed) {
			enemyGraphics.tint = 0x8B4513; // Brown for dust storm
		} else if (self.weakened) {
			enemyGraphics.tint = 0xFF4500; // Orange-red for weakened
		} else if (self.poisoned && (self.slowed || self.gumStuck)) {
			// Combine poison (0x00FFb3) and slow/gum (0x9900FF) colors
			// Simple average: R: (0+153)/2=76, G: (255+0)/2=127, B: (170+255)/2=212
			enemyGraphics.tint = 0x4C7FD4;
		} else if (self.poisoned) {
			enemyGraphics.tint = 0x00FFb3;
		} else if (self.slowed || self.gumStuck) {
			enemyGraphics.tint = 0xff0080;
		} else {
			enemyGraphics.tint = 0xFFFFFF;
		}
		if (self.currentTarget) {
			var ox = self.currentTarget.x - self.currentCellX;
			var oy = self.currentTarget.y - self.currentCellY;
			if (ox !== 0 || oy !== 0) {
				var angle = Math.atan2(oy, ox);
				if (enemyGraphics.targetRotation === undefined) {
					enemyGraphics.targetRotation = angle;
					enemyGraphics.rotation = angle;
				} else {
					if (Math.abs(angle - enemyGraphics.targetRotation) > 0.05) {
						tween.stop(enemyGraphics, {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = enemyGraphics.rotation;
						var angleDiff = angle - currentRotation;
						// Normalize angle difference to -PI to PI range for shortest path
						while (angleDiff > Math.PI) {
							angleDiff -= Math.PI * 2;
						}
						while (angleDiff < -Math.PI) {
							angleDiff += Math.PI * 2;
						}
						enemyGraphics.targetRotation = angle;
						tween(enemyGraphics, {
							rotation: currentRotation + angleDiff
						}, {
							duration: 250,
							easing: tween.easeOut
						});
					}
				}
			}
		}
		healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	};
	return self;
});
var Grid = Container.expand(function (gridWidth, gridHeight) {
	var self = Container.call(this);
	self.cells = [];
	self.spawns = [];
	self.goals = [];
	for (var i = 0; i < gridWidth; i++) {
		self.cells[i] = [];
		for (var j = 0; j < gridHeight; j++) {
			self.cells[i][j] = {
				score: 0,
				pathId: 0,
				towersInRange: []
			};
		}
	}
	/*
				Cell Types
				0: Transparent floor
				1: Wall
				2: Spawn
				3: Goal
	*/
	for (var i = 0; i < gridWidth; i++) {
		for (var j = 0; j < gridHeight; j++) {
			var cell = self.cells[i][j];
			var cellType = i === 0 || i === gridWidth - 1 || j <= 4 || j >= gridHeight - 4 ? 1 : 0;
			if (i > 11 - 3 && i <= 11 + 3) {
				if (j === 0) {
					cellType = 2;
					self.spawns.push(cell);
				} else if (j <= 4) {
					cellType = 0;
				} else if (j === gridHeight - 1) {
					cellType = 3;
					self.goals.push(cell);
				} else if (j >= gridHeight - 4) {
					cellType = 0;
				}
			}
			cell.type = cellType;
			cell.x = i;
			cell.y = j;
			cell.upLeft = self.cells[i - 1] && self.cells[i - 1][j - 1];
			cell.up = self.cells[i - 1] && self.cells[i - 1][j];
			cell.upRight = self.cells[i - 1] && self.cells[i - 1][j + 1];
			cell.left = self.cells[i][j - 1];
			cell.right = self.cells[i][j + 1];
			cell.downLeft = self.cells[i + 1] && self.cells[i + 1][j - 1];
			cell.down = self.cells[i + 1] && self.cells[i + 1][j];
			cell.downRight = self.cells[i + 1] && self.cells[i + 1][j + 1];
			cell.neighbors = [cell.upLeft, cell.up, cell.upRight, cell.right, cell.downRight, cell.down, cell.downLeft, cell.left];
			cell.targets = [];
			if (j > 3 && j <= gridHeight - 4) {
				var debugCell = new DebugCell();
				self.addChild(debugCell);
				debugCell.cell = cell;
				debugCell.x = i * CELL_SIZE;
				debugCell.y = j * CELL_SIZE;
				cell.debugCell = debugCell;
			}
		}
	}
	self.getCell = function (x, y) {
		return self.cells[x] && self.cells[x][y];
	};
	self.pathFind = function () {
		var before = new Date().getTime();
		var toProcess = self.goals.concat([]);
		maxScore = 0;
		pathId += 1;
		for (var a = 0; a < toProcess.length; a++) {
			toProcess[a].pathId = pathId;
		}
		function processNode(node, targetValue, targetNode) {
			if (node && node.type != 1) {
				if (node.pathId < pathId || targetValue < node.score) {
					node.targets = [targetNode];
				} else if (node.pathId == pathId && targetValue == node.score) {
					node.targets.push(targetNode);
				}
				if (node.pathId < pathId || targetValue < node.score) {
					node.score = targetValue;
					if (node.pathId != pathId) {
						toProcess.push(node);
					}
					node.pathId = pathId;
					if (targetValue > maxScore) {
						maxScore = targetValue;
					}
				}
			}
		}
		while (toProcess.length) {
			var nodes = toProcess;
			toProcess = [];
			for (var a = 0; a < nodes.length; a++) {
				var node = nodes[a];
				var targetScore = node.score + 14142;
				if (node.up && node.left && node.up.type != 1 && node.left.type != 1) {
					processNode(node.upLeft, targetScore, node);
				}
				if (node.up && node.right && node.up.type != 1 && node.right.type != 1) {
					processNode(node.upRight, targetScore, node);
				}
				if (node.down && node.right && node.down.type != 1 && node.right.type != 1) {
					processNode(node.downRight, targetScore, node);
				}
				if (node.down && node.left && node.down.type != 1 && node.left.type != 1) {
					processNode(node.downLeft, targetScore, node);
				}
				targetScore = node.score + 10000;
				processNode(node.up, targetScore, node);
				processNode(node.right, targetScore, node);
				processNode(node.down, targetScore, node);
				processNode(node.left, targetScore, node);
			}
		}
		for (var a = 0; a < self.spawns.length; a++) {
			if (self.spawns[a].pathId != pathId) {
				console.warn("Spawn blocked");
				return true;
			}
		}
		for (var a = 0; a < enemies.length; a++) {
			var enemy = enemies[a];
			// Skip enemies that haven't entered the viewable area yet
			if (enemy.currentCellY < 4) {
				continue;
			}
			// Skip flying enemies from path check as they can fly over obstacles
			if (enemy.isFlying) {
				continue;
			}
			var target = self.getCell(enemy.cellX, enemy.cellY);
			if (enemy.currentTarget) {
				if (enemy.currentTarget.pathId != pathId) {
					if (!target || target.pathId != pathId) {
						console.warn("Enemy blocked 1 ");
						return true;
					}
				}
			} else if (!target || target.pathId != pathId) {
				console.warn("Enemy blocked 2");
				return true;
			}
		}
		console.log("Speed", new Date().getTime() - before);
	};
	self.renderDebug = function () {
		for (var i = 0; i < gridWidth; i++) {
			for (var j = 0; j < gridHeight; j++) {
				var debugCell = self.cells[i][j].debugCell;
				if (debugCell) {
					debugCell.render(self.cells[i][j]);
				}
			}
		}
	};
	self.updateEnemy = function (enemy) {
		var cell = grid.getCell(enemy.cellX, enemy.cellY);
		if (cell.type == 3) {
			return true;
		}
		if (enemy.isFlying && enemy.shadow) {
			enemy.shadow.x = enemy.x + 20; // Match enemy x-position + offset
			enemy.shadow.y = enemy.y + 20; // Match enemy y-position + offset
			// Match shadow rotation with enemy rotation
			if (enemy.children[0] && enemy.shadow.children[0]) {
				enemy.shadow.children[0].rotation = enemy.children[0].rotation;
			}
		}
		// Check if the enemy has reached the entry area (y position is at least 5)
		var hasReachedEntryArea = enemy.currentCellY >= 4;
		// If enemy hasn't reached the entry area yet, just move down vertically
		if (!hasReachedEntryArea) {
			// Move directly downward
			enemy.currentCellY += enemy.speed;
			// Rotate enemy graphic to face downward (PI/2 radians = 90 degrees)
			var angle = Math.PI / 2;
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update enemy's position
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// If enemy has now reached the entry area, update cell coordinates
			if (enemy.currentCellY >= 4) {
				enemy.cellX = Math.round(enemy.currentCellX);
				enemy.cellY = Math.round(enemy.currentCellY);
			}
			return false;
		}
		// After reaching entry area, handle flying enemies differently
		if (enemy.isFlying) {
			// Flying enemies head straight to the closest goal
			if (!enemy.flyingTarget) {
				// Set flying target to the closest goal
				enemy.flyingTarget = self.goals[0];
				// Find closest goal if there are multiple
				if (self.goals.length > 1) {
					var closestDist = Infinity;
					for (var i = 0; i < self.goals.length; i++) {
						var goal = self.goals[i];
						var dx = goal.x - enemy.cellX;
						var dy = goal.y - enemy.cellY;
						var dist = dx * dx + dy * dy;
						if (dist < closestDist) {
							closestDist = dist;
							enemy.flyingTarget = goal;
						}
					}
				}
			}
			// Move directly toward the goal
			var ox = enemy.flyingTarget.x - enemy.currentCellX;
			var oy = enemy.flyingTarget.y - enemy.currentCellY;
			var dist = Math.sqrt(ox * ox + oy * oy);
			if (dist < enemy.speed) {
				// Reached the goal
				return true;
			}
			var angle = Math.atan2(oy, ox);
			// Rotate enemy graphic to match movement direction
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update the cell position to track where the flying enemy is
			enemy.cellX = Math.round(enemy.currentCellX);
			enemy.cellY = Math.round(enemy.currentCellY);
			enemy.currentCellX += Math.cos(angle) * enemy.speed;
			enemy.currentCellY += Math.sin(angle) * enemy.speed;
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// Update shadow position if this is a flying enemy
			return false;
		}
		// Handle normal pathfinding enemies
		if (!enemy.currentTarget) {
			enemy.currentTarget = cell.targets[0];
		}
		if (enemy.currentTarget) {
			if (cell.score < enemy.currentTarget.score) {
				enemy.currentTarget = cell;
			}
			var ox = enemy.currentTarget.x - enemy.currentCellX;
			var oy = enemy.currentTarget.y - enemy.currentCellY;
			var dist = Math.sqrt(ox * ox + oy * oy);
			if (dist < enemy.speed) {
				enemy.cellX = Math.round(enemy.currentCellX);
				enemy.cellY = Math.round(enemy.currentCellY);
				enemy.currentTarget = undefined;
				return;
			}
			var angle = Math.atan2(oy, ox);
			enemy.currentCellX += Math.cos(angle) * enemy.speed;
			enemy.currentCellY += Math.sin(angle) * enemy.speed;
		}
		enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
		enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
	};
});
var NextWaveButton = Container.expand(function () {
	var self = Container.call(this);
	var buttonBackground = self.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 300;
	buttonBackground.height = 100;
	buttonBackground.tint = 0xffffff;
	var buttonText = new Text2("Next Wave", {
		size: 50,
		fill: 0xff0080,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	self.addChild(buttonText);
	self.enabled = false;
	self.visible = false;
	self.update = function () {
		if (waveIndicator && waveIndicator.gameStarted && currentWave < totalWaves) {
			self.enabled = true;
			self.visible = true;
			buttonBackground.tint = 0x00ffb3;
			self.alpha = 1;
		} else {
			self.enabled = false;
			self.visible = false;
			buttonBackground.tint = 0xffffff;
			self.alpha = 0.7;
		}
	};
	self.down = function () {
		if (!self.enabled) {
			return;
		}
		if (waveIndicator.gameStarted && currentWave < totalWaves) {
			currentWave++; // Increment to the next wave directly
			waveTimer = 0; // Reset wave timer
			waveInProgress = true;
			waveSpawned = false;
			// Get the type of the current wave (which is now the next wave)
			var waveType = waveIndicator.getWaveTypeName(currentWave);
			var enemyCount = waveIndicator.getEnemyCount(currentWave);
			var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) activated!"));
		}
	};
	return self;
});
var Notification = Container.expand(function (message) {
	var self = Container.call(this);
	var notificationGraphics = self.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var isSmallNotification = message === "Cannot build here!";
	// Set fixed size to 1700x600px
	notificationGraphics.width = 1700;
	notificationGraphics.height = 600;
	if (isSmallNotification) {
		notificationGraphics.width = 1100;
		notificationGraphics.height = 300;
	}
	// Parse message to extract wave info for two-line formatting
	var displayMessage = message;
	var isWaveMessage = false;
	var waveInfo = "";
	var waveDetails = "";
	// Check if this is a wave message
	if (message.includes("Wave ") && (message.includes("incoming!") || message.includes("activated!"))) {
		isWaveMessage = true;
		// Extract wave number and type
		var waveMatch = message.match(/Wave (\d+) \(([^)]+)\)/);
		if (waveMatch) {
			var waveNumber = waveMatch[1];
			var waveTypeInfo = waveMatch[2];
			waveInfo = "Wave " + waveNumber;
			waveDetails = waveTypeInfo;
			displayMessage = waveInfo + "\n" + waveDetails;
		}
	}
	var notificationText = new Text2("", {
		size: isWaveMessage ? 90 : 90,
		fill: 0xff0080,
		weight: 800,
		align: 'center'
	});
	notificationText.anchor.set(0.5, 0.5);
	self.addChild(notificationText);
	// Position notification in center of screen
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	self.alpha = 0;
	self.scaleX = 0.3;
	self.scaleY = 0.3;
	// Electronic text animation variables
	var currentCharIndex = 0;
	var displayText = "";
	var electronicTimer = 0;
	var charDelay = 4; // frames between characters for electronic typing effect
	var isAnimatingText = true;
	// Add electronic glitch effect
	var glitchTimer = 0;
	var originalMessage = displayMessage;
	// Entrance animation - scale up and fade in
	tween(self, {
		alpha: 1,
		scaleX: 1.1,
		scaleY: 1.1
	}, {
		duration: 300,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			// Settle to normal size
			tween(self, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 200,
				easing: tween.easeOut
			});
		}
	});
	var fadeOutTime = 240;
	self.update = function () {
		// Electronic text animation
		if (isAnimatingText && electronicTimer % charDelay === 0) {
			if (currentCharIndex < originalMessage.length) {
				displayText += originalMessage[currentCharIndex];
				notificationText.setText(displayText);
				currentCharIndex++;
			} else {
				isAnimatingText = false;
			}
		}
		electronicTimer++;
		// Add subtle glitch effect after text is complete
		if (!isAnimatingText) {
			glitchTimer++;
			if (glitchTimer % 60 === 0) {
				// Glitch every second
				// Briefly change one random character
				if (Math.random() < 0.1) {
					var glitchChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?`~";
					var randomChar = glitchChars[Math.floor(Math.random() * glitchChars.length)];
					var glitchIndex = Math.floor(Math.random() * displayText.length);
					var glitchedText = displayText.substring(0, glitchIndex) + randomChar + displayText.substring(glitchIndex + 1);
					notificationText.setText(glitchedText);
					// Restore original text after 3 frames
					LK.setTimeout(function () {
						notificationText.setText(displayText);
					}, 50);
				}
			}
		}
		if (fadeOutTime > 0) {
			fadeOutTime--;
			if (fadeOutTime <= 60) {
				// Exit animation - scale down and fade out
				if (!self.exitAnimStarted) {
					self.exitAnimStarted = true;
					tween(self, {
						alpha: 0,
						scaleX: 0.8,
						scaleY: 0.8
					}, {
						duration: 300,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							self.destroy();
						}
					});
				}
			}
		} else if (!self.exitAnimStarted) {
			self.destroy();
		}
	};
	return self;
});
var Ship = Container.expand(function (type) {
	var self = Container.call(this);
	self.type = type || 1; // Ship type 1, 2, or 3
	self.speed = 2 + Math.random() * 2; // Random speed between 2-4
	self.direction = Math.random() < 0.5 ? 1 : -1; // 1 for left to right, -1 for right to left
	// Select ship asset based on type
	var shipAsset = 'Ship' + self.type;
	var shipGraphics = self.attachAsset(shipAsset, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Play ship sound based on ship type
	var shipSound = 'Ship' + self.type + 'sound';
	game.playSoundWithVolume(shipSound);
	// Flip ship if moving right to left
	if (self.direction === -1) {
		shipGraphics.scaleX = -1;
	}
	// Calculate game field boundaries
	var gridLeft = 150; // grid.x value
	var gridWidth = 24 * 76; // 24 cells * CELL_SIZE
	var gridRight = gridLeft + gridWidth; // 150 + 1824 = 1974
	// Calculate vertical boundaries based on grid position
	var gridTop = 200 - 76 * 4; // grid.y value (200 - CELL_SIZE * 4)
	var gridHeight = (29 + 6) * 76; // (29 + 6) cells * CELL_SIZE
	var gridBottom = gridTop + gridHeight;
	// Random Y position within the game field boundaries
	self.y = gridTop + Math.random() * gridHeight;
	// Set starting X position based on direction, spawning from field edges
	if (self.direction === 1) {
		// Moving left to right, start from left edge of field
		self.x = gridLeft - shipGraphics.width / 2;
	} else {
		// Moving right to left, start from right edge of field
		self.x = gridRight + shipGraphics.width / 2;
	}
	self.update = function () {
		self.x += self.speed * self.direction;
		// Check if ship has moved off the opposite field edge
		if (self.direction === 1 && self.x > gridRight + shipGraphics.width) {
			self.destroy();
		} else if (self.direction === -1 && self.x < gridLeft - shipGraphics.width) {
			self.destroy();
		}
		// Initialize sound timer if not set
		if (self.soundTimer === undefined) {
			self.soundTimer = 0;
		}
		// Increment sound timer
		self.soundTimer++;
		// Play ship sound every 120 frames (2 seconds at 60 FPS)
		if (self.soundTimer % 120 === 0) {
			var shipSound = 'Ship' + self.type + 'sound';
			game.playSoundWithVolume(shipSound);
		}
	};
	return self;
});
var SourceTower = Container.expand(function (towerType) {
	var self = Container.call(this);
	self.towerType = towerType || 'cannon';
	// Use specific tower asset based on type
	var towerAssetId = 'CannonTower'; // default
	switch (self.towerType) {
		case 'rifle':
			towerAssetId = 'RifleTower';
			break;
		case 'flame':
			towerAssetId = 'FlameTower';
			break;
		case 'Rocket':
			towerAssetId = 'RocketTower';
			break;
		case 'gumbomb':
			towerAssetId = 'GumBombTower';
			break;
		case 'ToxinBomb':
			towerAssetId = 'ToxinBombTower';
			break;
		case 'cannon':
		default:
			towerAssetId = 'CannonTower';
			break;
	}
	// Increase size of base for easier touch
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.3,
		scaleY: 1.3
	});
	// No need to tint as we're using specific tower assets
	var towerCost = getTowerCost(self.towerType);
	// Add shadow for tower type label
	var typeLabelShadow = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	typeLabelShadow.anchor.set(0.5, 0.5);
	typeLabelShadow.x = 4;
	typeLabelShadow.y = -20 + 4;
	self.addChild(typeLabelShadow);
	// Add tower type label
	var displayName = self.towerType === 'rifle' ? 'Rifle' : self.towerType === 'ToxinBomb' ? 'Toxinbomb' : self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1);
	// Set color based on tower type
	var towerColor = 0xFFFFFF; // default white
	switch (self.towerType) {
		case 'cannon':
			towerColor = 0xff0080;
			break;
		case 'rifle':
			towerColor = 0xff0080;
			break;
		case 'flame':
			towerColor = 0xff0080;
			break;
		case 'Rocket':
			towerColor = 0xff0080;
			break;
		case 'gumbomb':
			towerColor = 0xff0080;
			break;
		case 'ToxinBomb':
			towerColor = 0xff0080;
			break;
	}
	var typeLabel = new Text2(displayName, {
		size: 50,
		fill: towerColor,
		weight: 800
	});
	typeLabel.anchor.set(0.5, 0.5);
	typeLabel.y = -20; // Position above center of tower
	self.addChild(typeLabel);
	// Add cost shadow
	var costLabelShadow = new Text2(towerCost, {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	costLabelShadow.anchor.set(0.5, 0.5);
	costLabelShadow.x = 4;
	costLabelShadow.y = 24 + 12;
	self.addChild(costLabelShadow);
	// Add cost label
	var costLabel = new Text2(towerCost, {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	costLabel.anchor.set(0.5, 0.5);
	costLabel.y = 20 + 12;
	self.addChild(costLabel);
	self.update = function () {
		// Check if player can afford this tower
		var canAfford = crystals >= getTowerCost(self.towerType);
		// Set opacity based on affordability
		self.alpha = canAfford ? 1 : 0.5;
	};
	return self;
});
var SpeakingGirl = Container.expand(function () {
	var self = Container.call(this);
	var girlAsset1 = self.attachAsset('Girl1', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 500,
		height: 500
	});
	var girlAsset2 = self.attachAsset('Girl2', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 500,
		height: 500
	});
	var girlAsset3 = self.attachAsset('Girl3', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 500,
		height: 500
	});
	var allGirlAssets = [girlAsset1, girlAsset2, girlAsset3];
	// Girl1 is index 0, Girl2 is 1, Girl3 is 2
	var animationSequence = [0, 1, 0, 2];
	var currentFrameIndexInSequence = 0;
	var animationInterval = null;
	var hasStartedAnimation = false;
	function setFrame(assetIndex) {
		for (var i = 0; i < allGirlAssets.length; i++) {
			allGirlAssets[i].visible = i === assetIndex;
		}
	}
	function animate() {
		currentFrameIndexInSequence = (currentFrameIndexInSequence + 1) % animationSequence.length;
		var assetIndexToShow = animationSequence[currentFrameIndexInSequence];
		setFrame(assetIndexToShow);
	}
	function startSpeakingAnimation() {
		if (!hasStartedAnimation) {
			hasStartedAnimation = true;
			animationInterval = LK.setInterval(animate, 300);
			for (var i = 0; i < game.children.length; i++) {
				if (game.children[i] instanceof Tablet) {
					game.children[i].startAnimation();
					break;
				}
			}
		}
	}
	// Start at right edge of screen, move to left side
	self.x = 2048 - 250; // Start from right edge (250 = half of 500px width)
	self.y = 2732 - 250; // 250 = half of 500px height, so bottom edge inside
	setFrame(0); // Start with Girl1
	// Move from right to left side
	tween(self, {
		x: 0 + 250 // Move to left edge inside screen
	}, {
		duration: 2000,
		// 2 second movement
		easing: tween.easeOut,
		onFinish: function onFinish() {
			// Start animation when reaching left side
			startSpeakingAnimation();
		}
	});
	var originalDestroy = self.destroy;
	self.destroy = function () {
		if (animationInterval) {
			LK.clearInterval(animationInterval);
		}
		tween.stop(self);
		originalDestroy.call(self);
	};
	return self;
});
var Tablet = Container.expand(function () {
	var self = Container.call(this);
	var tabletGraphics = self.attachAsset('Tablet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Position tablet in center of screen
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	// Message to display with electronic character animation - formatted with more lines
	var message = "Hi! I'm the high commander:\n\nWe shall begin a war with\nthe enemies, nothing will\nstand in our ways,\n\nwe will destroy them and\nwe prove our supremacy,\n\nwe will not rest until\nvictory is ours!";
	// Create text with 100px spacing from sides
	var messageText = new Text2("", {
		size: 80,
		fill: 0xff0080,
		weight: 800
	});
	messageText.anchor.set(0.5, 0.5);
	self.addChild(messageText);
	// Animation variables
	var currentChar = 0;
	var displayText = "";
	var animationTimer = 0;
	var charDelay = 3; // Frames between characters (electronic typing effect)
	var isAnimating = false;
	self.startAnimation = function () {
		isAnimating = true;
	};
	self.update = function () {
		if (isAnimating && animationTimer % charDelay === 0) {
			if (currentChar < message.length) {
				displayText += message[currentChar];
				messageText.setText(displayText);
				currentChar++;
			} else {
				isAnimating = false;
				// Auto-destroy after message is complete and a short delay
				tween(self, {
					alpha: 0
				}, {
					duration: 1000,
					delay: 3000,
					// Wait 3 seconds after text is complete
					easing: tween.easeOut,
					onFinish: function onFinish() {
						// Remove girl character when tablet is destroyed
						if (girlCharacter && girlCharacter.parent) {
							girlCharacter.destroy();
							girlCharacter = null;
						}
						self.destroy();
						// Show game started notification
						var notification = game.addChild(new Notification("Game started!\nPrepare for battle!"));
						var originalDestroy = notification.destroy;
						notification.destroy = function () {
							canStartWaves = true;
							canPlaceTowers = true;
							originalDestroy.call(this);
						};
					}
				});
			}
		}
		animationTimer++;
	};
	return self;
});
var Tower = Container.expand(function (id) {
	var self = Container.call(this);
	self.id = id || 'cannon';
	self.level = 1;
	self.maxLevel = 6;
	self.gridX = 0;
	self.gridY = 0;
	self.range = 3 * CELL_SIZE;
	// Standardized method to get the current range of the tower
	self.getRange = function () {
		// Always calculate range based on tower type and level
		switch (self.id) {
			case 'flame':
				// Flame: base 5, +0.8 per level, but final upgrade gets a huge boost
				if (self.level === self.maxLevel) {
					return 12 * CELL_SIZE; // Significantly increased range for max level
				}
				return (5 + (self.level - 1) * 0.8) * CELL_SIZE;
			case 'Rocket':
				// Rocket: base range higher than sniper, +0.8 per level
				if (self.level === self.maxLevel) {
					return 14 * CELL_SIZE; // Higher than sniper's max range
				}
				return (6 + (self.level - 1) * 0.8) * CELL_SIZE;
			case 'rifle':
				// Rifle: base 3 (default), +0.5 per level
				return (3 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'gumbomb':
				// GumBomb: base 3.5, +0.5 per level
				return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'ToxinBomb':
				// ToxinBomb: base 3.2, +0.5 per level
				return (3.2 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'cannon':
				// Cannon: base 3, +0.5 per level
				return (3 + (self.level - 1) * 0.5) * CELL_SIZE;
				break;
			default:
				// Default: base 3, +0.5 per level
				return (3 + (self.level - 1) * 0.5) * CELL_SIZE;
		}
	};
	self.cellsInRange = [];
	self.fireRate = 60;
	self.bulletSpeed = 5;
	self.damage = 7;
	self.lastFired = 0;
	self.targetEnemy = null;
	self.flameEffect = null; // Track active flame effect for flame tower
	self.flameAnimation = null; // Track flame animation visual
	switch (self.id) {
		case 'rifle':
			self.fireRate = Math.floor(60 / 3.5); // 3.5 shots per second = 60/3.5 = 17 frames
			self.damage = 5;
			self.range = 3 * CELL_SIZE; // Default tower range
			self.bulletSpeed = 7;
			break;
		case 'flame':
			self.fireRate = 120; // 0.5 shots per second
			self.damage = 9;
			self.range = 5 * CELL_SIZE;
			self.bulletSpeed = 25;
			break;
		case 'Rocket':
			self.fireRate = Math.floor(60 / 1.0); // 1.0 shots per second = 60 frames
			self.damage = 13;
			self.range = 2 * CELL_SIZE;
			self.bulletSpeed = 8;
			break;
		case 'gumbomb':
			self.fireRate = 50;
			self.damage = 3;
			self.range = 3.5 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
		case 'ToxinBomb':
			self.fireRate = 70;
			self.damage = 18;
			self.range = 3.2 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
	}
	// Use specific tower asset based on type
	var towerAssetId = 'CannonTower'; // default
	switch (self.id) {
		case 'rifle':
			towerAssetId = 'RifleTower';
			break;
		case 'flame':
			towerAssetId = 'FlameTower';
			break;
		case 'Rocket':
			towerAssetId = 'RocketTower';
			break;
		case 'gumbomb':
			towerAssetId = 'GumBombTower';
			break;
		case 'ToxinBomb':
			towerAssetId = 'ToxinBombTower';
			break;
		case 'cannon':
		default:
			towerAssetId = 'CannonTower';
			break;
	}
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No need to tint as we're using specific tower assets
	var levelIndicators = [];
	var maxDots = self.maxLevel;
	var dotSpacing = baseGraphics.width / (maxDots + 1);
	var dotSize = 30;
	for (var i = 0; i < maxDots; i++) {
		var dot = new Container();
		var outlineCircle = dot.attachAsset('towerLevelIndicator', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		outlineCircle.width = dotSize + 4;
		outlineCircle.height = dotSize + 4;
		outlineCircle.tint = 0x000000;
		var towerLevelIndicator = dot.attachAsset('towerLevelIndicator', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		towerLevelIndicator.width = dotSize;
		towerLevelIndicator.height = dotSize;
		towerLevelIndicator.tint = 0xCCCCCC;
		dot.x = dotSpacing * (i + 1) - baseGraphics.width / 2;
		dot.y = -CELL_SIZE * 1.2;
		self.addChild(dot);
		levelIndicators.push(dot);
	}
	var gunContainer = new Container();
	self.addChild(gunContainer);
	var weaponAssetId = 'Weapon1'; // default
	switch (self.id) {
		case 'rifle':
			weaponAssetId = 'Weapon2';
			break;
		case 'flame':
			weaponAssetId = 'Weapon3';
			break;
		case 'Rocket':
			weaponAssetId = 'Weapon4';
			break;
		case 'gumbomb':
			weaponAssetId = 'Weapon5';
			break;
		case 'ToxinBomb':
			weaponAssetId = 'Weapon6';
			break;
		case 'cannon':
		default:
			weaponAssetId = 'Weapon1';
			break;
	}
	var gunGraphics = gunContainer.attachAsset(weaponAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.updateLevelIndicators = function () {
		for (var i = 0; i < maxDots; i++) {
			var dot = levelIndicators[i];
			var towerLevelIndicator = dot.children[1];
			if (i < self.level) {
				towerLevelIndicator.tint = 0xff0080;
			} else {
				switch (self.id) {
					case 'rifle':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'flame':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'Rocket':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'gumbomb':
						towerLevelIndicator.tint = 0xffffff;
						break;
					case 'ToxinBomb':
						towerLevelIndicator.tint = 0xffffff;
						break;
					default:
						towerLevelIndicator.tint = 0xffffff;
				}
			}
		}
	};
	self.updateLevelIndicators();
	self.refreshCellsInRange = function () {
		for (var i = 0; i < self.cellsInRange.length; i++) {
			var cell = self.cellsInRange[i];
			var towerIndex = cell.towersInRange.indexOf(self);
			if (towerIndex !== -1) {
				cell.towersInRange.splice(towerIndex, 1);
			}
		}
		self.cellsInRange = [];
		var rangeRadius = self.getRange() / CELL_SIZE;
		var centerX = self.gridX + 1;
		var centerY = self.gridY + 1;
		var minI = Math.floor(centerX - rangeRadius - 0.5);
		var maxI = Math.ceil(centerX + rangeRadius + 0.5);
		var minJ = Math.floor(centerY - rangeRadius - 0.5);
		var maxJ = Math.ceil(centerY + rangeRadius + 0.5);
		for (var i = minI; i <= maxI; i++) {
			for (var j = minJ; j <= maxJ; j++) {
				var closestX = Math.max(i, Math.min(centerX, i + 1));
				var closestY = Math.max(j, Math.min(centerY, j + 1));
				var deltaX = closestX - centerX;
				var deltaY = closestY - centerY;
				var distanceSquared = deltaX * deltaX + deltaY * deltaY;
				if (distanceSquared <= rangeRadius * rangeRadius) {
					var cell = grid.getCell(i, j);
					if (cell) {
						self.cellsInRange.push(cell);
						cell.towersInRange.push(self);
					}
				}
			}
		}
		grid.renderDebug();
	};
	self.getTotalValue = function () {
		var baseTowerCost = getTowerCost(self.id);
		var totalInvestment = baseTowerCost;
		var baseUpgradeCost = baseTowerCost; // Upgrade cost now scales with base tower cost
		for (var i = 1; i < self.level; i++) {
			totalInvestment += Math.floor(baseUpgradeCost * Math.pow(2, i - 1));
		}
		return totalInvestment;
	};
	self.upgrade = function () {
		if (self.level < self.maxLevel) {
			// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
			var baseUpgradeCost = getTowerCost(self.id);
			var upgradeCost;
			// Make last upgrade level extra expensive
			if (self.level === self.maxLevel - 1) {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.level - 1) * 3.5 / 2); // Half the cost for final upgrade
			} else {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.level - 1));
			}
			if (crystals >= upgradeCost) {
				setCrystals(crystals - upgradeCost);
				self.level++;
				// No need to update self.range here; getRange() is now the source of truth
				// Apply tower-specific upgrades based on type
				if (self.id === 'rifle') {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade (double the effect)
						self.fireRate = Math.max(4, 12 - self.level * 3); // double the effect, starting from 12
						self.damage = 8 + self.level * 8; // double the effect, starting from 8
						self.bulletSpeed = 7 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(6, 12 - self.level * 1); // Rifle gets faster with upgrades, starting from 12
						self.damage = 8 + self.level * 2; // Starting from 8 damage
						self.bulletSpeed = 7 + self.level * 0.7;
					}
				} else {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade for all other towers (double the effect)
						self.fireRate = Math.max(5, 60 - self.level * 24); // double the effect
						self.damage = 10 + self.level * 20; // double the effect
						self.bulletSpeed = 5 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(20, 60 - self.level * 8);
						self.damage = 10 + self.level * 5;
						self.bulletSpeed = 5 + self.level * 0.5;
					}
				}
				self.refreshCellsInRange();
				self.updateLevelIndicators();
				if (self.level > 1) {
					var levelDot = levelIndicators[self.level - 1].children[1];
					tween(levelDot, {
						scaleX: 1.5,
						scaleY: 1.5
					}, {
						duration: 300,
						easing: tween.elasticOut,
						onFinish: function onFinish() {
							tween(levelDot, {
								scaleX: 1,
								scaleY: 1
							}, {
								duration: 200,
								easing: tween.easeOut
							});
						}
					});
				}
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough crystals to upgrade!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.findTarget = function () {
		var closestEnemy = null;
		var closestScore = Infinity;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			// Check if enemy is in range
			if (distance <= self.getRange()) {
				// Handle flying enemies differently - they can be targeted regardless of path
				if (enemy.isFlying) {
					// For flying enemies, prioritize by distance to the goal
					if (enemy.flyingTarget) {
						var goalX = enemy.flyingTarget.x;
						var goalY = enemy.flyingTarget.y;
						var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY));
						// Use distance to goal as score
						if (distToGoal < closestScore) {
							closestScore = distToGoal;
							closestEnemy = enemy;
						}
					} else {
						// If no flying target yet (shouldn't happen), prioritize by distance to tower
						if (distance < closestScore) {
							closestScore = distance;
							closestEnemy = enemy;
						}
					}
				} else {
					// For ground enemies, use the original path-based targeting
					// Get the cell for this enemy
					var cell = grid.getCell(enemy.cellX, enemy.cellY);
					if (cell && cell.pathId === pathId) {
						// Use the cell's score (distance to exit) for prioritization
						// Lower score means closer to exit
						if (cell.score < closestScore) {
							closestScore = cell.score;
							closestEnemy = enemy;
						}
					}
				}
			}
		}
		if (!closestEnemy) {
			self.targetEnemy = null;
		}
		return closestEnemy;
	};
	self.update = function () {
		// Handle tower boost effect
		if (self.boosted) {
			self.boostDuration--;
			if (self.boostDuration <= 0) {
				self.boosted = false;
				self.damage = self.originalDamage;
			}
		}
		self.targetEnemy = self.findTarget();
		if (!self.targetEnemy) {
			if (self.flameAnimation) {
				self.flameAnimation.destroy();
				self.flameAnimation = null;
			}
			if (self.flameEffect) {
				self.flameEffect.destroy();
				self.flameEffect = null;
			}
		}
		if (self.targetEnemy) {
			var dx = self.targetEnemy.x - self.x;
			var dy = self.targetEnemy.y - self.y;
			var angle = Math.atan2(dy, dx);
			// Smooth gun rotation using tween
			if (gunContainer.targetRotation === undefined) {
				gunContainer.targetRotation = angle;
				gunContainer.rotation = angle;
			} else {
				if (Math.abs(angle - gunContainer.targetRotation) > 0.05) {
					tween.stop(gunContainer, {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = gunContainer.rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					gunContainer.targetRotation = angle;
					tween(gunContainer, {
						rotation: currentRotation + angleDiff
					}, {
						duration: 200,
						easing: tween.easeOut
					});
				}
			}
			// Flame tower has special continuous firing logic
			if (self.id === 'flame') {
				// Continuously apply damage if an enemy is targeted
				if (self.targetEnemy && self.isInRange(self.targetEnemy)) {
					// Apply damage every frame while the enemy is in range and alive
					if (self.targetEnemy.health > 0) {
						var actualDamage = self.damage / 60; // Damage per second (damage/60 FPS)
						if (self.targetEnemy.damageResistance) {
							actualDamage = actualDamage * self.targetEnemy.damageResistance;
						}
						self.targetEnemy.health -= actualDamage;
						// Ensure health doesn't go below zero
						if (self.targetEnemy.health <= 0) {
							self.targetEnemy.health = 0;
						} else {
							// Update enemy health bar using stored original width
							var healthPercentage = self.targetEnemy.health / self.targetEnemy.maxHealth;
							self.targetEnemy.healthBar.width = self.targetEnemy.healthBarOriginalWidth * healthPercentage;
						}
						// --- Flame Visuals ---
						var dx = self.targetEnemy.x - self.x;
						var dy = self.targetEnemy.y - self.y;
						var distance = Math.sqrt(dx * dx + dy * dy);
						// Create flame animation from the gun if not already active
						if (!self.flameAnimation) {
							self.flameAnimation = new Container();
							var flameGraphics = self.flameAnimation.attachAsset('Flame', {
								anchorX: 0,
								// Anchor at the base (left) of the flame
								anchorY: 0.5 // Anchor in the middle vertically
							});
							// The Flame asset needs no rotation as it should extend horizontally from the gun
							flameGraphics.rotation = 0;
							flameGraphics.tint = 0xFF8800;
							gunContainer.addChild(self.flameAnimation);
							// Position at the front edge of the gun barrel
							self.flameAnimation.x = gunGraphics.width / 2 + 20;
							// Set initial scale for appear animation
							flameGraphics.scale.set(0, 0.6);
							// Initialize flame sound timer
							self.flameSoundTimer = 0;
						}
						// Play flame sound repeatedly while burning
						if (!self.flameSoundTimer) {
							self.flameSoundTimer = 0;
						}
						self.flameSoundTimer++;
						// Play flame sound every 30 frames (0.5 seconds at 60 FPS) while actively burning
						if (self.flameSoundTimer % 30 === 0) {
							game.playSoundWithVolume('Flamesound');
						}
						// Update the flame animation every frame to stretch and flicker
						if (self.flameAnimation && self.flameAnimation.children[0]) {
							var flameGraphics = self.flameAnimation.children[0];
							// The flame asset is 300px long (originally height)
							var flameAssetLength = 300;
							var targetScaleX = distance / flameAssetLength;
							// Animate the flame length
							flameGraphics.scale.x += (targetScaleX - flameGraphics.scale.x) * 0.3;
							// Use a sinusoidal flicker for a more natural look on the width
							var flicker = Math.sin(LK.ticks * 0.5) * 0.1;
							flameGraphics.scale.y = 0.6 + flicker;
						}
						// Show visual effect on the enemy
						if (!self.flameEffect) {
							self.flameEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'flame');
							game.addChild(self.flameEffect);
						}
						// Update the position of the flame effect to match the target enemy
						self.flameEffect.x = self.targetEnemy.x;
						self.flameEffect.y = self.targetEnemy.y;
					} else {
						// Target is dead, destroy flame animation and effect
						if (self.flameAnimation) {
							self.flameAnimation.destroy();
							self.flameAnimation = null;
						}
						if (self.flameEffect) {
							self.flameEffect.destroy();
							self.flameEffect = null;
						}
					}
				} else {
					// No target enemy in range, destroy flame animation and effect
					if (self.flameAnimation) {
						self.flameAnimation.destroy();
						self.flameAnimation = null;
					}
					if (self.flameEffect) {
						self.flameEffect.destroy();
						self.flameEffect = null;
					}
				}
			} else {
				// Standard tower firing logic (single bullets)
				if (self.id === 'flame') {
					// Manage flame visibility based on fire rate cooldown
					var flameGraphics = self.flameAnimation ? self.flameAnimation.children[0] : null;
					if (flameGraphics) {
						if (LK.ticks - self.lastFired >= self.fireRate * 0.6) {
							// Show flame for 60% of fire rate
							flameGraphics.visible = true;
						} else {
							flameGraphics.visible = false;
						}
					}
					if (LK.ticks - self.lastFired >= self.fireRate) {
						self.fire();
						self.lastFired = LK.ticks;
					}
				} else {
					if (LK.ticks - self.lastFired >= self.fireRate) {
						self.fire();
						self.lastFired = LK.ticks;
					}
				}
			}
		}
	};
	self.down = function (x, y, obj) {
		var existingMenus = game.children.filter(function (child) {
			return child instanceof UpgradeMenu;
		});
		var hasOwnMenu = false;
		var rangeCircle = null;
		for (var i = 0; i < game.children.length; i++) {
			if (game.children[i].isTowerRange && game.children[i].tower === self) {
				rangeCircle = game.children[i];
				break;
			}
		}
		for (var i = 0; i < existingMenus.length; i++) {
			if (existingMenus[i].tower === self) {
				hasOwnMenu = true;
				break;
			}
		}
		if (hasOwnMenu) {
			for (var i = 0; i < existingMenus.length; i++) {
				if (existingMenus[i].tower === self) {
					hideUpgradeMenu(existingMenus[i]);
				}
			}
			if (rangeCircle) {
				game.removeChild(rangeCircle);
			}
			selectedTower = null;
			grid.renderDebug();
			return;
		}
		for (var i = 0; i < existingMenus.length; i++) {
			existingMenus[i].destroy();
		}
		for (var i = game.children.length - 1; i >= 0; i--) {
			if (game.children[i].isTowerRange) {
				game.removeChild(game.children[i]);
			}
		}
		selectedTower = self;
		var rangeIndicator = new Container();
		rangeIndicator.isTowerRange = true;
		rangeIndicator.tower = self;
		game.addChild(rangeIndicator);
		rangeIndicator.x = self.x;
		rangeIndicator.y = self.y;
		var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		rangeGraphics.width = rangeGraphics.height = self.getRange() * 2;
		rangeGraphics.alpha = 0.3;
		var upgradeMenu = new UpgradeMenu(self);
		game.addChild(upgradeMenu);
		upgradeMenu.x = 2048 / 2;
		// Center the menu on screen using asset height
		tween(upgradeMenu, {
			y: 2732 / 2
		}, {
			duration: 200,
			easing: tween.backOut
		});
		grid.renderDebug();
	};
	self.isInRange = function (enemy) {
		if (!enemy) {
			return false;
		}
		var dx = enemy.x - self.x;
		var dy = enemy.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		return distance <= self.getRange();
	};
	self.fire = function () {
		if (self.targetEnemy) {
			var potentialDamage = 0;
			for (var i = 0; i < self.targetEnemy.bulletsTargetingThis.length; i++) {
				potentialDamage += self.targetEnemy.bulletsTargetingThis[i].damage;
			}
			if (self.targetEnemy.health > potentialDamage) {
				var bulletX = self.x + Math.cos(gunContainer.rotation) * 40;
				var bulletY = self.y + Math.sin(gunContainer.rotation) * 40;
				var bullet = new Bullet(bulletX, bulletY, self.targetEnemy, self.damage, self.bulletSpeed);
				// Set bullet type based on tower type
				bullet.type = self.id;
				// Store reference to source tower for range checking (all tower types)
				bullet.sourceTower = self;
				// For Rocket towers, use Rocket asset
				if (self.id === 'Rocket') {
					// Replace bullet asset with Rocket asset
					bullet.removeChild(bullet.children[0]);
					var rocketGraphics = bullet.attachAsset('Rocket', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					rocketGraphics.tint = 0xff0000;
					rocketGraphics.width = 80;
					rocketGraphics.height = 70;
				}
				// For gumbomb tower, pass level for scaling gum effect
				if (self.id === 'gumbomb') {
					bullet.sourceTowerLevel = self.level;
				}
				// Customize bullet appearance based on tower type
				switch (self.id) {
					case 'rifle':
						// Replace bullet asset with RifleBullet asset
						bullet.removeChild(bullet.children[0]);
						var rifleGraphics = bullet.attachAsset('RifleBullet', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						rifleGraphics.tint = 0xffd900;
						rifleGraphics.width = 5;
						rifleGraphics.height = 10;
						break;
					// Remove flame bullet type creation as flame tower now applies continuous damage
					case 'Rocket':
						// Rocket bullets now use Rocket asset, styling already applied above
						break;
					case 'gumbomb':
						// Replace bullet asset with GumBomb asset
						bullet.removeChild(bullet.children[0]);
						var gumbombGraphics = bullet.attachAsset('gumbomb', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						gumbombGraphics.tint = 0xff0080;
						gumbombGraphics.width = 35;
						gumbombGraphics.height = 35;
						break;
					case 'ToxinBomb':
						// Replace bullet asset with ToxinBomb asset
						bullet.removeChild(bullet.children[0]);
						var toxinGraphics = bullet.attachAsset('ToxinBomb', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						toxinGraphics.tint = 0x01df01;
						toxinGraphics.width = 35;
						toxinGraphics.height = 35;
						break;
				}
				game.addChild(bullet);
				bullets.push(bullet);
				self.targetEnemy.bulletsTargetingThis.push(bullet);
				// Play sound for tower shots
				switch (self.id) {
					case 'cannon':
						game.playSoundWithVolume('Bulletsound');
						break;
					case 'rifle':
						game.playSoundWithVolume('Riflebulletsound');
						break;
					case 'Rocket':
						game.playSoundWithVolume('Rocketsound');
						break;
					case 'gumbomb':
						game.playSoundWithVolume('Gumbombsound');
						break;
					case 'ToxinBomb':
						game.playSoundWithVolume('Toxinbombsound');
						break;
				}
				// --- Fire recoil effect for gunContainer ---
				// Stop any ongoing recoil tweens before starting a new one
				tween.stop(gunContainer, {
					x: true,
					y: true,
					scaleX: true,
					scaleY: true
				});
				// Always use the original resting position for recoil, never accumulate offset
				if (gunContainer._restX === undefined) {
					gunContainer._restX = 0;
				}
				if (gunContainer._restY === undefined) {
					gunContainer._restY = 0;
				}
				if (gunContainer._restScaleX === undefined) {
					gunContainer._restScaleX = 1;
				}
				if (gunContainer._restScaleY === undefined) {
					gunContainer._restScaleY = 1;
				}
				// Reset to resting position before animating (in case of interrupted tweens)
				gunContainer.x = gunContainer._restX;
				gunContainer.y = gunContainer._restY;
				gunContainer.scaleX = gunContainer._restScaleX;
				gunContainer.scaleY = gunContainer._restScaleY;
				// Calculate recoil offset (recoil back along the gun's rotation)
				var recoilDistance = 8;
				var recoilX = -Math.cos(gunContainer.rotation) * recoilDistance;
				var recoilY = -Math.sin(gunContainer.rotation) * recoilDistance;
				// Animate recoil back from the resting position
				tween(gunContainer, {
					x: gunContainer._restX + recoilX,
					y: gunContainer._restY + recoilY
				}, {
					duration: 60,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						// Animate return to original position/scale
						tween(gunContainer, {
							x: gunContainer._restX,
							y: gunContainer._restY
						}, {
							duration: 90,
							easing: tween.cubicIn
						});
					}
				});
			}
		}
	};
	self.placeOnGrid = function (gridX, gridY) {
		self.gridX = gridX;
		self.gridY = gridY;
		self.x = grid.x + gridX * CELL_SIZE + CELL_SIZE / 2;
		self.y = grid.y + gridY * CELL_SIZE + CELL_SIZE / 2;
		for (var i = 0; i < 2; i++) {
			for (var j = 0; j < 2; j++) {
				var cell = grid.getCell(gridX + i, gridY + j);
				if (cell) {
					cell.type = 1;
				}
			}
		}
		self.refreshCellsInRange();
		// Play placement sound for cannon tower
		if (self.id === 'cannon') {
			game.playSoundWithVolume('placmentsound1');
		} else if (self.id === 'rifle') {
			game.playSoundWithVolume('placmentsound2');
		} else if (self.id === 'flame') {
			game.playSoundWithVolume('placmentsound3');
		} else if (self.id === 'Rocket') {
			game.playSoundWithVolume('placmentsound4');
		} else if (self.id === 'gumbomb') {
			game.playSoundWithVolume('placmentsound5');
		} else if (self.id === 'ToxinBomb') {
			game.playSoundWithVolume('placmentsound6');
		}
	};
	return self;
});
var TowerPreview = Container.expand(function () {
	var self = Container.call(this);
	var towerRange = 3;
	var rangeInPixels = towerRange * CELL_SIZE;
	self.towerType = 'cannon';
	self.hasEnoughGold = true;
	var rangeIndicator = new Container();
	self.addChild(rangeIndicator);
	var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	rangeGraphics.alpha = 0.3;
	var previewGraphics = self.attachAsset('towerpreview', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	previewGraphics.width = CELL_SIZE * 2;
	previewGraphics.height = CELL_SIZE * 2;
	self.canPlace = false;
	self.gridX = 0;
	self.gridY = 0;
	self.blockedByEnemy = false;
	self.update = function () {
		var previousHasEnoughGold = self.hasEnoughGold;
		self.hasEnoughGold = crystals >= getTowerCost(self.towerType);
		// Only update appearance if the affordability status has changed
		if (previousHasEnoughGold !== self.hasEnoughGold) {
			self.updateAppearance();
		}
	};
	self.updateAppearance = function () {
		// Use Tower class to get the source of truth for range
		var tempTower = new Tower(self.towerType);
		var previewRange = tempTower.getRange();
		// Clean up tempTower to avoid memory leaks
		if (tempTower && tempTower.destroy) {
			tempTower.destroy();
		}
		// Set range indicator using unified range logic
		rangeGraphics.width = rangeGraphics.height = previewRange * 2;
		switch (self.towerType) {
			case 'rifle':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'flame':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'Rocket':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'gumbomb':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'ToxinBomb':
				previewGraphics.tint = 0xFFFFFF;
				break;
			case 'cannon':
				previewGraphics.tint = 0xFFFFFF;
				break;
			default:
				previewGraphics.tint = 0xFFFFFF;
		}
		if (!self.canPlace || !self.hasEnoughGold) {
			previewGraphics.tint = 0xffffff;
		}
	};
	self.updatePlacementStatus = function () {
		var validGridPlacement = true;
		if (self.gridY <= 4 || self.gridY + 1 >= grid.cells[0].length - 4) {
			validGridPlacement = false;
		} else {
			for (var i = 0; i < 2; i++) {
				for (var j = 0; j < 2; j++) {
					var cell = grid.getCell(self.gridX + i, self.gridY + j);
					if (!cell || cell.type !== 0) {
						validGridPlacement = false;
						break;
					}
				}
				if (!validGridPlacement) {
					break;
				}
			}
		}
		self.blockedByEnemy = false;
		if (validGridPlacement) {
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				if (enemy.currentCellY < 4) {
					continue;
				}
				// Only check non-flying enemies, flying enemies can pass over towers
				if (!enemy.isFlying) {
					if (enemy.cellX >= self.gridX && enemy.cellX < self.gridX + 2 && enemy.cellY >= self.gridY && enemy.cellY < self.gridY + 2) {
						self.blockedByEnemy = true;
						break;
					}
					if (enemy.currentTarget) {
						var targetX = enemy.currentTarget.x;
						var targetY = enemy.currentTarget.y;
						if (targetX >= self.gridX && targetX < self.gridX + 2 && targetY >= self.gridY && targetY < self.gridY + 2) {
							self.blockedByEnemy = true;
							break;
						}
					}
				}
			}
		}
		self.canPlace = validGridPlacement && !self.blockedByEnemy;
		self.hasEnoughGold = crystals >= getTowerCost(self.towerType);
		self.updateAppearance();
	};
	self.checkPlacement = function () {
		self.updatePlacementStatus();
	};
	self.snapToGrid = function (x, y) {
		var gridPosX = x - grid.x;
		var gridPosY = y - grid.y;
		self.gridX = Math.floor(gridPosX / CELL_SIZE);
		self.gridY = Math.floor(gridPosY / CELL_SIZE);
		self.x = grid.x + self.gridX * CELL_SIZE + CELL_SIZE / 2;
		self.y = grid.y + self.gridY * CELL_SIZE + CELL_SIZE / 2;
		self.checkPlacement();
	};
	return self;
});
var UpgradeMenu = Container.expand(function (tower) {
	var self = Container.call(this);
	self.tower = tower;
	var menuBackground = self.attachAsset('Notification2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Use asset dimensions instead of hardcoded values
	menuBackground.tint = 0xffffff;
	menuBackground.alpha = 0.9;
	// Set starting position offscreen using actual asset height
	self.y = 2732 + menuBackground.height / 2;
	// Define all elements
	var displayName = self.tower.id === 'rifle' ? 'Rifle' : self.tower.id === 'ToxinBomb' ? 'Toxinbomb' : self.tower.id.charAt(0).toUpperCase() + self.tower.id.slice(1);
	var fullTowerName = displayName + ' Tower';
	var towerTypeText = new Text2('', {
		size: 80,
		fill: 0xff0080,
		weight: 800
	});
	var currentNameText = '';
	var fullStatsText = 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s';
	var statsText = new Text2('', {
		size: 70,
		fill: 0xff0080,
		weight: 400
	});
	var currentStatsText = '';
	// Animation variables
	var nameAnimation = {
		text: fullTowerName,
		index: 0,
		timer: 0
	};
	var statsAnimation = {
		text: fullStatsText,
		index: 0,
		timer: 0
	};
	var animationPhase = 'name'; // name, stats, hold
	var holdTimer = 0;
	var holdDuration = 120; // 2 seconds
	var animationDelay = 2; // frames
	var upgradeButton = new Container();
	var buttonBackground = upgradeButton.attachAsset('Upgradebutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var isMaxLevel = self.tower.level >= self.tower.maxLevel;
	// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
	var baseUpgradeCost = getTowerCost(self.tower.id);
	var upgradeCost;
	if (isMaxLevel) {
		upgradeCost = 0;
	} else if (self.tower.level === self.tower.maxLevel - 1) {
		upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
	} else {
		upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1));
	}
	buttonBackground.tint = isMaxLevel ? 0x888888 : crystals >= upgradeCost ? 0x00ff00 : 0xff0000;
	var buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' crystal', {
		size: 60,
		fill: 0xff0080,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	var sellButton = new Container();
	var sellButtonBackground = sellButton.attachAsset('Sellbutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	sellButtonBackground.tint = 0xffffff;
	var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
	var sellValue = getTowerSellValue(totalInvestment);
	var sellButtonText = new Text2('Sell: +' + sellValue + ' crystal', {
		size: 60,
		fill: 0xff0080,
		weight: 800
	});
	sellButtonText.anchor.set(0.5, 0.5);
	sellButton.addChild(sellButtonText);
	var closeButton = new Container();
	var closeBackground = closeButton.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBackground.width = 90;
	closeBackground.height = 90;
	closeBackground.tint = 0x00ffb3;
	var closeText = new Text2('X', {
		size: 68,
		fill: 0xff0080,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	// Add all elements to self
	self.addChild(statsText);
	self.addChild(towerTypeText);
	self.addChild(upgradeButton);
	self.addChild(sellButton);
	self.addChild(closeButton);
	// Position all elements
	// Tower info
	towerTypeText.anchor.set(0.5, 0.5);
	towerTypeText.x = 0;
	towerTypeText.y = -175;
	statsText.anchor.set(0.5, 0.5);
	statsText.x = 0;
	statsText.y = 10;
	// Buttons
	var buttonYPos = menuBackground.height / 2 - 100 - buttonBackground.height / 2;
	upgradeButton.y = buttonYPos;
	sellButton.y = buttonYPos;
	var buttonSpacing = 20;
	sellButton.x = -sellButtonBackground.width / 2 - buttonSpacing;
	upgradeButton.x = buttonBackground.width / 2 + buttonSpacing;
	// Close button
	closeButton.x = menuBackground.width / 2 - 100;
	closeButton.y = -menuBackground.height / 2 + 250;
	upgradeButton.down = function (x, y, obj) {
		if (self.tower.level >= self.tower.maxLevel) {
			var notification = game.addChild(new Notification("Tower is already at max level!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
			return;
		}
		if (self.tower.upgrade()) {
			// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
			var baseUpgradeCost = getTowerCost(self.tower.id);
			if (self.tower.level >= self.tower.maxLevel) {
				upgradeCost = 0;
			} else if (self.tower.level === self.tower.maxLevel - 1) {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
			} else {
				upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1));
			}
			// Update stats text and restart animation
			fullStatsText = 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s';
			statsAnimation.text = fullStatsText;
			statsAnimation.index = 0;
			statsAnimation.timer = 0;
			statsText.setText('');
			currentStatsText = '';
			animationPhase = 'name';
			nameAnimation.index = 0;
			nameAnimation.timer = 0;
			towerTypeText.setText('');
			currentNameText = '';
			buttonText.setText('Upgrade: ' + upgradeCost + ' crystal');
			var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
			var sellValue = Math.floor(totalInvestment * 0.6);
			sellButtonText.setText('Sell: +' + sellValue + ' crystal');
			if (self.tower.level >= self.tower.maxLevel) {
				buttonBackground.tint = 0x888888;
				buttonText.setText('Max Level');
			}
			var rangeCircle = null;
			for (var i = 0; i < game.children.length; i++) {
				if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
					rangeCircle = game.children[i];
					break;
				}
			}
			if (rangeCircle) {
				var rangeGraphics = rangeCircle.children[0];
				rangeGraphics.width = rangeGraphics.height = self.tower.getRange() * 2;
			} else {
				var newRangeIndicator = new Container();
				newRangeIndicator.isTowerRange = true;
				newRangeIndicator.tower = self.tower;
				game.addChildAt(newRangeIndicator, 0);
				newRangeIndicator.x = self.tower.x;
				newRangeIndicator.y = self.tower.y;
				var rangeGraphics = newRangeIndicator.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				rangeGraphics.width = rangeGraphics.height = self.tower.getRange() * 2;
				rangeGraphics.alpha = 0.3;
			}
			tween(self, {
				scaleX: 1.05,
				scaleY: 1.05
			}, {
				duration: 100,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(self, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 100,
						easing: tween.easeIn
					});
				}
			});
		}
	};
	sellButton.down = function (x, y, obj) {
		var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
		var sellValue = getTowerSellValue(totalInvestment);
		setCrystals(crystals + sellValue);
		var notification = game.addChild(new Notification("Tower sold for " + sellValue + " crystal!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		var gridX = self.tower.gridX;
		var gridY = self.tower.gridY;
		for (var i = 0; i < 2; i++) {
			for (var j = 0; j < 2; j++) {
				var cell = grid.getCell(gridX + i, gridY + j);
				if (cell) {
					cell.type = 0;
					var towerIndex = cell.towersInRange.indexOf(self.tower);
					if (towerIndex !== -1) {
						cell.towersInRange.splice(towerIndex, 1);
					}
				}
			}
		}
		if (selectedTower === self.tower) {
			selectedTower = null;
		}
		var towerIndex = towers.indexOf(self.tower);
		if (towerIndex !== -1) {
			towers.splice(towerIndex, 1);
		}
		towerLayer.removeChild(self.tower);
		grid.pathFind();
		grid.renderDebug();
		self.destroy();
		for (var i = 0; i < game.children.length; i++) {
			if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
				game.removeChild(game.children[i]);
				break;
			}
		}
	};
	closeButton.down = function (x, y, obj) {
		LK.getSound('Closebuttonsound1').play();
		hideUpgradeMenu(self);
		selectedTower = null;
		grid.renderDebug();
	};
	self.update = function () {
		// Text animation
		if (animationPhase === 'name') {
			nameAnimation.timer++;
			if (nameAnimation.timer % animationDelay === 0 && nameAnimation.index < nameAnimation.text.length) {
				currentNameText += nameAnimation.text[nameAnimation.index];
				towerTypeText.setText(currentNameText);
				nameAnimation.index++;
			}
			if (nameAnimation.index >= nameAnimation.text.length) {
				animationPhase = 'stats';
			}
		} else if (animationPhase === 'stats') {
			statsAnimation.timer++;
			if (statsAnimation.timer % animationDelay === 0 && statsAnimation.index < statsAnimation.text.length) {
				currentStatsText += statsAnimation.text[statsAnimation.index];
				statsText.setText(currentStatsText);
				statsAnimation.index++;
			}
			if (statsAnimation.index >= statsAnimation.text.length) {
				animationPhase = 'hold';
				holdTimer = 0;
			}
		} else if (animationPhase === 'hold') {
			holdTimer++;
			if (holdTimer >= holdDuration) {
				animationPhase = 'name';
				nameAnimation.index = 0;
				nameAnimation.timer = 0;
				towerTypeText.setText('');
				currentNameText = '';
				statsAnimation.index = 0;
				statsAnimation.timer = 0;
				statsText.setText('');
				currentStatsText = '';
			}
		}
		if (self.tower.level >= self.tower.maxLevel) {
			if (buttonText.text !== 'Max Level') {
				buttonText.setText('Max Level');
				buttonBackground.tint = 0xffffff;
			}
			return;
		}
		// Exponential upgrade cost: base cost * (2 ^ (level-1)), scaled by tower base cost
		var baseUpgradeCost = getTowerCost(self.tower.id);
		var currentUpgradeCost;
		if (self.tower.level >= self.tower.maxLevel) {
			currentUpgradeCost = 0;
		} else if (self.tower.level === self.tower.maxLevel - 1) {
			currentUpgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
		} else {
			currentUpgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1));
		}
		var canAfford = crystals >= currentUpgradeCost;
		buttonBackground.tint = canAfford ? 0x00ff00 : 0xff0000;
		var newText = 'Upgrade: ' + currentUpgradeCost + ' crystal';
		if (buttonText.text !== newText) {
			buttonText.setText(newText);
		}
	};
	return self;
});
var WaveIndicator = Container.expand(function () {
	var self = Container.call(this);
	self.gameStarted = false;
	self.waveMarkers = [];
	self.waveTypes = [];
	self.enemyCounts = [];
	self.indicatorWidth = 0;
	self.lastBossType = null; // Track the last boss type to avoid repeating
	var blockWidth = 400;
	var totalBlocksWidth = blockWidth * totalWaves;
	var startMarker = new Container();
	var startBlock = startMarker.attachAsset('Notification1', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	startBlock.width = blockWidth - 10;
	startBlock.height = 70 * 2;
	startBlock.tint = 0xffffff;
	// Add shadow for start text
	var startTextShadow = new Text2("Start Game", {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	startTextShadow.anchor.set(0.5, 0.5);
	startTextShadow.x = 4;
	startTextShadow.y = 4;
	startMarker.addChild(startTextShadow);
	var startText = new Text2("Start Game", {
		size: 50,
		fill: 0xff0080,
		weight: 800
	});
	startText.anchor.set(0.5, 0.5);
	startMarker.addChild(startText);
	startMarker.x = -self.indicatorWidth;
	self.addChild(startMarker);
	self.waveMarkers.push(startMarker);
	startMarker.down = function () {
		if (!self.gameStarted && canStartWaves) {
			self.gameStarted = true;
			currentWave = 0;
			waveTimer = nextWaveTime;
			startBlock.tint = 0x00FF00;
			startText.setText("Started!");
			startTextShadow.setText("Started!");
			// Make sure shadow position remains correct after text change
			startTextShadow.x = 4;
			startTextShadow.y = 4;
			var notification = game.addChild(new Notification("Game started!\nWave 1 incoming!"));
			notification.x = 2048 / 2;
			notification.y = 2732 / 2;
		}
	};
	for (var i = 0; i < totalWaves; i++) {
		var marker = new Container();
		var block = marker.attachAsset('Notification1', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		block.width = blockWidth - 10;
		block.height = 70 * 2;
		// --- Begin new unified wave logic ---
		var waveType = "normal";
		var enemyType = "normal";
		var enemyCount = 10;
		var isBossWave = (i + 1) % 10 === 0;
		// Ensure all types appear in early waves
		if (i === 0) {
			block.tint = 0xffffff;
			waveType = "Easy";
			enemyType = "normal";
			enemyCount = 10;
		} else if (i === 1) {
			block.tint = 0xffffff;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if (i === 2) {
			block.tint = 0xffffff;
			waveType = "Unstoppable";
			enemyType = "immune";
			enemyCount = 10;
		} else if (i === 3) {
			block.tint = 0xffffff;
			waveType = "Air";
			enemyType = "flying";
			enemyCount = 10;
		} else if (i === 4) {
			block.tint = 0xffffff;
			waveType = "Group";
			enemyType = "swarm";
			enemyCount = 30;
		} else if (isBossWave) {
			// Boss waves: cycle through all boss types, last boss is always flying
			var bossTypes = ['normal', 'fast', 'immune', 'flying'];
			var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
			if (i === totalWaves - 1) {
				// Last boss is always flying
				enemyType = 'flying';
				waveType = "Boss Air";
				block.tint = 0xffffff;
			} else {
				enemyType = bossTypes[bossTypeIndex % bossTypes.length];
				switch (enemyType) {
					case 'normal':
						block.tint = 0xffffff;
						waveType = "Boss Easy";
						break;
					case 'fast':
						block.tint = 0xffffff;
						waveType = "Boss Fast";
						break;
					case 'immune':
						block.tint = 0xffffff;
						waveType = "Boss Unstoppable";
						break;
					case 'flying':
						block.tint = 0xffffff;
						waveType = "Boss Air";
						break;
				}
			}
			enemyCount = 1;
			// Make the wave indicator for boss waves stand out
			// Set boss wave color to the color of the wave type
			switch (enemyType) {
				case 'normal':
					block.tint = 0xffffff;
					break;
				case 'fast':
					block.tint = 0xffffff;
					break;
				case 'immune':
					block.tint = 0xffffff;
					break;
				case 'flying':
					block.tint = 0xffffff;
					break;
				default:
					block.tint = 0xffffff;
					break;
			}
		} else if ((i + 1) % 5 === 0) {
			// Every 5th non-boss wave is fast
			block.tint = 0xffffff;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if ((i + 1) % 4 === 0) {
			// Every 4th non-boss wave is immune
			block.tint = 0xffffff;
			waveType = "Unstoppable";
			enemyType = "immune";
			enemyCount = 10;
		} else if ((i + 1) % 7 === 0) {
			// Every 7th non-boss wave is flying
			block.tint = 0xffffff;
			waveType = "Air";
			enemyType = "flying";
			enemyCount = 10;
		} else if ((i + 1) % 3 === 0) {
			// Every 3rd non-boss wave is swarm
			block.tint = 0xffffff;
			waveType = "Group";
			enemyType = "swarm";
			enemyCount = 30;
		} else {
			block.tint = 0xffffff;
			waveType = "Easy";
			enemyType = "normal";
			enemyCount = 10;
		}
		// --- End new unified wave logic ---
		// Add tween animation to transition block color from red to white
		tween(block, {
			tint: 0xFFFFFF
		}, {
			duration: 2000,
			easing: tween.easeInOut
		});
		// Mark boss waves with a special visual indicator
		if (isBossWave && enemyType !== 'swarm') {
			// Add a crown or some indicator to the wave marker for boss waves
			var bossIndicator = marker.attachAsset('towerLevelIndicator', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			bossIndicator.width = 30;
			bossIndicator.height = 30;
			bossIndicator.tint = 0xFFD700; // Gold color
			bossIndicator.y = -block.height / 2 - 15;
			// Change the wave type text to indicate boss
			waveType = "BOSS";
		}
		// Store the wave type and enemy count
		self.waveTypes[i] = enemyType;
		self.enemyCounts[i] = enemyCount;
		self.waveDisplayNames = self.waveDisplayNames || [];
		self.waveDisplayNames[i] = waveType;
		// Add shadow for wave type - 30% smaller than before
		var waveTypeShadow = new Text2("Wave " + (i + 1), {
			size: 56,
			fill: 0x000000,
			weight: 800
		});
		waveTypeShadow.anchor.set(0.5, 0.5);
		waveTypeShadow.x = 0 + 2;
		waveTypeShadow.y = -20 + 2;
		marker.addChild(waveTypeShadow);
		// Add wave type text - 30% smaller than before
		var waveTypeText = new Text2("Wave " + (i + 1), {
			size: 56,
			fill: 0xff0080,
			weight: 800
		});
		waveTypeText.anchor.set(0.5, 0.5);
		waveTypeText.x = 0;
		waveTypeText.y = -20;
		marker.addChild(waveTypeText);
		// Add shadow for wave number - 20% larger than before
		var waveNumShadow = new Text2(waveType, {
			size: 48,
			fill: 0x000000,
			weight: 800
		});
		waveNumShadow.anchor.set(0.5, 0.5);
		waveNumShadow.x = 0 + 2;
		waveNumShadow.y = 20 + 2;
		marker.addChild(waveNumShadow);
		// Main wave number text - 20% larger than before
		var waveNum = new Text2(waveType, {
			size: 48,
			fill: 0xff0080,
			weight: 800
		});
		waveNum.anchor.set(0.5, 0.5);
		waveNum.x = 0;
		waveNum.y = 20;
		marker.addChild(waveNum);
		marker.x = -self.indicatorWidth + (i + 1) * blockWidth;
		self.addChild(marker);
		self.waveMarkers.push(marker);
	}
	// Get wave type for a specific wave number
	self.getWaveType = function (waveNumber) {
		if (waveNumber < 1 || waveNumber > totalWaves) {
			return "normal";
		}
		// If this is a boss wave (waveNumber % 10 === 0), and the type is the same as lastBossType
		// then we should return a different boss type
		var waveType = self.waveTypes[waveNumber - 1];
		return waveType;
	};
	// Get enemy count for a specific wave number
	self.getEnemyCount = function (waveNumber) {
		if (waveNumber < 1 || waveNumber > totalWaves) {
			return 10;
		}
		return self.enemyCounts[waveNumber - 1];
	};
	// Get display name for a wave type
	self.getWaveTypeName = function (waveNumber) {
		if (waveNumber < 1 || waveNumber > totalWaves) {
			return "Normal";
		}
		// Return the stored display name
		return self.waveDisplayNames[waveNumber - 1] || "Normal";
	};
	self.positionIndicator = new Container();
	var indicator = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	indicator.width = blockWidth - 10;
	indicator.height = 16;
	indicator.tint = 0x00ffb3;
	indicator.y = -65;
	var indicator2 = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	indicator2.width = blockWidth - 10;
	indicator2.height = 16;
	indicator2.tint = 0x00ffb3;
	indicator2.y = 65;
	var leftWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	leftWall.width = 16;
	leftWall.height = 146;
	leftWall.tint = 0x00ffb3;
	leftWall.x = -(blockWidth - 16) / 2;
	var rightWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	rightWall.width = 16;
	rightWall.height = 146;
	rightWall.tint = 0x00ffb3;
	rightWall.x = (blockWidth - 16) / 2;
	self.addChild(self.positionIndicator);
	self.update = function () {
		var progress = waveTimer / nextWaveTime;
		var moveAmount = (progress + currentWave) * blockWidth;
		for (var i = 0; i < self.waveMarkers.length; i++) {
			var marker = self.waveMarkers[i];
			marker.x = -moveAmount + i * blockWidth;
		}
		self.positionIndicator.x = 0;
		for (var i = 0; i < totalWaves + 1; i++) {
			var marker = self.waveMarkers[i];
			if (i === 0) {
				continue;
			}
			var block = marker.children[0];
			if (i - 1 < currentWave) {
				block.alpha = .5;
			}
		}
		self.handleWaveProgression = function () {
			if (!self.gameStarted) {
				return;
			}
			if (currentWave < totalWaves) {
				waveTimer++;
				if (waveTimer >= nextWaveTime) {
					waveTimer = 0;
					currentWave++;
					waveInProgress = true;
					waveSpawned = false;
					if (currentWave != 1) {
						var waveType = self.getWaveTypeName(currentWave);
						var enemyCount = self.getEnemyCount(currentWave);
						var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) incoming!"));
						notification.x = 2048 / 2;
						notification.y = 2732 / 2;
					}
				}
			}
		};
		self.handleWaveProgression();
	};
	return self;
});
var WeatherSystem = Container.expand(function () {
	var self = Container.call(this);
	self.currentWeather = null;
	self.weatherParticles = [];
	self.weatherOverlay = null;
	self.lastWeatherType = null;
	// Weather types: sunny, rainy, snowy, foggy, stormy
	self.getWeatherType = function (waveNumber) {
		if (waveNumber < 1) {
			return 'sunny';
		}
		var weatherCycle = Math.floor((waveNumber - 1) / 10) % 5;
		var weatherTypes = ['sunny', 'rainy', 'snowy', 'foggy', 'stormy'];
		return weatherTypes[weatherCycle];
	};
	self.update = function () {
		var weatherType = self.getWeatherType(currentWave);
		// Change weather if needed
		if (weatherType !== self.currentWeather) {
			self.clearWeather();
			self.currentWeather = weatherType;
			self.applyWeather(weatherType);
		}
		// Update particles
		for (var i = self.weatherParticles.length - 1; i >= 0; i--) {
			var particle = self.weatherParticles[i];
			if (particle && particle.update) {
				particle.update();
			}
			if (!particle || !particle.parent || particle.shouldRemove) {
				if (particle && particle.parent) {
					particle.destroy();
				}
				self.weatherParticles.splice(i, 1);
			}
		}
		// Spawn new particles based on weather
		if (self.currentWeather === 'rainy') {
			if (Math.random() < 0.3) {
				// 30% chance per frame
				self.spawnRainDrop();
			}
		} else if (self.currentWeather === 'snowy') {
			if (Math.random() < 0.2) {
				// 20% chance per frame
				self.spawnSnowflake();
			}
		} else if (self.currentWeather === 'stormy') {
			if (Math.random() < 0.35) {
				// 35% chance per frame
				self.spawnStormParticle();
			}
			if (Math.random() < 0.01) {
				// 1% chance for lightning
				self.createLightning();
			}
		}
	};
	self.clearWeather = function () {
		// Clear all particles
		for (var i = 0; i < self.weatherParticles.length; i++) {
			if (self.weatherParticles[i] && self.weatherParticles[i].parent) {
				self.weatherParticles[i].destroy();
			}
		}
		self.weatherParticles = [];
		// Remove overlay
		if (self.weatherOverlay) {
			tween(self.weatherOverlay, {
				alpha: 0
			}, {
				duration: 1000,
				onFinish: function onFinish() {
					if (self.weatherOverlay && self.weatherOverlay.parent) {
						self.weatherOverlay.destroy();
					}
					self.weatherOverlay = null;
				}
			});
		}
	};
	self.applyWeather = function (weatherType) {
		switch (weatherType) {
			case 'sunny':
				self.applySunnyWeather();
				break;
			case 'rainy':
				self.applyRainyWeather();
				break;
			case 'snowy':
				self.applySnowyWeather();
				break;
			case 'foggy':
				self.applyFoggyWeather();
				break;
			case 'stormy':
				self.applyStormyWeather();
				break;
		}
	};
	self.applySunnyWeather = function () {
		// Create sun rays effect
		for (var i = 0; i < 8; i++) {
			(function () {
				var sunRay = self.attachAsset('cell', {
					anchorX: 0.5,
					anchorY: 0,
					width: 150,
					height: 2048,
					tint: 0xFFFF88,
					alpha: 0
				});
				sunRay.x = 300 + i * 200;
				sunRay.y = -500;
				sunRay.rotation = 0.3 + i * 0.1;
				sunRay.blendMode = 1;
				tween(sunRay, {
					alpha: 0.15
				}, {
					duration: 2000,
					easing: tween.easeOut
				});
				// Gentle animation
				var _animateSunRay = function animateSunRay() {
					tween(sunRay, {
						alpha: 0.1 + Math.random() * 0.1,
						rotation: sunRay.rotation + (Math.random() - 0.5) * 0.1
					}, {
						duration: 3000 + Math.random() * 2000,
						easing: tween.easeInOut,
						onFinish: _animateSunRay
					});
				};
				_animateSunRay();
				self.weatherParticles.push(sunRay);
			})();
		}
		// Add warm overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0xFFFF00,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.05
		}, {
			duration: 2000
		});
	};
	self.applyRainyWeather = function () {
		// Add dark overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0x4444AA,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.2
		}, {
			duration: 2000
		});
	};
	self.spawnRainDrop = function () {
		var rainDrop = self.attachAsset('cell', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 3,
			height: 20,
			tint: 0x6699FF,
			alpha: 0.6,
			x: Math.random() * 2048,
			y: -50
		});
		rainDrop.velocity = 15 + Math.random() * 10;
		rainDrop.update = function () {
			rainDrop.y += rainDrop.velocity;
			if (rainDrop.y > 2782) {
				rainDrop.shouldRemove = true;
				// Create splash effect
				var splash = self.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 20,
					height: 10,
					tint: 0x6699FF,
					alpha: 0.5,
					x: rainDrop.x,
					y: 2732
				});
				tween(splash, {
					width: 40,
					height: 20,
					alpha: 0
				}, {
					duration: 300,
					onFinish: function onFinish() {
						if (splash.parent) {
							splash.destroy();
						}
					}
				});
			}
		};
		self.weatherParticles.push(rainDrop);
	};
	self.applySnowyWeather = function () {
		// Add light blue overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0xCCDDFF,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.15
		}, {
			duration: 2000
		});
	};
	self.spawnSnowflake = function () {
		var snowflake = self.attachAsset('rangeCircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 8 + Math.random() * 8,
			height: 8 + Math.random() * 8,
			tint: 0xFFFFFF,
			alpha: 0.8,
			x: Math.random() * 2048,
			y: -50
		});
		snowflake.velocity = 2 + Math.random() * 2;
		snowflake.swaySpeed = 0.02 + Math.random() * 0.02;
		snowflake.swayAmount = 30 + Math.random() * 20;
		snowflake.baseX = snowflake.x;
		snowflake.time = Math.random() * Math.PI * 2;
		snowflake.update = function () {
			snowflake.y += snowflake.velocity;
			snowflake.time += snowflake.swaySpeed;
			snowflake.x = snowflake.baseX + Math.sin(snowflake.time) * snowflake.swayAmount;
			snowflake.rotation += 0.02;
			if (snowflake.y > 2782) {
				snowflake.shouldRemove = true;
			}
		};
		self.weatherParticles.push(snowflake);
	};
	self.applyFoggyWeather = function () {
		// Create multiple fog layers
		for (var i = 0; i < 5; i++) {
			(function (index) {
				var fog = self.attachAsset('rangeCircle', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 800,
					height: 600,
					tint: 0xCCCCCC,
					alpha: 0,
					x: Math.random() * 2048,
					y: Math.random() * 2732
				});
				fog.blendMode = 1;
				tween(fog, {
					alpha: 0.3
				}, {
					duration: 3000,
					easing: tween.easeOut
				});
				// Animate fog movement
				var _animateFog = function animateFog() {
					var targetX = Math.random() * 2048;
					var targetY = Math.random() * 2732;
					tween(fog, {
						x: targetX,
						y: targetY,
						scaleX: 0.8 + Math.random() * 0.4,
						scaleY: 0.8 + Math.random() * 0.4
					}, {
						duration: 20000 + Math.random() * 10000,
						easing: tween.easeInOut,
						onFinish: _animateFog
					});
				};
				_animateFog();
				self.weatherParticles.push(fog);
			})();
		}
	};
	self.applyStormyWeather = function () {
		// Add dark storm overlay
		self.weatherOverlay = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0x333366,
			alpha: 0
		});
		tween(self.weatherOverlay, {
			alpha: 0.3
		}, {
			duration: 2000
		});
	};
	self.spawnStormParticle = function () {
		// Mix of heavy rain and wind particles
		var particle = self.attachAsset('cell', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 4,
			height: 25,
			tint: 0x8899CC,
			alpha: 0.7,
			x: Math.random() * 2248 - 100,
			// Can start off-screen
			y: -50,
			rotation: -0.3 // Angled rain
		});
		particle.velocityX = 5 + Math.random() * 3;
		particle.velocityY = 20 + Math.random() * 10;
		particle.update = function () {
			particle.x += particle.velocityX;
			particle.y += particle.velocityY;
			if (particle.y > 2782 || particle.x > 2148) {
				particle.shouldRemove = true;
			}
		};
		self.weatherParticles.push(particle);
	};
	self.createLightning = function () {
		// Flash effect
		var flash = self.attachAsset('cell', {
			width: 2048,
			height: 2732,
			tint: 0xFFFFFF,
			alpha: 0
		});
		tween(flash, {
			alpha: 0.6
		}, {
			duration: 50,
			onFinish: function onFinish() {
				tween(flash, {
					alpha: 0
				}, {
					duration: 100,
					onFinish: function onFinish() {
						if (flash.parent) {
							flash.destroy();
						}
					}
				});
			}
		});
		// Lightning bolt
		var bolt = self.attachAsset('cell', {
			anchorX: 0.5,
			anchorY: 0,
			width: 10,
			height: 2732,
			tint: 0xCCCCFF,
			alpha: 0,
			x: 200 + Math.random() * 1648,
			y: 0
		});
		bolt.blendMode = 1;
		// Create jagged lightning effect
		var segments = 8;
		for (var i = 0; i < segments; i++) {
			(function (index) {
				var segment = self.attachAsset('cell', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: 5 + Math.random() * 15,
					height: 2732 / segments,
					tint: 0xFFFFFF,
					alpha: 0,
					x: bolt.x + (Math.random() - 0.5) * 100,
					y: index * (2732 / segments)
				});
				segment.blendMode = 1;
				tween(segment, {
					alpha: 0.9
				}, {
					duration: 50,
					delay: index * 10,
					onFinish: function onFinish() {
						tween(segment, {
							alpha: 0
						}, {
							duration: 200,
							onFinish: function onFinish() {
								if (segment.parent) {
									segment.destroy();
								}
							}
						});
					}
				});
			})();
		}
		tween(bolt, {
			alpha: 0.8
		}, {
			duration: 50,
			onFinish: function onFinish() {
				tween(bolt, {
					alpha: 0
				}, {
					duration: 300,
					onFinish: function onFinish() {
						if (bolt.parent) {
							bolt.destroy();
						}
					}
				});
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x00ffdd
});
/**** 
* Game Code
****/ 
// Initialize sound system FIRST before any other game code
game.soundVolume = storage.soundVolume !== undefined ? storage.soundVolume : 1.0; // Load from storage or default to full volume
// Create the sound playing helper function
game.playSoundWithVolume = function (soundName) {
	var sound = LK.getSound(soundName);
	if (sound) {
		// Get the original volume from the asset definition
		var originalVolume = 1.0; // Default volume
		switch (soundName) {
			case 'Bulletsound':
				originalVolume = 0.3;
				break;
			case 'Flamesound':
				originalVolume = 0.5;
				break;
			case 'Gumbombsound':
				originalVolume = 0.4;
				break;
			case 'Riflebulletsound':
				originalVolume = 0.3;
				break;
			case 'Rocketsound':
				originalVolume = 0.3;
				break;
			case 'Ship1sound':
				originalVolume = 1.0;
				break;
			case 'Ship2sound':
				originalVolume = 1.0;
				break;
			case 'Ship3sound':
				originalVolume = 0.2;
				break;
			case 'Toxinbombsound':
				originalVolume = 1.0;
				break;
			case 'placmentsound1':
			case 'placmentsound2':
			case 'placmentsound3':
			case 'placmentsound4':
			case 'placmentsound5':
			case 'placmentsound6':
				originalVolume = 1.0;
				break;
		}
		// Apply both the original volume and the user's sound volume setting
		var finalVolume = originalVolume * game.soundVolume;
		// Play the sound with the calculated volume
		sound.play({
			volume: finalVolume
		});
	}
};
// Game state variables
// Define all available abilities with their effects
var abilityDefinitions = {
	'ability_0': {
		name: 'Healing Wave',
		description: 'Heal 25% of max health',
		icon: 'Ability1',
		color: 0x00FF00,
		effect: function effect() {
			lives = Math.min(100, lives + 25);
			updateUI();
			var notification = game.addChild(new Notification("Healing Wave activated! +25 health"));
			// Add a green screen flash for healing
			var flash = LK.getAsset('cell', {
				width: 2048,
				height: 2732,
				x: 0,
				y: 0,
				alpha: 0,
				tint: 0x00FF00
			});
			game.addChild(flash);
			tween(flash, {
				alpha: 0.5
			}, {
				duration: 200,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(flash, {
						alpha: 0
					}, {
						duration: 300,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							if (flash.parent) {
								flash.destroy();
							}
						}
					});
				}
			});
			// Add rising green healing particles across the screen
			for (var i = 0; i < 30; i++) {
				(function () {
					var particle = game.attachAsset('rangeCircle', {
						anchorX: 0.5,
						anchorY: 0.5,
						tint: 0x32CD32,
						// LimeGreen
						width: 15 + Math.random() * 20,
						height: 15 + Math.random() * 20,
						alpha: 0.8,
						blendMode: 1,
						x: Math.random() * 2048,
						y: 2732 + Math.random() * 200
					});
					tween(particle, {
						y: particle.y - 800 - Math.random() * 500,
						alpha: 0
					}, {
						duration: 1500 + Math.random() * 1000,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							if (particle.parent) {
								particle.destroy();
							}
						}
					});
				})();
			}
		}
	},
	'ability_1': {
		name: 'Weakness Curse',
		description: 'Enemies take 50% more damage for 10 seconds',
		icon: 'Ability2',
		color: 0xFF4500,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].weakened) {
					enemies[i].weakened = true;
					enemies[i].weakenDuration = 600; // 10 seconds at 60 FPS
					enemies[i].originalDamageResistance = enemies[i].damageResistance || 1;
					enemies[i].damageResistance = enemies[i].originalDamageResistance * 1.5; // Take 50% more damage
					// Add weakness animation on each enemy
					(function (currentEnemy) {
						var originalScaleX = currentEnemy.scaleX || 1;
						var originalScaleY = currentEnemy.scaleY || 1;
						tween(currentEnemy, {
							tint: 0xFF0000,
							scaleX: originalScaleX * 1.3,
							scaleY: originalScaleY * 1.3
						}, {
							duration: 200,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (currentEnemy && currentEnemy.parent) {
									tween(currentEnemy, {
										tint: 0xFF4500,
										scaleX: originalScaleX,
										scaleY: originalScaleY
									}, {
										duration: 500,
										easing: tween.easeOut
									});
								}
							}
						});
						// Add dripping curse particles
						var curseParticles = new Container();
						currentEnemy.addChild(curseParticles);
						for (var p = 0; p < 10; p++) {
							(function () {
								var particle = curseParticles.attachAsset('rangeCircle', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: 0x8A2BE2,
									// BlueViolet for curse
									width: 8 + Math.random() * 8,
									height: 8 + Math.random() * 8,
									alpha: 0.9,
									x: (Math.random() - 0.5) * currentEnemy.children[0].width,
									y: -currentEnemy.children[0].height / 2 + (Math.random() - 0.5) * 20
								});
								var duration = 800 + Math.random() * 500;
								var delay = Math.random() * 9500; // Drip throughout the 10s duration
								tween(particle, {
									y: particle.y + 60,
									alpha: 0
								}, {
									duration: duration,
									delay: delay,
									onFinish: function onFinish() {
										if (particle.parent) {
											particle.destroy();
										}
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (curseParticles.parent) {
								curseParticles.destroy();
							}
						}, 10000);
					})(enemies[i]);
				}
			}
			var notification = game.addChild(new Notification("Weakness Curse activated! Enemies weakened!"));
		}
	},
	'ability_2': {
		name: 'Lightning Storm',
		description: 'Deals 15% damage to all enemies based on their difficulty',
		icon: 'Ability3',
		color: 0xFFFF00,
		effect: function effect() {
			for (var i = enemies.length - 1; i >= 0; i--) {
				if (!enemies[i]) {
					continue;
				} // Safety check
				var damage = enemies[i].maxHealth * 0.15;
				if (enemies[i].type === 'easy') {
					damage *= 1.5;
				} else if (enemies[i].type === 'medium') {
					damage *= 1.0;
				} else if (enemies[i].type === 'hard') {
					damage *= 0.7;
				}
				enemies[i].health -= damage;
				if (enemies[i].health <= 0) {
					enemies[i].health = 0;
				} else {
					var healthPercentage = enemies[i].health / enemies[i].maxHealth;
					enemies[i].healthBar.width = enemies[i].healthBarOriginalWidth * healthPercentage;
				}
				// Use an IIFE to create a new scope for each enemy, fixing closure bugs
				(function (currentEnemy) {
					if (currentEnemy && currentEnemy.parent && currentEnemy.children[0]) {
						// Add electricity particle effects
						var lightningEffectContainer = new Container();
						currentEnemy.addChild(lightningEffectContainer);
						for (var k = 0; k < 7; k++) {
							// Create 7 lightning bolts
							(function () {
								// IIFE for each bolt's closure
								var bolt = lightningEffectContainer.attachAsset('cell', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: Math.random() < 0.5 ? 0xADD8E6 : 0xFFFFFF,
									// Light Blue or White
									width: 2 + Math.random() * 4,
									height: 30 + Math.random() * 50,
									alpha: 0
								});
								bolt.x = (Math.random() - 0.5) * 70;
								bolt.y = (Math.random() - 0.5) * 70;
								bolt.rotation = (Math.random() - 0.5) * Math.PI;
								tween(bolt, {
									alpha: 0.9
								}, {
									duration: 100,
									delay: Math.random() * 100,
									onFinish: function onFinish() {
										tween(bolt, {
											alpha: 0
										}, {
											duration: 150,
											onFinish: function onFinish() {
												if (bolt.parent) {
													bolt.destroy();
												}
											}
										});
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (lightningEffectContainer.parent) {
								lightningEffectContainer.destroy();
							}
						}, 600);
						// Add lightning strike tint animation on each enemy
						var enemyGraphics = currentEnemy.children[0];
						var originalTint = enemyGraphics.tint;
						tween(enemyGraphics, {
							tint: 0x87CEEB // Sky Blue for lightning strike
						}, {
							duration: 100,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (enemyGraphics && enemyGraphics.parent) {
									tween(enemyGraphics, {
										tint: 0xFFFFFF // White flash
									}, {
										duration: 50,
										easing: tween.easeIn,
										onFinish: function onFinish() {
											if (enemyGraphics && enemyGraphics.parent) {
												tween(enemyGraphics, {
													tint: 0x87CEEB // Sky Blue for lightning strike
												}, {
													duration: 50,
													easing: tween.easeOut,
													onFinish: function onFinish() {
														if (enemyGraphics && enemyGraphics.parent) {
															tween(enemyGraphics, {
																tint: originalTint
															}, {
																duration: 100,
																easing: tween.easeIn
															});
														}
													}
												});
											}
										}
									});
								}
							}
						});
					}
				})(enemies[i]);
			}
			var notification = game.addChild(new Notification("Lightning Storm! All enemies shocked!"));
		}
	},
	'ability_3': {
		name: 'Dust Storm',
		description: 'Slows all enemies by 70% for 3 seconds',
		icon: 'Ability4',
		color: 0x8B4513,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].dustSlowed) {
					enemies[i].dustSlowed = true;
					enemies[i].dustSlowDuration = 180; // 3 seconds at 60 FPS
					if (!enemies[i].originalSpeed) {
						enemies[i].originalSpeed = enemies[i].speed;
					}
					enemies[i].speed = enemies[i].originalSpeed * 0.3; // 70% slower
					// Add dust swirl animation on each enemy
					var currentEnemy = enemies[i]; // Store reference to avoid closure issues
					tween(currentEnemy, {
						tint: 0x8B4513
					}, {
						duration: 300
					});
					// Add dust particles swirling around the enemy
					var dustContainer = new Container();
					currentEnemy.addChild(dustContainer);
					for (var p = 0; p < 8; p++) {
						(function () {
							var particle = dustContainer.attachAsset('rangeCircle', {
								anchorX: 0.5,
								anchorY: 0.5,
								tint: 0xCD853F,
								// Peru color for dust
								width: 10 + Math.random() * 15,
								height: 10 + Math.random() * 15,
								alpha: 0.8
							});
							var angle = Math.random() * Math.PI * 2;
							var startRadius = 20;
							particle.x = Math.cos(angle) * startRadius;
							particle.y = Math.sin(angle) * startRadius;
							var endRadius = 40 + Math.random() * 20;
							var duration = 1500 + Math.random() * 1000;
							tween(particle, {
								x: Math.cos(angle) * endRadius,
								y: Math.sin(angle) * endRadius,
								alpha: 0,
								rotation: particle.rotation + Math.PI
							}, {
								duration: duration,
								onFinish: function onFinish() {
									if (particle.parent) {
										particle.destroy();
									}
								}
							});
						})();
					}
					LK.setTimeout(function () {
						if (dustContainer.parent) {
							dustContainer.destroy();
						}
					}, 3000); // Effect duration is 3 seconds
				}
			}
			var notification = game.addChild(new Notification("Dust Storm! Enemies slowed by dust!"));
		}
	},
	'ability_4': {
		name: 'Water Flood',
		description: 'Enemies drown slowly, losing 8% health per second for 5 seconds',
		icon: 'Ability5',
		color: 0x0080FF,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].drowning) {
					enemies[i].drowning = true;
					enemies[i].drownDuration = 300; // 5 seconds at 60 FPS
					enemies[i].drownDamage = enemies[i].maxHealth * 0.08 / 60; // 8% per second
					// Add water splash and drowning animation
					var currentEnemy = enemies[i]; // Store reference to avoid closure issues
					tween(currentEnemy, {
						tint: 0x0080FF
					}, {
						duration: 300
					});
					// Add bubbles rising from the enemy
					var bubbleContainer = new Container();
					currentEnemy.addChild(bubbleContainer);
					for (var b = 0; b < 5; b++) {
						(function () {
							var bubble = bubbleContainer.attachAsset('rangeCircle', {
								anchorX: 0.5,
								anchorY: 0.5,
								tint: 0xADD8E6,
								// Light blue for bubbles
								width: 5 + Math.random() * 10,
								height: 5 + Math.random() * 10,
								y: 0,
								x: (Math.random() - 0.5) * 20,
								alpha: 0.7
							});
							var duration = 1000 + Math.random() * 1000;
							var delay = Math.random() * 4000; // Bubbles appear throughout the 5s duration
							tween(bubble, {
								y: -40,
								alpha: 0
							}, {
								duration: duration,
								delay: delay,
								onFinish: function onFinish() {
									if (bubble.parent) {
										bubble.destroy();
									}
								}
							});
						})();
					}
					LK.setTimeout(function () {
						if (bubbleContainer.parent) {
							bubbleContainer.destroy();
						}
					}, 5000); // Effect duration is 5 seconds
				}
			}
			var notification = game.addChild(new Notification("Water Flood! Enemies are drowning!"));
		}
	},
	'ability_5': {
		name: 'Fire Ring',
		description: 'Creates fire around enemies, dealing 10% damage for 4 seconds',
		icon: 'Ability6',
		color: 0xFF0000,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].burning) {
					enemies[i].burning = true;
					enemies[i].burnDuration = 240; // 4 seconds at 60 FPS
					enemies[i].burnDamage = enemies[i].maxHealth * 0.10 / 60; // 10% per second
					// Add fire ring animation around each enemy
					(function (currentEnemy) {
						var fireIntensity = 0;
						var _burnAnimation = function burnAnimation() {
							if (!currentEnemy || !currentEnemy.parent || !currentEnemy.burning) {
								if (currentEnemy && currentEnemy.parent) {
									tween(currentEnemy, {
										tint: 0xFFFFFF,
										scaleX: 1,
										scaleY: 1
									}, {
										duration: 200
									});
								}
								return;
							}
							fireIntensity++;
							var flameColor = fireIntensity % 2 === 0 ? 0xFF0000 : 0xFF4500;
							var scale = 1 + (fireIntensity % 2 === 0 ? 0.1 : 0.05);
							tween(currentEnemy, {
								tint: flameColor,
								scaleX: scale,
								scaleY: scale
							}, {
								duration: 250,
								easing: tween.easeInOut,
								onFinish: _burnAnimation
							});
						};
						_burnAnimation();
						// Add rising embers/sparks
						var fireParticles = new Container();
						currentEnemy.addChild(fireParticles);
						for (var p = 0; p < 8; p++) {
							(function () {
								var particle = fireParticles.attachAsset('rangeCircle', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: Math.random() < 0.5 ? 0xFF4500 : 0xFFD700,
									// Orange-red to gold
									width: 5 + Math.random() * 10,
									height: 5 + Math.random() * 10,
									alpha: 0.9,
									blendMode: 1,
									x: (Math.random() - 0.5) * currentEnemy.children[0].width,
									y: (Math.random() - 0.5) * 20
								});
								var duration = 600 + Math.random() * 400;
								var delay = Math.random() * 3800;
								tween(particle, {
									y: particle.y - 40 - Math.random() * 20,
									alpha: 0
								}, {
									duration: duration,
									delay: delay,
									onFinish: function onFinish() {
										if (particle.parent) {
											particle.destroy();
										}
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (fireParticles.parent) {
								fireParticles.destroy();
							}
						}, 4000);
					})(enemies[i]);
				}
			}
			var notification = game.addChild(new Notification("Fire Ring! Enemies are burning!"));
		}
	},
	'ability_6': {
		name: 'Ice Freeze',
		description: 'Freezes all enemies for 3 seconds',
		icon: 'Ability7',
		color: 0x00FFFF,
		effect: function effect() {
			for (var i = 0; i < enemies.length; i++) {
				if (enemies[i] && !enemies[i].frozen) {
					enemies[i].frozen = true;
					enemies[i].freezeDuration = 180; // 3 seconds at 60 FPS
					if (!enemies[i].originalSpeed) {
						enemies[i].originalSpeed = enemies[i].speed;
					}
					enemies[i].speed = 0; // Completely frozen
					// Add ice freeze animation
					var currentEnemy = enemies[i]; // Store reference to avoid closure issues
					tween(currentEnemy, {
						tint: 0x00FFFF,
						scaleX: 0.9,
						scaleY: 0.9
					}, {
						duration: 400,
						easing: tween.easeOut
					});
					// Add ice shards that form around the enemy
					var iceContainer = new Container();
					currentEnemy.addChild(iceContainer);
					for (var s = 0; s < 8; s++) {
						(function () {
							var shard = iceContainer.attachAsset('cell', {
								anchorX: 0.5,
								anchorY: 0.5
							});
							shard.tint = 0xB0E0E6; // Powder blue
							shard.width = 15;
							shard.height = 5;
							shard.rotation = Math.random() * Math.PI * 2;
							var angle = Math.random() * Math.PI * 2;
							var radius = 20 + Math.random() * 10;
							shard.x = Math.cos(angle) * radius;
							shard.y = Math.sin(angle) * radius;
							shard.alpha = 0;
							tween(shard, {
								alpha: 1.0
							}, {
								duration: 400
							});
						})();
					}
					LK.setTimeout(function () {
						if (iceContainer.parent) {
							tween(iceContainer, {
								alpha: 0
							}, {
								duration: 300,
								onFinish: function onFinish() {
									if (iceContainer.parent) {
										iceContainer.destroy();
									}
								}
							});
						}
					}, 2700); // Start fading out before freeze ends
				}
			}
			var notification = game.addChild(new Notification("Ice Freeze! All enemies frozen!"));
		}
	},
	'ability_7': {
		name: 'Shield Boost',
		description: 'Gain 15 health and towers deal 25% more damage for 8 seconds',
		icon: 'Ability8',
		color: 0xFFD700,
		effect: function effect() {
			lives = Math.min(100, lives + 15);
			updateUI();
			// Boost all towers
			for (var i = 0; i < towers.length; i++) {
				if (towers[i] && !towers[i].boosted) {
					towers[i].boosted = true;
					towers[i].boostDuration = 480; // 8 seconds at 60 FPS
					towers[i].originalDamage = towers[i].damage;
					towers[i].damage = Math.floor(towers[i].damage * 1.25);
					// Add golden glow animation to boosted towers
					(function (currentTower) {
						tween(currentTower, {
							tint: 0xFFD700,
							scaleX: 1.15,
							scaleY: 1.15
						}, {
							duration: 300,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								if (currentTower && currentTower.parent) {
									tween(currentTower, {
										scaleX: 1,
										scaleY: 1
									}, {
										duration: 200,
										easing: tween.easeIn
									});
								}
							}
						});
						// Add shimmering shield particles
						var shieldParticles = new Container();
						currentTower.addChild(shieldParticles);
						for (var p = 0; p < 12; p++) {
							(function () {
								var particle = shieldParticles.attachAsset('rangeCircle', {
									anchorX: 0.5,
									anchorY: 0.5,
									tint: 0xFFD700,
									// Gold
									width: 8 + Math.random() * 12,
									height: 8 + Math.random() * 12,
									alpha: 0,
									blendMode: 1
								});
								var angle = Math.random() * Math.PI * 2;
								var startRadius = 30 + Math.random() * 20;
								var endRadius = 60 + Math.random() * 30;
								particle.x = Math.cos(angle) * startRadius;
								particle.y = Math.sin(angle) * startRadius;
								tween(particle, {
									alpha: 0.8
								}, {
									duration: 400,
									delay: Math.random() * 1000,
									onFinish: function onFinish() {
										tween(particle, {
											x: Math.cos(angle) * endRadius,
											y: Math.sin(angle) * endRadius,
											alpha: 0
										}, {
											duration: 800 + Math.random() * 500,
											delay: Math.random() * 6000,
											onFinish: function onFinish() {
												if (particle.parent) {
													particle.destroy();
												}
											}
										});
									}
								});
							})();
						}
						LK.setTimeout(function () {
							if (shieldParticles.parent) {
								shieldParticles.destroy();
							}
						}, 8000); // 8 seconds
					})(towers[i]);
				}
			}
			var notification = game.addChild(new Notification("Shield Boost! Health gained and towers boosted!"));
		}
	},
	'ability_8': {
		name: 'Ultimate Storm',
		description: 'Combines multiple effects: heal, damage enemies, slow them',
		icon: 'Ability9',
		color: 0xFF00FF,
		effect: function effect() {
			// Heal player
			lives = Math.min(100, lives + 20);
			updateUI();
			// Damage and slow all enemies
			for (var i = 0; i < enemies.length; i++) {
				if (!enemies[i]) {
					continue;
				} // Safety check
				// Deal damage
				var damage = enemies[i].maxHealth * 0.20;
				enemies[i].health -= damage;
				if (enemies[i].health <= 0) {
					enemies[i].health = 0;
				} else {
					var healthPercentage = enemies[i].health / enemies[i].maxHealth;
					enemies[i].healthBar.width = enemies[i].healthBarOriginalWidth * healthPercentage;
				}
				// Apply slow
				if (!enemies[i].ultimateSlowed) {
					enemies[i].ultimateSlowed = true;
					enemies[i].ultimateSlowDuration = 300; // 5 seconds
					if (!enemies[i].originalSpeed) {
						enemies[i].originalSpeed = enemies[i].speed;
					}
					enemies[i].speed = enemies[i].originalSpeed * 0.4; // 60% slower
				}
				// Add ultimate storm animation - combination of all effects
				(function (currentEnemy) {
					var stormPhase = 0;
					var _ultimateStormAnimation = function ultimateStormAnimation() {
						stormPhase++;
						if (!currentEnemy || !currentEnemy.parent) {
							return;
						}
						if (stormPhase === 1) {
							// Lightning phase (Blue/White)
							tween(currentEnemy, {
								tint: 0x87CEEB,
								scaleX: 1.2,
								scaleY: 1.2
							}, {
								duration: 150,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (currentEnemy && currentEnemy.parent) {
										tween(currentEnemy, {
											tint: 0xFFFFFF
										}, {
											duration: 150,
											easing: tween.easeIn,
											onFinish: _ultimateStormAnimation
										});
									} else {
										_ultimateStormAnimation();
									}
								}
							});
						} else if (stormPhase === 2) {
							// Fire phase (Red/Orange)
							tween(currentEnemy, {
								tint: 0xFF0000,
								scaleX: 1.1,
								scaleY: 1.1
							}, {
								duration: 150,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (currentEnemy && currentEnemy.parent) {
										tween(currentEnemy, {
											tint: 0xFF4500
										}, {
											duration: 150,
											easing: tween.easeIn,
											onFinish: _ultimateStormAnimation
										});
									} else {
										_ultimateStormAnimation();
									}
								}
							});
						} else if (stormPhase === 3) {
							// Ice phase (Cyan)
							tween(currentEnemy, {
								tint: 0x00FFFF,
								scaleX: 0.9,
								scaleY: 0.9
							}, {
								duration: 200,
								easing: tween.easeOut,
								onFinish: _ultimateStormAnimation
							});
						} else {
							// Final phase - return to normal with magical glow
							tween(currentEnemy, {
								tint: 0xFF00FF,
								scaleX: 1,
								scaleY: 1
							}, {
								duration: 300,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (currentEnemy && currentEnemy.parent) {
										tween(currentEnemy, {
											tint: 0xFFFFFF
										}, {
											duration: 500,
											easing: tween.easeIn
										});
									}
								}
							});
						}
					};
					// Start ultimate storm animation
					_ultimateStormAnimation();
					// Add multi-colored particle explosion
					var stormParticles = new Container();
					currentEnemy.addChild(stormParticles);
					var colors = [0x87CEEB, 0xFFFFFF, 0xFF0000, 0xFF4500, 0x00FFFF, 0xFF00FF];
					for (var p = 0; p < 25; p++) {
						(function () {
							var particle = stormParticles.attachAsset('rangeCircle', {
								anchorX: 0.5,
								anchorY: 0.5,
								tint: colors[Math.floor(Math.random() * colors.length)],
								width: 10 + Math.random() * 15,
								height: 10 + Math.random() * 15,
								alpha: 1.0,
								blendMode: 1
							});
							var angle = Math.random() * Math.PI * 2;
							var startRadius = 10;
							var endRadius = 60 + Math.random() * 40;
							particle.x = Math.cos(angle) * startRadius;
							particle.y = Math.sin(angle) * startRadius;
							var duration = 500 + Math.random() * 400;
							tween(particle, {
								x: Math.cos(angle) * endRadius,
								y: Math.sin(angle) * endRadius,
								alpha: 0,
								rotation: particle.rotation + Math.PI * 2
							}, {
								duration: duration,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (particle.parent) {
										particle.destroy();
									}
								}
							});
						})();
					}
					LK.setTimeout(function () {
						if (stormParticles.parent) {
							stormParticles.destroy();
						}
					}, 1200);
				})(enemies[i]);
			}
			var notification = game.addChild(new Notification("ULTIMATE STORM! All effects activated!"));
		}
	}
};
var canStartWaves = false;
var canPlaceTowers = false;
var gameStarted = false;
var showingIntro = true;
var showingScores = false;
var scoreBackground = null;
var scoreMenu = null;
var showingAbilities = false;
var abilitiesMenu = null;
var showingSettings = false;
var settingBackground = null;
var settingMenu = null;
var brightnessOverlay = null;
var isDraggingLightButton = false;
var isDraggingMusicButton = false;
var isDraggingSoundButton = false;
var girlCharacter = null;
var showingTutorial = false;
var tutorialScreen = null;
// High scores management
function getHighScores() {
	return storage.highScores || [];
}
function addHighScore(score) {
	var highScores = getHighScores();
	highScores.push(score);
	// Sort in descending order
	highScores.sort(function (a, b) {
		return b - a;
	});
	// Keep only top 10
	if (highScores.length > 10) {
		highScores = highScores.slice(0, 10);
	}
	storage.highScores = highScores;
	return highScores;
}
function showAbilities() {
	if (showingAbilities) {
		return;
	}
	showingAbilities = true;
	abilitiesMenu = new AbilitiesMenu();
	abilitiesMenu.x = 2048 / 2 - 60;
	abilitiesMenu.y = 2732 / 2;
	game.addChild(abilitiesMenu);
	abilitiesMenu.scale.set(0.5);
	abilitiesMenu.alpha = 0;
	tween(abilitiesMenu, {
		scaleX: 1,
		scaleY: 1,
		alpha: 1
	}, {
		duration: 300,
		easing: tween.easeOut
	});
}
function hideAbilities() {
	if (!showingAbilities || !abilitiesMenu) {
		return;
	}
	showingAbilities = false;
	tween(abilitiesMenu, {
		scaleX: 0.5,
		scaleY: 0.5,
		alpha: 0
	}, {
		duration: 300,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			if (abilitiesMenu) {
				abilitiesMenu.destroy();
				abilitiesMenu = null;
			}
		}
	});
}
function showSettings() {
	if (showingSettings) {
		return;
	}
	showingSettings = true;
	settingBackground = game.attachAsset('SettingBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var startX = 2048 + settingBackground.width / 2;
	var targetX = 2048 / 2;
	settingBackground.x = startX;
	settingBackground.y = 2732 / 2;
	game.addChild(settingBackground);
	settingMenu = new Container();
	settingMenu.x = startX;
	settingMenu.y = 2732 / 2;
	game.addChild(settingMenu);
	var closeButton = new Container();
	closeButton.attachAsset('CloseButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.y = settingBackground.height / 2 - 150;
	settingMenu.addChild(closeButton);
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideSettings();
	};
	// Calculate vertical positions to center all three volume settings in the settingBackground
	var totalHeight = 400; // Total height span for all three settings (200px spacing between each)
	var musicY = -totalHeight / 2; // -200
	var soundY = 0; // Center
	var lightY = totalHeight / 2; // 200
	// Calculate horizontal positions to center all elements in the settingBackground
	var totalWidth = 700; // Approximate total width of icon + bar + percentage text
	var iconX = -totalWidth / 2 - 200; // Center the icons horizontally, moved 200px left
	var barX = iconX + 150;
	// Music Setting
	var musicIcon = settingMenu.attachAsset('MusicIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	musicIcon.x = iconX;
	musicIcon.y = musicY;
	var musicBar = settingMenu.attachAsset('MusicBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	musicBar.name = "musicBar";
	musicBar.x = barX;
	musicBar.y = musicY;
	var musicButton = settingMenu.attachAsset('MusicButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	musicButton.name = "musicButton";
	musicButton.y = musicY;
	// Position music button based on current music volume
	var currentMusicVolume = game.musicVolume || 1.0;
	var musicTrackWidth = musicBar.width - musicButton.width;
	musicButton.x = musicBar.x + musicButton.width / 2 + musicTrackWidth * currentMusicVolume;
	// Add music volume percentage text
	var musicPercentage = new Text2(Math.round((game.musicVolume || 1.0) * 100) + "%", {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	musicPercentage.anchor.set(0.5, 0.5);
	musicPercentage.x = musicBar.x + musicBar.width + 80;
	musicPercentage.y = musicY;
	musicPercentage.name = "musicPercentage";
	settingMenu.addChild(musicPercentage);
	musicButton.down = function () {
		isDraggingMusicButton = true;
	};
	// Sound Setting
	var soundIcon = settingMenu.attachAsset('SoundIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	soundIcon.x = iconX;
	soundIcon.y = soundY;
	var soundBar = settingMenu.attachAsset('SoundBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	soundBar.name = "soundBar";
	soundBar.x = barX;
	soundBar.y = soundY;
	var soundButton = settingMenu.attachAsset('SoundButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	soundButton.name = "soundButton";
	soundButton.y = soundY;
	// Add sound volume percentage text
	var soundPercentage = new Text2(Math.round(game.soundVolume * 100) + "%", {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	soundPercentage.anchor.set(0.5, 0.5);
	soundPercentage.x = soundBar.x + soundBar.width + 80;
	soundPercentage.y = soundY;
	soundPercentage.name = "soundPercentage";
	settingMenu.addChild(soundPercentage);
	// Position sound button based on current sound volume
	var currentSoundVolume = game.soundVolume || 1.0;
	var soundTrackWidth = soundBar.width - soundButton.width;
	soundButton.x = soundBar.x + soundButton.width / 2 + soundTrackWidth * currentSoundVolume;
	soundButton.down = function () {
		isDraggingSoundButton = true;
	};
	// Light Setting
	var lightIcon = settingMenu.attachAsset('LightIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	lightIcon.x = iconX;
	lightIcon.y = lightY;
	var lightBar = settingMenu.attachAsset('LightBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	lightBar.name = "lightBar";
	lightBar.x = barX;
	lightBar.y = lightY;
	var lightButton = settingMenu.attachAsset('LightButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	lightButton.name = "lightButton";
	lightButton.y = lightY;
	lightButton.x = lightBar.x + lightButton.width / 2;
	// Add light percentage text
	var lightPercentage = new Text2("0%", {
		size: 50,
		fill: 0x00ffb3,
		weight: 800
	});
	lightPercentage.anchor.set(0.5, 0.5);
	lightPercentage.x = lightBar.x + lightBar.width + 80;
	lightPercentage.y = lightY;
	lightPercentage.name = "lightPercentage";
	settingMenu.addChild(lightPercentage);
	lightButton.down = function () {
		isDraggingLightButton = true;
	};
	tween(settingBackground, {
		x: targetX
	}, {
		duration: 500,
		easing: tween.easeOut
	});
	tween(settingMenu, {
		x: targetX
	}, {
		duration: 500,
		easing: tween.easeOut
	});
}
function hideSettings() {
	if (!showingSettings) {
		return;
	}
	showingSettings = false;
	var targetX = 2048 + 1600 / 2;
	if (settingBackground) {
		tween(settingBackground, {
			x: targetX
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				if (settingBackground) {
					game.removeChild(settingBackground);
					settingBackground = null;
				}
			}
		});
	}
	if (settingMenu) {
		tween(settingMenu, {
			x: targetX
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				if (settingMenu) {
					game.removeChild(settingMenu);
					settingMenu = null;
				}
			}
		});
	}
}
function showHighScores() {
	if (showingScores) {
		return;
	}
	showingScores = true;
	// Create score background
	scoreBackground = game.attachAsset('Scorebackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	scoreBackground.x = 2048 / 2;
	scoreBackground.y = 2732 / 2;
	game.addChild(scoreBackground);
	// Create score menu container
	scoreMenu = new Container();
	scoreMenu.x = 2048 / 2;
	scoreMenu.y = 2732 / 2;
	game.addChild(scoreMenu);
	// Add title
	var titleShadow = new Text2("HIGH SCORES", {
		size: 80,
		fill: 0x000000,
		weight: 800
	});
	titleShadow.anchor.set(0.5, 0.5);
	titleShadow.x = 4;
	titleShadow.y = -400 + 4;
	scoreMenu.addChild(titleShadow);
	var title = new Text2("HIGH SCORES", {
		size: 80,
		fill: 0x00ffb3,
		weight: 800
	});
	title.anchor.set(0.5, 0.5);
	title.y = -400;
	scoreMenu.addChild(title);
	// Get and display high scores
	var highScores = getHighScores();
	for (var i = 0; i < 10; i++) {
		var rank = i + 1;
		var scoreValue = i < highScores.length ? highScores[i] : 0;
		var yPos = -280 + i * 60;
		// Score rank and value shadow
		var scoreShadow = new Text2(rank + ". " + scoreValue, {
			size: 60,
			fill: 0x000000,
			weight: 800
		});
		scoreShadow.anchor.set(0.5, 0.5);
		scoreShadow.x = 4;
		scoreShadow.y = yPos + 4;
		scoreMenu.addChild(scoreShadow);
		// Score rank and value
		var scoreColor = i < 3 ? 0xFFD700 : 0x00ffb3; // Gold for top 3
		var scoreText = new Text2(rank + ". " + scoreValue, {
			size: 60,
			fill: scoreColor,
			weight: 800
		});
		scoreText.anchor.set(0.5, 0.5);
		scoreText.y = yPos;
		scoreMenu.addChild(scoreText);
	}
	// Add close button
	var closeButton = new Container();
	var closeButtonBg = closeButton.attachAsset('ScoreCloseButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.y = 450;
	scoreMenu.addChild(closeButton);
	// Close button handler
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideHighScores();
	};
}
function hideHighScores() {
	if (!showingScores) {
		return;
	}
	showingScores = false;
	if (scoreBackground) {
		game.removeChild(scoreBackground);
		scoreBackground = null;
	}
	if (scoreMenu) {
		game.removeChild(scoreMenu);
		scoreMenu = null;
	}
}
function showTutorial() {
	if (showingTutorial) {
		return;
	}
	showingTutorial = true;
	// Create tutorial screen container
	tutorialScreen = new Container();
	tutorialScreen.x = 2048 / 2;
	tutorialScreen.y = 2732 / 2;
	game.addChild(tutorialScreen);
	// Add background using proper Tutorialbackground asset
	var tutorialBg = tutorialScreen.attachAsset('Tutorialbackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	tutorialBg.width = 2048;
	tutorialBg.height = 2732;
	// Add title
	var title = new Text2("HOW TO PLAY", {
		size: 80,
		fill: 0xff0080,
		weight: 800
	});
	title.anchor.set(0.5, 0.5);
	title.y = -tutorialBg.height / 2 + 100;
	tutorialScreen.addChild(title);
	// Tutorial content
	var tutorialContent = [{
		title: "1. PLACING TOWERS",
		desc: "Drag towers from bottom bar\nto the grid. Each tower costs\ncrystals shown below it."
	}, {
		title: "2. UPGRADE & SELL",
		desc: "Tap on a placed tower to\nupgrade (costs more crystals)\nor sell (get 80% back)."
	}, {
		title: "3. TOWER TYPES",
		desc: "Cannon: Basic damage\nRifle: Fast shooting\nFlame: Continuous damage\nRocket: Splash damage\nGumbomb: Slows enemies\nToxinbomb: Poison damage"
	}, {
		title: "4. START WAVES",
		desc: "Click 'Start Game' to begin.\nEnemies spawn from top and\nmove to bottom. Stop them!"
	}, {
		title: "5. ABILITIES",
		desc: "Click ability button (bottom left)\nto use special powers. Each\ncosts crystals but helps a lot!"
	}, {
		title: "6. ENEMY TYPES",
		desc: "Normal: Standard enemies\nFast: Move quickly\nImmune: Can't be slowed\nFlying: Go over towers\nSwarm: Many weak enemies\nBoss: Strong, every 10 waves"
	}, {
		title: "7. WIN CONDITION",
		desc: "Survive all 100 waves to win!\nLose all health and game over.\nEarn crystals by defeating enemies."
	}];
	// Per-section manual positions for title and description
	var tutorialSectionPositions = [
	// 1. PLACING TOWERS
	{
		titleX: 0,
		titleY: -1200,
		descX: 0,
		descY: -1120
	},
	// 2. UPGRADE & SELL
	{
		titleX: 0,
		titleY: -910,
		descX: 0,
		descY: -830
	},
	// 3. TOWER TYPES
	{
		titleX: 0,
		titleY: -590,
		descX: 0,
		descY: -510
	},
	// 4. START WAVES (moved down 50px from type 3)
	{
		titleX: 0,
		titleY: -120,
		descX: 0,
		descY: -40
	},
	// 5. ABILITIES
	{
		titleX: 0,
		titleY: 150,
		descX: 0,
		descY: 230
	},
	// 6. ENEMY TYPES
	{
		titleX: 0,
		titleY: 440,
		descX: 0,
		descY: 520
	},
	// 7. WIN CONDITION (moved down 50px from type 6)
	{
		titleX: 0,
		titleY: 910,
		descX: 0,
		descY: 990
	}];
	// Display tutorial content with manual positions
	for (var i = 0; i < tutorialContent.length; i++) {
		var section = tutorialContent[i];
		var pos = tutorialSectionPositions[i] || {
			titleX: 0,
			titleY: 0,
			descX: 0,
			descY: 60
		};
		// Create a container for each section to ensure proper layering
		var sectionContainer = new Container();
		tutorialScreen.addChild(sectionContainer);
		// Section title - ensure it's added first and positioned correctly
		var sectionTitle = new Text2(section.title, {
			size: 60,
			fill: 0x00ffb3,
			weight: 800
		});
		sectionTitle.anchor.set(0.5, 0); // Anchor at top center
		sectionTitle.x = pos.titleX;
		sectionTitle.y = pos.titleY;
		sectionContainer.addChild(sectionTitle);
		// Section description - add after title to ensure proper layering
		var sectionDesc = new Text2(section.desc, {
			size: 55,
			fill: 0xFFD700,
			weight: 600,
			align: 'center'
		});
		sectionDesc.anchor.set(0.5, 0); // Anchor at top center
		sectionDesc.x = pos.descX;
		sectionDesc.y = pos.descY;
		sectionContainer.addChild(sectionDesc);
	}
	// Add close button using proper Tutorialclosebutton asset
	var closeButton = tutorialScreen.attachAsset('Tutorialclosebutton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeButton.x = 0;
	closeButton.y = tutorialBg.height / 2 - 100;
	closeButton.down = function () {
		LK.getSound('Closebuttonsound1').play();
		hideTutorial();
	};
	// Entrance animation
	tutorialScreen.scaleX = 0.5;
	tutorialScreen.scaleY = 0.5;
	tutorialScreen.alpha = 0;
	tween(tutorialScreen, {
		scaleX: 1,
		scaleY: 1,
		alpha: 1
	}, {
		duration: 300,
		easing: tween.easeOut
	});
}
function hideTutorial() {
	if (!showingTutorial) {
		return;
	}
	showingTutorial = false;
	tween(tutorialScreen, {
		scaleX: 0.5,
		scaleY: 0.5,
		alpha: 0
	}, {
		duration: 300,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			if (tutorialScreen) {
				tutorialScreen.destroy();
				tutorialScreen = null;
			}
		}
	});
}
// Add intro background image to cover the entire game area
var introBackground = game.attachAsset('Introbackground', {
	anchorX: 0,
	anchorY: 0,
	width: 2048,
	height: 2732
});
// Position background at top-left corner
introBackground.x = 0;
introBackground.y = 0;
// Send background to the back
game.addChildAt(introBackground, 0);
// Play intro music immediately when intro starts
LK.playMusic('Intromusic');
// Position buttons vertically below the center of the screen
var buttonCenterX = 2048 / 2;
var buttonSpacing = 280; // Increased vertical spacing between buttons
var startY = 2732 / 2 + 400; // Start position for the first button, to place the group below center
// Add StartButton at the top
var startButton = game.attachAsset('StartButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
startButton.x = buttonCenterX;
startButton.y = startY;
game.addChild(startButton);
// Add Tutorial Button below start button
var tutorialButton = game.attachAsset('Tutorialbutton', {
	anchorX: 0.5,
	anchorY: 0.5
});
tutorialButton.x = buttonCenterX;
tutorialButton.y = startY + buttonSpacing;
game.addChild(tutorialButton);
// Add ScoreButton below tutorial button
var scoreButton = game.attachAsset('ScoreButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
scoreButton.x = buttonCenterX;
scoreButton.y = startY + buttonSpacing * 2;
game.addChild(scoreButton);
// Add SettingButton at the bottom
var settingButton = game.attachAsset('SettingButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
settingButton.x = buttonCenterX;
settingButton.y = startY + buttonSpacing * 3;
game.addChild(settingButton);
// Add game background image (initially hidden)
var gameBackground = game.attachAsset('gamebackground', {
	anchorX: 0,
	anchorY: 0,
	width: 2048,
	height: 2732
});
gameBackground.x = 0;
gameBackground.y = 0;
gameBackground.visible = false;
game.addChildAt(gameBackground, 0);
// Function to start the game
function startGame() {
	showingIntro = false;
	gameStarted = true;
	// Hide intro elements
	introBackground.visible = false;
	startButton.visible = false;
	scoreButton.visible = false;
	settingButton.visible = false;
	tutorialButton.visible = false;
	// Show game elements
	gameBackground.visible = true;
	debugLayer.visible = true;
	towerLayer.visible = true;
	enemyLayer.visible = true;
	crystalIcon.visible = true;
	crystalLabelText.visible = true;
	crystalNumberText.visible = true;
	healthBarContainer.visible = true;
	scoreLabelText.visible = true;
	scoreNumberText.visible = true;
	waveIndicator.visible = true;
	nextWaveButtonContainer.visible = true;
	towerPreview.visible = false;
	// Stop intro music and play game music only if music is on
	LK.stopMusic();
	// Add a small delay to ensure intro music is fully stopped before starting new music
	LK.setTimeout(function () {
		if (musicOn) {
			LK.playMusic('Gamemusic1');
		}
	}, 100);
}
// Add click handlers for buttons
startButton.down = function () {
	if (showingTutorial) {
		return;
	}
	LK.getSound('Startbuttonsound1').play();
	startGame();
};
scoreButton.down = function () {
	if (showingTutorial) {
		return;
	}
	showHighScores();
};
settingButton.down = function () {
	if (showingIntro && !showingScores && !showingTutorial) {
		showSettings();
	}
};
tutorialButton.down = function () {
	if (showingIntro && !showingScores && !showingSettings && !showingTutorial) {
		showTutorial();
	}
};
var isHidingUpgradeMenu = false;
function hideUpgradeMenu(menu) {
	if (isHidingUpgradeMenu) {
		return;
	}
	isHidingUpgradeMenu = true;
	// Get menu background height from the asset
	var menuHeight = 500; // Default fallback
	if (menu.children[0]) {
		menuHeight = menu.children[0].height;
	}
	tween(menu, {
		y: 2732 + menuHeight / 2
	}, {
		duration: 150,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			menu.destroy();
			isHidingUpgradeMenu = false;
		}
	});
}
var CELL_SIZE = 76;
var pathId = 1;
var maxScore = 0;
var enemies = [];
var towers = [];
var bullets = [];
var defenses = [];
var selectedTower = null;
var crystals = 500;
var lives = 100;
var score = 0;
var currentWave = 0;
var lastWave = 0;
var totalWaves = 100;
var waveTimer = 0;
var waveInProgress = false;
var waveSpawned = false;
var nextWaveTime = 12000 / 2;
var sourceTower = null;
var enemiesToSpawn = 10; // Default number of enemies per wave
var ships = [];
var lastShip3Spawn = 0;
var ship3SpawnInterval = 2400; // 40 seconds at 60 FPS
var crystalLabelText = new Text2('Crystal: ', {
	size: 60,
	fill: 0xff0080,
	weight: 800
});
crystalLabelText.anchor.set(1, 0.9);
var crystalNumberText = new Text2(crystals.toString(), {
	size: 60,
	fill: 0x00ffb3,
	weight: 800
});
crystalNumberText.anchor.set(0, 0.9);
var healthBarBG = LK.getAsset('healthBarOutline', {
	anchorX: 0.5,
	anchorY: 1
});
var healthBarFill = LK.getAsset('gameHealthBar', {
	anchorX: 0,
	anchorY: 1.1
});
healthBarFill.x = -healthBarBG.width / 2 + (healthBarBG.width - healthBarFill.width) / 2;
healthBarFill.originalWidth = healthBarFill.width;
var healthText = new Text2('100/100', {
	size: 50,
	fill: 0x00ffb3,
	weight: 800
});
healthText.anchor.set(0.5, 0.9);
var healthBarContainer = new Container();
healthBarContainer.addChild(healthBarBG);
healthBarContainer.addChild(healthBarFill);
healthBarContainer.addChild(healthText);
var scoreLabelText = new Text2('Score: ', {
	size: 60,
	fill: 0xff0080,
	weight: 800
});
scoreLabelText.anchor.set(1, 0.9);
var scoreNumberText = new Text2(score.toString(), {
	size: 60,
	fill: 0x00ffb3,
	weight: 800
});
scoreNumberText.anchor.set(0, 0.9);
var topMargin = 50;
var centerX = 2048 / 2;
var spacing = 350;
var crystalIcon = LK.getAsset('Crystal', {
	anchorX: 1.0,
	anchorY: 0.9,
	scaleX: 0.4,
	scaleY: 0.6
});
LK.gui.top.addChild(crystalIcon);
LK.gui.top.addChild(crystalLabelText);
LK.gui.top.addChild(crystalNumberText);
LK.gui.top.addChild(healthBarContainer);
LK.gui.top.addChild(scoreLabelText);
LK.gui.top.addChild(scoreNumberText);
// Hide UI elements during intro
crystalIcon.visible = false;
crystalLabelText.visible = false;
crystalNumberText.visible = false;
healthBarContainer.visible = false;
scoreLabelText.visible = false;
scoreNumberText.visible = false;
healthBarContainer.x = 0;
healthBarContainer.y = topMargin;
// Position Crystal UI elements
var crystalTextX = -380;
crystalLabelText.x = crystalTextX;
crystalLabelText.y = topMargin;
crystalNumberText.x = crystalTextX;
crystalNumberText.y = topMargin;
crystalIcon.x = crystalTextX - 250;
crystalIcon.y = topMargin;
// Position Score UI elements
var scoreTextX = 450;
scoreLabelText.x = scoreTextX;
scoreLabelText.y = topMargin;
scoreNumberText.x = scoreTextX;
scoreNumberText.y = topMargin;
// Add mute button to top right corner with music state tracking
var musicOn = true; // Track current music state
var muteButton = LK.getAsset('Mutebutton1', {
	anchorX: 1.0,
	anchorY: -0.1,
	width: 100,
	height: 100
});
muteButton.x = 2048 - 50; // 50px from right edge
muteButton.y = 0; // 0px from top edge
game.addChild(muteButton);
// Add mute button click handler
muteButton.down = function () {
	musicOn = !musicOn; // Toggle music state
	if (musicOn) {
		// Music is now on - show Mutebutton1 and resume music
		game.removeChild(muteButton);
		muteButton = LK.getAsset('Mutebutton1', {
			anchorX: 1.0,
			anchorY: -0.1,
			width: 100,
			height: 100
		});
		muteButton.x = 2048 - 50;
		muteButton.y = 0;
		game.addChild(muteButton);
		// Animate button appearance
		muteButton.alpha = 0;
		tween(muteButton, {
			alpha: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		// Resume appropriate music based on game state
		if (showingIntro) {
			LK.playMusic('Intromusic');
		} else if (gameStarted) {
			// Resume game music based on current wave
			var musicToPlay;
			if (currentWave > 0 && currentWave % 10 === 0) {
				// isBossWave
				var bossMusics = ['Bossmusic1', 'Bossmusic2', 'Bossmusic3', 'Bossmusic4', 'Bossmusic5'];
				var musicIndex = (currentWave / 10 - 1) % bossMusics.length;
				musicToPlay = bossMusics[musicIndex];
			} else {
				// is normal wave, or wave 0
				var gameMusics = ['Gamemusic1', 'Gamemusic2', 'gamemusic3', 'Gamemusic4', 'Gamemusic5'];
				var musicIndex = Math.floor(currentWave / 10) % gameMusics.length;
				musicToPlay = gameMusics[musicIndex];
			}
			LK.playMusic(musicToPlay);
		}
	} else {
		// Music is now off - show Mutebutton2 and stop music
		game.removeChild(muteButton);
		muteButton = LK.getAsset('Mutebutton2', {
			anchorX: 1.0,
			anchorY: -0.1,
			width: 100,
			height: 100
		});
		muteButton.x = 2048 - 50;
		muteButton.y = 0;
		game.addChild(muteButton);
		// Animate button appearance
		muteButton.alpha = 0;
		tween(muteButton, {
			alpha: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		// Stop all music
		LK.stopMusic();
	}
	// Re-assign the click handler to the new button
	muteButton.down = arguments.callee;
};
function updateUI() {
	crystalNumberText.setText(crystals.toString());
	healthText.setText(lives + '/100');
	// Update health bar fill width based on current lives (assuming max 100 lives)
	var healthPercentage = lives / 100;
	healthBarFill.width = healthBarFill.originalWidth * healthPercentage;
	scoreNumberText.setText(score.toString());
}
function setCrystals(value) {
	crystals = value;
	updateUI();
}
var debugLayer = new Container();
var towerLayer = new Container();
// Create three separate layers for enemy hierarchy
var enemyLayerBottom = new Container(); // For normal enemies
var enemyLayerMiddle = new Container(); // For shadows
var enemyLayerTop = new Container(); // For flying enemies
var enemyLayer = new Container(); // Main container to hold all enemy layers
// Add layers in correct order (bottom first, then middle for shadows, then top)
enemyLayer.addChild(enemyLayerBottom);
enemyLayer.addChild(enemyLayerMiddle);
enemyLayer.addChild(enemyLayerTop);
var grid = new Grid(24, 29 + 6);
grid.x = 150;
grid.y = 200 - CELL_SIZE * 4;
grid.pathFind();
grid.renderDebug();
debugLayer.addChild(grid);
game.addChild(debugLayer);
game.addChild(towerLayer);
game.addChild(enemyLayer);
// Initialize weather system
var weatherSystem = new WeatherSystem();
game.addChild(weatherSystem);
brightnessOverlay = LK.getAsset('cell', {
	width: 2048,
	height: 2732
});
brightnessOverlay.tint = 0x000000;
brightnessOverlay.alpha = 0;
brightnessOverlay.x = 0;
brightnessOverlay.y = 0;
game.addChild(brightnessOverlay);
// Hide game elements during intro
debugLayer.visible = false;
towerLayer.visible = false;
enemyLayer.visible = false;
var offset = 0;
var towerPreview = new TowerPreview();
game.addChild(towerPreview);
towerPreview.visible = false;
var isDragging = false;
function wouldBlockPath(gridX, gridY) {
	var cells = [];
	for (var i = 0; i < 2; i++) {
		for (var j = 0; j < 2; j++) {
			var cell = grid.getCell(gridX + i, gridY + j);
			if (cell) {
				cells.push({
					cell: cell,
					originalType: cell.type
				});
				cell.type = 1;
			}
		}
	}
	var blocked = grid.pathFind();
	for (var i = 0; i < cells.length; i++) {
		cells[i].cell.type = cells[i].originalType;
	}
	grid.pathFind();
	grid.renderDebug();
	return blocked;
}
function getTowerCost(towerType) {
	var cost = 10;
	switch (towerType) {
		case 'rifle':
			cost = 20;
			break;
		case 'flame':
			cost = 60;
			break;
		case 'Rocket':
			cost = 80;
			break;
		case 'gumbomb':
			cost = 30;
			break;
		case 'ToxinBomb':
			cost = 100;
			break;
	}
	return cost;
}
function getTowerSellValue(totalValue) {
	return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.8) : totalValue;
}
function placeTower(gridX, gridY, towerType) {
	var towerCost = getTowerCost(towerType);
	if (crystals >= towerCost) {
		var tower = new Tower(towerType || 'cannon');
		tower.placeOnGrid(gridX, gridY);
		towerLayer.addChild(tower);
		towers.push(tower);
		setCrystals(crystals - towerCost);
		grid.pathFind();
		grid.renderDebug();
		return true;
	} else {
		var notification = game.addChild(new Notification("Not enough crystals!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		return false;
	}
}
game.down = function (x, y, obj) {
	// Handle tutorial menu during intro
	if (showingIntro && showingTutorial) {
		// Check if click is outside tutorial area
		var menuLeft = 2048 / 2 - 900;
		var menuRight = 2048 / 2 + 900;
		var menuTop = 2732 / 2 - 1200;
		var menuBottom = 2732 / 2 + 1200;
		if (x < menuLeft || x > menuRight || y < menuTop || y > menuBottom) {
			hideTutorial();
		}
		return;
	}
	// Handle high scores menu during intro
	if (showingIntro && showingScores) {
		// Check if click is outside score menu area
		var menuLeft = 2048 / 2 - 800;
		var menuRight = 2048 / 2 + 800;
		var menuTop = 2732 / 2 - 1100;
		var menuBottom = 2732 / 2 + 1100;
		if (x < menuLeft || x > menuRight || y < menuTop || y > menuBottom) {
			hideHighScores();
		}
		return;
	}
	// Don't process game input during intro
	if (showingIntro || !gameStarted) {
		return;
	}
	var upgradeMenuVisible = game.children.some(function (child) {
		return child instanceof UpgradeMenu;
	});
	if (upgradeMenuVisible) {
		return;
	}
	for (var i = 0; i < sourceTowers.length; i++) {
		var tower = sourceTowers[i];
		if (x >= tower.x - tower.width / 2 && x <= tower.x + tower.width / 2 && y >= tower.y - tower.height / 2 && y <= tower.y + tower.height / 2) {
			if (!canPlaceTowers) {
				return;
			}
			towerPreview.visible = true;
			isDragging = true;
			towerPreview.towerType = tower.towerType;
			towerPreview.updateAppearance();
			// Apply the same offset as in move handler to ensure consistency when starting drag
			towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
			break;
		}
	}
};
game.move = function (x, y, obj) {
	if (isDraggingMusicButton) {
		if (settingMenu) {
			var musicBar = null;
			var musicButton = null;
			var musicPercentage = null;
			for (var i = 0; i < settingMenu.children.length; i++) {
				if (settingMenu.children[i].name === "musicBar") {
					musicBar = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "musicButton") {
					musicButton = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "musicPercentage") {
					musicPercentage = settingMenu.children[i];
				}
			}
			if (musicBar && musicButton) {
				var localPos = settingMenu.toLocal({
					x: x,
					y: y
				});
				var minX = musicBar.x + musicButton.width / 2;
				var maxX = musicBar.x + musicBar.width - musicButton.width / 2;
				var newX = Math.max(minX, Math.min(maxX, localPos.x));
				musicButton.x = newX;
				var trackWidth = maxX - minX;
				var percentage = trackWidth > 0 ? (newX - minX) / trackWidth : 0;
				// Store current music volume and apply to currently playing music
				if (typeof game.musicVolume === 'undefined') {
					game.musicVolume = 1.0;
				}
				game.musicVolume = percentage;
				// Update percentage display
				if (musicPercentage) {
					musicPercentage.setText(Math.round(percentage * 100) + "%");
				}
				// Stop current music and restart with new volume
				LK.stopMusic();
				if (musicOn && percentage > 0) {
					// Determine which music should be playing and restart with new volume
					if (showingIntro) {
						LK.playMusic('Intromusic', {
							fade: {
								start: 0,
								end: percentage,
								duration: 100
							}
						});
					} else if (gameStarted) {
						// Resume game music based on current wave with new volume
						var musicToPlay;
						if (currentWave > 0 && currentWave % 10 === 0) {
							// isBossWave
							var bossMusics = ['Bossmusic1', 'Bossmusic2', 'Bossmusic3', 'Bossmusic4', 'Bossmusic5'];
							var musicIndex = (currentWave / 10 - 1) % bossMusics.length;
							musicToPlay = bossMusics[musicIndex];
						} else {
							// is normal wave, or wave 0
							var gameMusics = ['Gamemusic1', 'Gamemusic2', 'gamemusic3', 'Gamemusic4', 'Gamemusic5'];
							var musicIndex = Math.floor(currentWave / 10) % gameMusics.length;
							musicToPlay = gameMusics[musicIndex];
						}
						LK.playMusic(musicToPlay, {
							fade: {
								start: 0,
								end: percentage,
								duration: 100
							}
						});
					}
				}
			}
		}
		return;
	}
	if (isDraggingSoundButton) {
		if (settingMenu) {
			var soundBar = null;
			var soundButton = null;
			var soundPercentage = null;
			for (var i = 0; i < settingMenu.children.length; i++) {
				if (settingMenu.children[i].name === "soundBar") {
					soundBar = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "soundButton") {
					soundButton = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "soundPercentage") {
					soundPercentage = settingMenu.children[i];
				}
			}
			if (soundBar && soundButton) {
				var localPos = settingMenu.toLocal({
					x: x,
					y: y
				});
				var minX = soundBar.x + soundButton.width / 2;
				var maxX = soundBar.x + soundBar.width - soundButton.width / 2;
				var newX = Math.max(minX, Math.min(maxX, localPos.x));
				soundButton.x = newX;
				var trackWidth = maxX - minX;
				var percentage = trackWidth > 0 ? (newX - minX) / trackWidth : 0;
				// Update the global sound volume
				game.soundVolume = percentage;
				// Save sound volume to storage
				storage.soundVolume = percentage;
				// Update percentage display
				if (soundPercentage) {
					soundPercentage.setText(Math.round(percentage * 100) + "%");
				}
				// Play a test sound when dragging to give immediate feedback
				if (percentage > 0) {
					game.playSoundWithVolume('Bulletsound');
				}
			}
		}
		return;
	}
	if (isDraggingLightButton) {
		if (settingMenu) {
			var lightBar = null;
			var lightButton = null;
			var lightPercentage = null;
			for (var i = 0; i < settingMenu.children.length; i++) {
				if (settingMenu.children[i].name === "lightBar") {
					lightBar = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "lightButton") {
					lightButton = settingMenu.children[i];
				}
				if (settingMenu.children[i].name === "lightPercentage") {
					lightPercentage = settingMenu.children[i];
				}
			}
			if (lightBar && lightButton) {
				var localPos = settingMenu.toLocal({
					x: x,
					y: y
				});
				var minX = lightBar.x + lightButton.width / 2;
				var maxX = lightBar.x + lightBar.width - lightButton.width / 2;
				var newX = Math.max(minX, Math.min(maxX, localPos.x));
				lightButton.x = newX;
				var trackWidth = maxX - minX;
				var percentage = trackWidth > 0 ? (newX - minX) / trackWidth : 0;
				if (brightnessOverlay) {
					brightnessOverlay.alpha = percentage * 0.7; // Max dim alpha 0.7
				}
				// Update percentage display
				if (lightPercentage) {
					lightPercentage.setText(Math.round(percentage * 100) + "%");
				}
			}
		}
		return;
	}
	// Don't process game input during intro
	if (showingIntro || !gameStarted) {
		return;
	}
	if (isDragging) {
		// Shift the y position upward by 1.5 tiles to show preview above finger
		towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
	}
};
game.up = function (x, y, obj) {
	if (isDraggingLightButton) {
		isDraggingLightButton = false;
		return;
	}
	if (isDraggingMusicButton) {
		isDraggingMusicButton = false;
		return;
	}
	if (isDraggingSoundButton) {
		isDraggingSoundButton = false;
		return;
	}
	// Don't process game input during intro
	if (showingIntro || !gameStarted) {
		return;
	}
	var clickedOnTower = false;
	for (var i = 0; i < towers.length; i++) {
		var tower = towers[i];
		var towerLeft = tower.x - tower.width / 2;
		var towerRight = tower.x + tower.width / 2;
		var towerTop = tower.y - tower.height / 2;
		var towerBottom = tower.y + tower.height / 2;
		if (x >= towerLeft && x <= towerRight && y >= towerTop && y <= towerBottom) {
			clickedOnTower = true;
			break;
		}
	}
	var upgradeMenus = game.children.filter(function (child) {
		return child instanceof UpgradeMenu;
	});
	if (upgradeMenus.length > 0 && !isDragging && !clickedOnTower) {
		var clickedOnMenu = false;
		for (var i = 0; i < upgradeMenus.length; i++) {
			var menu = upgradeMenus[i];
			var menuWidth = 2048;
			var menuHeight = 450;
			var menuLeft = menu.x - menuWidth / 2;
			var menuRight = menu.x + menuWidth / 2;
			var menuTop = menu.y - menuHeight / 2;
			var menuBottom = menu.y + menuHeight / 2;
			if (x >= menuLeft && x <= menuRight && y >= menuTop && y <= menuBottom) {
				clickedOnMenu = true;
				break;
			}
		}
		if (!clickedOnMenu) {
			for (var i = 0; i < upgradeMenus.length; i++) {
				var menu = upgradeMenus[i];
				hideUpgradeMenu(menu);
			}
			for (var i = game.children.length - 1; i >= 0; i--) {
				if (game.children[i].isTowerRange) {
					game.removeChild(game.children[i]);
				}
			}
			selectedTower = null;
			grid.renderDebug();
		}
	}
	if (isDragging) {
		isDragging = false;
		if (towerPreview.canPlace) {
			if (!wouldBlockPath(towerPreview.gridX, towerPreview.gridY)) {
				placeTower(towerPreview.gridX, towerPreview.gridY, towerPreview.towerType);
			} else {
				var notification = game.addChild(new Notification("Tower would block the path!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
			}
		} else if (towerPreview.blockedByEnemy) {
			var notification = game.addChild(new Notification("Cannot build: Enemy in the way!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
		} else if (towerPreview.visible) {
			var notification = game.addChild(new Notification("Cannot build here!"));
			notification.x = 2048 / 2;
			notification.y = grid.y + grid.cells[0].length * CELL_SIZE - CELL_SIZE * 6;
		}
		towerPreview.visible = false;
		if (isDragging) {
			var upgradeMenus = game.children.filter(function (child) {
				return child instanceof UpgradeMenu;
			});
			for (var i = 0; i < upgradeMenus.length; i++) {
				upgradeMenus[i].destroy();
			}
		}
	}
};
var waveIndicator = new WaveIndicator();
waveIndicator.x = 2048 / 2;
waveIndicator.y = 2732 - 80;
waveIndicator.visible = false;
game.addChild(waveIndicator);
var nextWaveButtonContainer = new Container();
var nextWaveButton = new NextWaveButton();
nextWaveButton.x = 2048 - 200;
nextWaveButton.y = 2732 - 100 + 20;
nextWaveButtonContainer.addChild(nextWaveButton);
var inGameSettingButton = nextWaveButtonContainer.attachAsset('SettingButton', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 0.6,
	scaleY: 0.6
});
var abilityButton = nextWaveButtonContainer.attachAsset('AbilityButton', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 0.6,
	scaleY: 0.6
});
abilityButton.x = 80; // Move 30px to the right
abilityButton.y = 2550 - 150 + 30; // Move 230px down 
abilityButton.down = function () {
	if (!gameStarted || showingIntro || !canStartWaves) {
		var notification = game.addChild(new Notification("Cannot use abilities\nuntil game starts!"));
		return;
	}
	LK.getSound('Abilitybuttonsound1').play();
	showAbilities();
};
inGameSettingButton.x = 2048 - 70; // Move 50px further to the right 
inGameSettingButton.y = 2420;
inGameSettingButton.down = function () {
	showSettings();
};
nextWaveButtonContainer.visible = false;
game.addChild(nextWaveButtonContainer);
var towerTypes = ['cannon', 'rifle', 'flame', 'Rocket', 'gumbomb', 'ToxinBomb'];
var sourceTowers = [];
var towerSpacing = 300; // Increase spacing for larger towers
var startX = 2048 / 2 - towerTypes.length * towerSpacing / 2 + towerSpacing / 2;
var towerY = 2732 - CELL_SIZE * 3 - 90;
for (var i = 0; i < towerTypes.length; i++) {
	var tower = new SourceTower(towerTypes[i]);
	tower.x = startX + i * towerSpacing;
	tower.y = towerY;
	towerLayer.addChild(tower);
	sourceTowers.push(tower);
}
sourceTower = null;
enemiesToSpawn = 10;
game.update = function () {
	// Only run game logic if the game has started
	if (!gameStarted || showingIntro) {
		return;
	}
	// Add static flag to track if intro sequence has been shown
	if (typeof game.introSequenceShown === 'undefined') {
		game.introSequenceShown = false;
	}
	if (!game.introSequenceShown) {
		game.introSequenceShown = true;
		girlCharacter = new SpeakingGirl();
		game.addChild(girlCharacter);
		// Spawn tablet after girl with slight delay
		LK.setTimeout(function () {
			var tablet = new Tablet();
			game.addChild(tablet);
		}, 500); // 500ms delay after girl spawns
	}
	// Weather system update
	if (weatherSystem) {
		weatherSystem.update();
	}
	if (currentWave !== lastWave) {
		if (musicOn && (typeof game.musicVolume === 'undefined' || game.musicVolume > 0)) {
			// Only play music if music is enabled and volume is greater than 0
			var musicVolume = typeof game.musicVolume !== 'undefined' ? game.musicVolume : 1.0;
			var musicToPlay = null;
			if (currentWave > 0 && currentWave % 10 === 0) {
				// isBossWave
				var bossMusics = ['Bossmusic1', 'Bossmusic2', 'Bossmusic3', 'Bossmusic4', 'Bossmusic5'];
				var musicIndex = (currentWave / 10 - 1) % bossMusics.length;
				musicToPlay = bossMusics[musicIndex];
			} else if (currentWave > 1 && (currentWave - 1) % 10 === 0) {
				// isPostBossWave
				var gameMusics = ['Gamemusic1', 'Gamemusic2', 'gamemusic3', 'Gamemusic4', 'Gamemusic5'];
				var musicIndex = Math.floor((currentWave - 1) / 10) % gameMusics.length;
				musicToPlay = gameMusics[musicIndex];
			}
			if (musicToPlay) {
				LK.playMusic(musicToPlay, {
					fade: {
						start: 0,
						end: musicVolume,
						duration: 100
					}
				});
			}
		}
		lastWave = currentWave;
	}
	if (waveInProgress) {
		if (!waveSpawned) {
			waveSpawned = true;
			// Get wave type and enemy count from the wave indicator
			var waveType = waveIndicator.getWaveType(currentWave);
			var enemyCount = waveIndicator.getEnemyCount(currentWave);
			// Check if this is a boss wave
			var isBossWave = currentWave % 10 === 0 && currentWave > 0;
			if (isBossWave && waveType !== 'swarm') {
				// Boss waves have just 1 enemy regardless of what the wave indicator says
				enemyCount = 1;
				// Show boss announcement
				var notification = game.addChild(new Notification("⚠️ BOSS WAVE! ⚠️"));
				notification.x = 2048 / 2;
				notification.y = 2732 / 2;
			}
			// Spawn the appropriate number of enemies
			for (var i = 0; i < enemyCount; i++) {
				var enemy = new Enemy(waveType);
				// Add enemy to the appropriate layer based on type
				if (enemy.isFlying) {
					// Add flying enemy to the top layer
					enemyLayerTop.addChild(enemy);
					// If it's a flying enemy, add its shadow to the middle layer
					if (enemy.shadow) {
						enemyLayerMiddle.addChild(enemy.shadow);
					}
				} else {
					// Add normal/ground enemies to the bottom layer
					enemyLayerBottom.addChild(enemy);
				}
				// Enemy scaling is now handled in Enemy constructor based on currentWave
				// This ensures consistent scaling every 5 waves for all enemy types
				// All enemy types now spawn in the middle 6 tiles at the top spacing
				var gridWidth = 24;
				var midPoint = Math.floor(gridWidth / 2); // 12
				// Find a column that isn't occupied by another enemy that's not yet in view
				var availableColumns = [];
				for (var col = midPoint - 3; col < midPoint + 3; col++) {
					var columnOccupied = false;
					// Check if any enemy is already in this column but not yet in view
					for (var e = 0; e < enemies.length; e++) {
						if (enemies[e].cellX === col && enemies[e].currentCellY < 4) {
							columnOccupied = true;
							break;
						}
					}
					if (!columnOccupied) {
						availableColumns.push(col);
					}
				}
				// If all columns are occupied, use original random method
				var spawnX;
				if (availableColumns.length > 0) {
					// Choose a random unoccupied column
					spawnX = availableColumns[Math.floor(Math.random() * availableColumns.length)];
				} else {
					// Fallback to random if all columns are occupied
					spawnX = midPoint - 3 + Math.floor(Math.random() * 6); // x from 9 to 14
				}
				var spawnY = -1 - Math.random() * 5; // Random distance above the grid for spreading
				enemy.cellX = spawnX;
				enemy.cellY = 5; // Position after entry
				enemy.currentCellX = spawnX;
				enemy.currentCellY = spawnY;
				enemy.waveNumber = currentWave;
				enemies.push(enemy);
			}
		}
		var currentWaveEnemiesRemaining = false;
		for (var i = 0; i < enemies.length; i++) {
			if (enemies[i].waveNumber === currentWave) {
				currentWaveEnemiesRemaining = true;
				break;
			}
		}
		if (waveSpawned && !currentWaveEnemiesRemaining) {
			waveInProgress = false;
			waveSpawned = false;
		}
	}
	for (var a = enemies.length - 1; a >= 0; a--) {
		var enemy = enemies[a];
		if (enemy.health <= 0) {
			for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
				var bullet = enemy.bulletsTargetingThis[i];
				bullet.targetEnemy = null;
			}
			// Boss enemies give more crystals and score - increased rewards
			var crystalsEarned = enemy.isBoss ? Math.floor(25 + (enemy.waveNumber - 1) * 1.5) : Math.floor(3 + (enemy.waveNumber - 1) * 0.4);
			var crystalIndicator = new CrystalIndicator(crystalsEarned, enemy.x, enemy.y);
			game.addChild(crystalIndicator);
			setCrystals(crystals + crystalsEarned);
			// Give more score for defeating a boss
			var scoreValue = enemy.isBoss ? 100 : 5;
			score += scoreValue;
			// Add a notification for boss defeat
			if (enemy.isBoss) {
				var notification = game.addChild(new Notification("Boss defeated! +" + crystalsEarned + " crystal!"));
				notification.x = 2048 / 2;
				notification.y = 2732 / 2;
			}
			updateUI();
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			continue;
		}
		if (grid.updateEnemy(enemy)) {
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			lives = Math.max(0, lives - 1);
			updateUI();
			if (lives <= 0) {
				// Save high score before showing game over
				addHighScore(score);
				LK.showGameOver();
			}
		}
	}
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (!bullets[i].parent) {
			if (bullets[i].targetEnemy) {
				var targetEnemy = bullets[i].targetEnemy;
				var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
				if (bulletIndex !== -1) {
					targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
				}
			}
			bullets.splice(i, 1);
		}
	}
	if (towerPreview.visible) {
		towerPreview.checkPlacement();
	}
	if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) {
		// Save high score before showing you win
		addHighScore(score);
		LK.showYouWin();
	}
	// Ship spawning logic
	// Spawn ship1 or ship2 randomly, on average every 20 seconds
	if (Math.random() < 1 / 1200) {
		// 1200 ticks = 20 seconds at 60 FPS
		// Randomly select ship type (1 or 2)
		var shipType = Math.floor(Math.random() * 2) + 1;
		var ship = new Ship(shipType);
		// Add ship to game at a lower layer so it appears behind game elements
		game.addChildAt(ship, 1); // Just above background
		ships.push(ship);
	}
	// Spawn ship3 every 40 seconds
	if (LK.ticks - lastShip3Spawn >= ship3SpawnInterval) {
		lastShip3Spawn = LK.ticks;
		var ship = new Ship(3);
		// Add ship to game at a lower layer so it appears behind game elements
		game.addChildAt(ship, 1); // Just above background
		ships.push(ship);
	}
	// Update and cleanup ships
	for (var i = ships.length - 1; i >= 0; i--) {
		if (!ships[i].parent) {
			ships.splice(i, 1);
		}
	}
};
 
 Pack top square of towers facing the screen to use it as a grid. future. seen from above. HD colors.
 Pack top square of tower facing the screen to use it as a grid. future. seen from above. HD colors.
 
 
 
 
 
 
 
 
 
 
 
 different cyber flying enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 different cyber electro flying enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 different cyborg electro enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 
 
 different cyber small enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 different cyber spider small enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 different cyber big Robot enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 different big cyber snake Robot enemy from the front side facing camera. HD colors. separated In-Game asset. 2d. High contrast. No shadows
 Fullscreen modern App Store landscape banner, 16:9, high definition, HD colors. for a future game of tower defense with cyberpunk and abstract style titled "Cyber Towers" without description "Defend the exit way in final path from different enemies Robots, cyborgs, cyber robot snakes, cyber spiders, flying cyber robots, by placing towers each tower have different weapon then the others, cannon, rifle, flame, rocket, gum bomb, toxin bomb. don't let them pass through the path!". with text on the middle of the banner "Cyber Towers"!
 
 
 
 
 
 
 Police cyber flying Ship assets without 'police' text, Cyberpunk, Abstract, Futuer, HD colors, Different colors. Horizontal. seen from a side. In-Game asset. 2d. High contrast. No shadows
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Ability icon 'healing' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'weakness curse' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Lighting storm' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Dust storm' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Water flood' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Fire ring' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Ice freeze' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Shield Boost' . cyberpunk. abstract. Futuer. different colors. HD colors
 Ability icon 'Ultimate Storm' . cyberpunk. abstract. Futuer. different colors. HD colors
 
 placmentsound1
Sound effect
placmentsound2
Sound effect
placmentsound3
Sound effect
placmentsound4
Sound effect
placmentsound5
Sound effect
placmentsound6
Sound effect
Intromusic
Music
Bulletsound
Sound effect
Riflebulletsound
Sound effect
Flamesound
Sound effect
Rocketsound
Sound effect
Gumbombsound
Sound effect
Gamemusic2
Music
gamemusic3
Music
Gamemusic4
Music
Gamemusic5
Music
Bossmusic1
Music
Bossmusic2
Music
Bossmusic3
Music
Bossmusic4
Music
Bossmusic5
Music
Ship1sound
Sound effect
Ship2sound
Sound effect
Ship3sound
Sound effect
Gamemusic1
Music
Toxinbombsound
Sound effect
Closebuttonsound1
Sound effect
Useabilitysound1
Sound effect
Abilitybuttonsound1
Sound effect
Startbuttonsound1
Sound effect
Bigrobots_damage_sound1
Sound effect
Cybersnake_damage_sound1
Sound effect
Cyborg_Damage_sound1
Sound effect
Electro_Damage_sound1
Sound effect
Eye_Damage_sound1
Sound effect
Firo_Damage_sound1
Sound effect
Robot_Damage_sound1
Sound effect