/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
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;
		}
		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
			self.targetEnemy.health -= self.damage;
			if (self.targetEnemy.health <= 0) {
				self.targetEnemy.health = 0;
			} else {
				self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70;
			}
			// Apply special effects based on bullet type
			if (self.type === 'splash') {
				// Create visual splash effect
				var splashEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'splash');
				game.addChild(splashEffect);
				// Splash damage to nearby enemies
				var splashRadius = CELL_SIZE * 1.5;
				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 {
								otherEnemy.healthBar.width = otherEnemy.health / otherEnemy.maxHealth * 70;
							}
						}
					}
				}
			} else if (self.type === 'slow') {
				// Prevent slow effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create visual slow effect
					var slowEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'slow');
					game.addChild(slowEffect);
					// Apply slow effect
					// Make slow percentage scale with tower level (default 50%, up to 80% at max level)
					var slowPct = 0.5;
					if (self.sourceTowerLevel !== undefined) {
						// Scale: 50% at level 1, 60% at 2, 65% at 3, 70% at 4, 75% at 5, 80% at 6
						var slowLevels = [0.5, 0.6, 0.65, 0.7, 0.75, 0.8];
						var idx = Math.max(0, Math.min(5, self.sourceTowerLevel - 1));
						slowPct = slowLevels[idx];
					}
					if (!self.targetEnemy.slowed) {
						self.targetEnemy.originalSpeed = self.targetEnemy.speed;
						self.targetEnemy.speed *= 1 - slowPct; // Slow by X%
						self.targetEnemy.slowed = true;
						self.targetEnemy.slowDuration = 180; // 3 seconds at 60 FPS
					} else {
						self.targetEnemy.slowDuration = 180; // Reset duration
					}
				}
			} else if (self.type === 'poison') {
				// Prevent poison effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create visual poison effect
					var poisonEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'poison');
					game.addChild(poisonEffect);
					// Apply poison 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
				}
			} else if (self.type === 'sniper') {
				// Create visual critical hit effect for sniper
				var sniperEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'sniper');
				game.addChild(sniperEffect);
			}
			self.destroy();
		} else {
			var angle = Math.atan2(dy, dx);
			self.x += Math.cos(angle) * self.speed;
			self.y += Math.sin(angle) * self.speed;
		}
	};
	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 = [];
	var numberLabel = new Text2('0', {
		size: 30,
		fill: 0xFFFFFF,
		weight: 800
	});
	numberLabel.anchor.set(.5, .5);
	self.addChild(numberLabel);
	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();
						numberLabel.setText("-");
						cellGraphics.tint = 0x880000;
						return;
					}
					numberLabel.visible = true;
					var tint = Math.floor(data.score / maxScore * 0x88);
					var towerInRangeHighlight = false;
					if (selectedTower && data.towersInRange && data.towersInRange.indexOf(selectedTower) !== -1) {
						towerInRangeHighlight = true;
						cellGraphics.tint = 0x0088ff;
					} else {
						cellGraphics.tint = 0x88 - tint << 8 | tint;
					}
					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;
						var angle = Math.atan2(oy, ox);
						if (!debugArrows[a]) {
							debugArrows[a] = LK.getAsset('arrow', {
								anchorX: -.5,
								anchorY: 0.5
							});
							debugArrows[a].alpha = .5;
							self.addChildAt(debugArrows[a], 1);
						}
						debugArrows[a].rotation = angle;
					}
					break;
				}
			case 1:
				{
					self.removeArrows();
					cellGraphics.tint = 0xaaaaaa;
					numberLabel.visible = false;
					break;
				}
			case 3:
				{
					self.removeArrows();
					cellGraphics.tint = 0x008800;
					numberLabel.visible = false;
					break;
				}
		}
		numberLabel.setText(Math.floor(data.score / 1000) / 10);
	};
});
// 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 'poison':
			effectGraphics.tint = 0x00FFAA;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'sniper':
			effectGraphics.tint = 0xFF5500;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'missile_explosion':
			effectGraphics.tint = 0xFF0000;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 3;
			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
	switch (self.type) {
		case 'fast':
			self.speed *= 2; // Soviet fast tanks (T-34)
			self.maxHealth = 100;
			break;
		case 'immune':
			self.isImmune = true; // Soviet heavy tanks (KV-1)
			self.maxHealth = 80;
			break;
		case 'flying':
			self.isFlying = true; // Soviet aircraft (MiG-21)
			self.maxHealth = 80;
			break;
		case 'swarm':
			self.maxHealth = 50; // Soviet infantry squads
			break;
		case 'geese':
			self.isFlying = true; // Geese can fly
			self.maxHealth = 40; // Slightly weaker than normal
			self.speed *= 1.3; // Faster than normal enemies
			break;
		case 'normal':
		default:
			// Soviet medium tanks (T-55)
			break;
	}
	if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') {
		self.isBoss = true;
		// Boss enemies have 20x health and are larger
		self.maxHealth *= 20;
		// Slower speed for bosses
		self.speed = self.speed * 0.7;
	}
	self.health = self.maxHealth;
	// Get appropriate asset for this enemy type
	var assetId = 'enemy';
	if (self.type !== 'normal') {
		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
		var shadowGraphics = self.shadow.attachAsset(assetId || 'enemy', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow effect
		shadowGraphics.tint = 0x000000; // Black shadow
		shadowGraphics.alpha = 0.4; // 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('healthBarOutline', {
		anchorX: 0,
		anchorY: 0.5
	});
	var healthBarBG = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	var healthBar = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	healthBarBG.y = healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	healthBarOutline.x = -healthBarOutline.width / 2;
	healthBarBG.x = healthBar.x = -healthBar.width / 2 - .5;
	healthBar.tint = 0x00ff00;
	healthBarBG.tint = 0xff0000;
	self.healthBar = healthBar;
	self.update = function () {
		if (self.health <= 0) {
			self.health = 0;
			self.healthBar.width = 0;
			return; // Early exit for dead enemies
		}
		// Cache enemy graphics reference for performance
		var graphics = self.children[0];
		if (!graphics) return;
		// Track if we need to update tint (expensive operation)
		var needTintUpdate = false;
		var newTint = 0xFFFFFF;
		// Handle slow effect
		if (self.isImmune) {
			// Immune enemies cannot be slowed or poisoned, clear any such effects
			if (self.slowed || self.poisoned) {
				self.slowed = false;
				self.slowEffect = false;
				self.poisoned = false;
				self.poisonEffect = false;
				// Reset speed to original if needed
				if (self.originalSpeed !== undefined) {
					self.speed = self.originalSpeed;
				}
				needTintUpdate = true;
			}
		} else {
			// Handle slow effect
			if (self.slowed) {
				// Visual indication of slowed status
				if (!self.slowEffect) {
					self.slowEffect = true;
					needTintUpdate = true;
				}
				self.slowDuration--;
				if (self.slowDuration <= 0) {
					self.speed = self.originalSpeed;
					self.slowed = false;
					self.slowEffect = false;
					needTintUpdate = true;
				}
			}
			// Handle poison effect (only every 30 frames for damage)
			if (self.poisoned) {
				// Visual indication of poisoned status
				if (!self.poisonEffect) {
					self.poisonEffect = true;
					needTintUpdate = true;
				}
				// Apply poison damage every 30 frames (twice per second)
				if (LK.ticks % 30 === 0) {
					self.health -= self.poisonDamage;
					if (self.health <= 0) {
						self.health = 0;
						return; // Early exit for newly dead enemies
					}
					self.healthBar.width = self.health / self.maxHealth * 70;
				}
				self.poisonDuration--;
				if (self.poisonDuration <= 0) {
					self.poisoned = false;
					self.poisonEffect = false;
					needTintUpdate = true;
				}
			}
		}
		// Set tint based on effect status (only if needed)
		if (needTintUpdate) {
			if (self.isImmune) {
				newTint = 0xFFFFFF;
			} else if (self.poisoned && self.slowed) {
				// Combine poison (0x00FFAA) and slow (0x9900FF) colors
				// Simple average: R: (0+153)/2=76, G: (255+0)/2=127, B: (170+255)/2=212
				newTint = 0x4C7FD4;
			} else if (self.poisoned) {
				newTint = 0x00FFAA;
			} else if (self.slowed) {
				newTint = 0x9900FF;
			} else {
				newTint = 0xFFFFFF;
			}
			graphics.tint = newTint;
		}
		// Only update rotation if we have a target and significant movement
		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 (graphics.targetRotation === undefined) {
					graphics.targetRotation = angle;
					graphics.rotation = angle;
				} else {
					if (Math.abs(angle - graphics.targetRotation) > 0.1) {
						// Increased threshold to reduce rotation updates
						tween.stop(graphics, {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = graphics.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;
						}
						graphics.targetRotation = angle;
						tween(graphics, {
							rotation: currentRotation + angleDiff
						}, {
							duration: 300,
							easing: tween.easeOut
						});
					}
				}
			}
		}
		// Only update health bar position if graphics height changed (rare)
		if (!self._lastGraphicsHeight || self._lastGraphicsHeight !== graphics.height) {
			healthBarOutline.y = healthBarBG.y = healthBar.y = -graphics.height / 2 - 10;
			self._lastGraphicsHeight = graphics.height;
		}
	};
	return self;
});
var GoldIndicator = 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 goldText = new Text2("+" + value, {
		size: 45,
		fill: 0xFFD700,
		weight: 800
	});
	goldText.anchor.set(0.5, 0.5);
	self.addChild(goldText);
	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 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;
			}
		}
		// Pre-filter ground enemies to reduce loop iterations
		var groundEnemies = [];
		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;
			}
			groundEnemies.push(enemy);
		}
		// Check path validity for ground enemies only
		for (var a = 0; a < groundEnemies.length; a++) {
			var enemy = groundEnemies[a];
			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 GuideSystem = Container.expand(function () {
	var self = Container.call(this);
	self.currentTip = 0;
	self.tips = ["Welcome to Tower Defense! Place towers to stop enemies.", "Drag towers from the bottom to build them on the battlefield.", "Different towers have different strengths - experiment!", "Upgrade towers by clicking on them after placement.", "The brown button with an eagle gives you 70 gold if pressed enough!", "Flying enemies can only be hit by certain tower types.", "Boss waves appear every 10 rounds - prepare accordingly!", "Use missiles for emergency situations - they cost 50 gold."];
	self.visible = false;
	self.tipShown = false;
	// Background
	var guideBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	guideBackground.width = 1800;
	guideBackground.height = 300;
	guideBackground.tint = 0x2C3E50;
	guideBackground.alpha = 0.95;
	// Title
	var titleText = new Text2("Game Guide", {
		size: 80,
		fill: 0xFFD700,
		weight: 800
	});
	titleText.anchor.set(0.5, 0.5);
	titleText.y = -80;
	self.addChild(titleText);
	// Tip text
	var tipText = new Text2("", {
		size: 60,
		fill: 0xFFFFFF,
		weight: 400
	});
	tipText.anchor.set(0.5, 0.5);
	tipText.y = 0;
	self.addChild(tipText);
	// Navigation buttons
	var prevButton = new Container();
	var prevBg = prevButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	prevBg.width = 200;
	prevBg.height = 80;
	prevBg.tint = 0x3498DB;
	var prevText = new Text2("Previous", {
		size: 45,
		fill: 0xFFFFFF,
		weight: 800
	});
	prevText.anchor.set(0.5, 0.5);
	prevButton.addChild(prevText);
	prevButton.x = -400;
	prevButton.y = 80;
	self.addChild(prevButton);
	var nextButton = new Container();
	var nextBg = nextButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	nextBg.width = 200;
	nextBg.height = 80;
	nextBg.tint = 0x3498DB;
	var nextText = new Text2("Next", {
		size: 45,
		fill: 0xFFFFFF,
		weight: 800
	});
	nextText.anchor.set(0.5, 0.5);
	nextButton.addChild(nextText);
	nextButton.x = 0;
	nextButton.y = 80;
	self.addChild(nextButton);
	var closeButton = new Container();
	var closeBg = closeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBg.width = 200;
	closeBg.height = 80;
	closeBg.tint = 0xE74C3C;
	var closeText = new Text2("Close", {
		size: 45,
		fill: 0xFFFFFF,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	closeButton.x = 400;
	closeButton.y = 80;
	self.addChild(closeButton);
	self.updateTip = function () {
		tipText.setText(self.tips[self.currentTip]);
		// Update button states
		prevBg.tint = self.currentTip > 0 ? 0x3498DB : 0x95A5A6;
		nextBg.tint = self.currentTip < self.tips.length - 1 ? 0x3498DB : 0x95A5A6;
	};
	self.showGuide = function () {
		self.visible = true;
		self.currentTip = 0;
		self.updateTip();
		// Animate in
		self.alpha = 0;
		self.scaleX = 0.8;
		self.scaleY = 0.8;
		tween(self, {
			alpha: 1,
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 300,
			easing: tween.backOut
		});
	};
	self.hideGuide = function () {
		tween(self, {
			alpha: 0,
			scaleX: 0.8,
			scaleY: 0.8
		}, {
			duration: 200,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.visible = false;
			}
		});
	};
	prevButton.down = function () {
		if (self.currentTip > 0) {
			self.currentTip--;
			self.updateTip();
			// Visual feedback
			tween(prevButton, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 100,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(prevButton, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 100,
						easing: tween.easeOut
					});
				}
			});
		}
	};
	nextButton.down = function () {
		if (self.currentTip < self.tips.length - 1) {
			self.currentTip++;
			self.updateTip();
			// Visual feedback
			tween(nextButton, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 100,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(nextButton, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 100,
						easing: tween.easeOut
					});
				}
			});
		}
	};
	closeButton.down = function () {
		self.hideGuide();
		// Visual feedback
		tween(closeButton, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(closeButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100,
					easing: tween.easeOut
				});
			}
		});
	};
	return self;
});
var LanguageButton = Container.expand(function () {
	var self = Container.call(this);
	// Load saved language or default to English
	self.currentLanguage = storage.language || 'EN';
	var buttonBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 120;
	buttonBackground.height = 80;
	buttonBackground.tint = 0x4169E1; // Royal blue
	var flagText = new Text2(self.currentLanguage, {
		size: 40,
		fill: 0xFFFFFF,
		weight: 800
	});
	flagText.anchor.set(0.5, 0.5);
	self.addChild(flagText);
	// Available languages
	self.languages = ['EN', 'ES', 'FR', 'DE', 'RU', 'ZH', 'JP', 'AR'];
	self.languageNames = {
		'EN': 'English',
		'ES': 'Español',
		'FR': 'Français',
		'DE': 'Deutsch',
		'RU': 'Русский',
		'ZH': '中文',
		'JP': '日本語',
		'AR': 'العربية'
	};
	// Translation dictionary for key game text
	self.translations = {
		'EN': {
			'nextWave': 'Next Wave',
			'gold': 'Gold',
			'lives': 'Lives',
			'score': 'Score',
			'startGame': 'Start Game',
			'started': 'Started!',
			'hawkButton': '🦅'
		},
		'ES': {
			'nextWave': 'Próxima Ola',
			'gold': 'Oro',
			'lives': 'Vidas',
			'score': 'Puntuación',
			'startGame': 'Comenzar Juego',
			'started': '¡Comenzado!',
			'hawkButton': '🦅'
		},
		'FR': {
			'nextWave': 'Vague Suivante',
			'gold': 'Or',
			'lives': 'Vies',
			'score': 'Score',
			'startGame': 'Commencer',
			'started': 'Commencé!',
			'hawkButton': '🦅'
		},
		'DE': {
			'nextWave': 'Nächste Welle',
			'gold': 'Gold',
			'lives': 'Leben',
			'score': 'Punkte',
			'startGame': 'Spiel Starten',
			'started': 'Gestartet!',
			'hawkButton': '🦅'
		},
		'RU': {
			'nextWave': 'Следующая Волна',
			'gold': 'Золото',
			'lives': 'Жизни',
			'score': 'Счёт',
			'startGame': 'Начать Игру',
			'started': 'Начато!',
			'hawkButton': '🦅'
		},
		'ZH': {
			'nextWave': '下一波',
			'gold': '金币',
			'lives': '生命',
			'score': '分数',
			'startGame': '开始游戏',
			'started': '已开始!',
			'hawkButton': '🦅'
		},
		'JP': {
			'nextWave': '次の波',
			'gold': 'ゴールド',
			'lives': 'ライフ',
			'score': 'スコア',
			'startGame': 'ゲーム開始',
			'started': '開始!',
			'hawkButton': '🦅'
		},
		'AR': {
			'nextWave': 'الموجة التالية',
			'gold': 'ذهب',
			'lives': 'الأرواح',
			'score': 'النتيجة',
			'startGame': 'بدء اللعبة',
			'started': 'بدأت!',
			'hawkButton': '🦅'
		}
	};
	// Update game language function
	self.updateGameLanguage = function () {
		var currentLang = self.translations[self.currentLanguage] || self.translations['EN'];
		// Update UI text elements
		if (goldText) {
			goldText.setText(currentLang.gold + ': ' + gold);
		}
		if (livesText) {
			livesText.setText(currentLang.lives + ': ' + lives);
		}
		if (scoreText) {
			scoreText.setText(currentLang.score + ': ' + score);
		}
		// Update hawk button text
		if (hawkButtonText) {
			hawkButtonText.setText(currentLang.hawkButton);
		}
		// Update next wave button if it exists
		if (nextWaveButton && nextWaveButton.children && nextWaveButton.children[1]) {
			nextWaveButton.children[1].setText(currentLang.nextWave);
		}
		// Update wave indicator start button if it exists
		if (waveIndicator && waveIndicator.waveMarkers && waveIndicator.waveMarkers[0]) {
			var startMarker = waveIndicator.waveMarkers[0];
			if (startMarker.children[1]) {
				startMarker.children[1].setText(currentLang.startGame);
			}
			if (startMarker.children[2]) {
				startMarker.children[2].setText(currentLang.startGame);
			}
		}
	};
	self.down = function () {
		// Cycle to next language
		var currentIndex = self.languages.indexOf(self.currentLanguage);
		var nextIndex = (currentIndex + 1) % self.languages.length;
		self.currentLanguage = self.languages[nextIndex];
		// Save to storage
		storage.language = self.currentLanguage;
		// Update display
		flagText.setText(self.currentLanguage);
		// Update all game text with new language
		self.updateGameLanguage();
		// Visual feedback
		tween(self, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(self, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100,
					easing: tween.easeIn
				});
			}
		});
		// Show notification with language name
		var languageName = self.languageNames[self.currentLanguage];
		var notification = game.addChild(new Notification("Language: " + languageName));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
		// Flash the button with the cultural colors
		var culturalColors = {
			'EN': 0x0052CC,
			// Blue
			'ES': 0xFFD700,
			// Gold
			'FR': 0x0055A4,
			// French blue
			'DE': 0x000000,
			// Black
			'RU': 0xDA020E,
			// Red
			'ZH': 0xFF0000,
			// Red
			'JP': 0xFF0000,
			// Red
			'AR': 0x00FF00 // Green
		};
		var originalTint = buttonBackground.tint;
		var culturalColor = culturalColors[self.currentLanguage] || 0x4169E1;
		tween(buttonBackground, {
			tint: culturalColor
		}, {
			duration: 200,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(buttonBackground, {
					tint: originalTint
				}, {
					duration: 300,
					easing: tween.easeIn
				});
			}
		});
	};
	return self;
});
var Missile = Container.expand(function (startX, startY, targetX, targetY, damage, speed, explosionRadius) {
	var self = Container.call(this);
	self.targetX = targetX || 0;
	self.targetY = targetY || 0;
	self.damage = damage || 50;
	self.speed = speed || 3;
	self.explosionRadius = explosionRadius || CELL_SIZE * 2;
	self.x = startX;
	self.y = startY;
	var missileGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	missileGraphics.tint = 0xFF4444; // Red color for missiles
	missileGraphics.width = 40;
	missileGraphics.height = 40;
	// Calculate trajectory
	var dx = self.targetX - self.x;
	var dy = self.targetY - self.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	self.directionX = dx / distance;
	self.directionY = dy / distance;
	// Rotate missile to face target
	var angle = Math.atan2(dy, dx);
	missileGraphics.rotation = angle;
	self.update = function () {
		// Move towards target
		self.x += self.directionX * self.speed;
		self.y += self.directionY * self.speed;
		// Check if reached target area
		var currentDx = self.targetX - self.x;
		var currentDy = self.targetY - self.y;
		var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy);
		if (currentDistance < self.speed * 2) {
			// Explode at target location
			self.explode();
			self.destroy();
		}
	};
	self.explode = function () {
		// Create explosion effect
		var explosionEffect = new EffectIndicator(self.x, self.y, 'missile_explosion');
		game.addChild(explosionEffect);
		// Apply splash damage to all enemies in radius
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var explosionDx = enemy.x - self.x;
			var explosionDy = enemy.y - self.y;
			var explosionDistance = Math.sqrt(explosionDx * explosionDx + explosionDy * explosionDy);
			if (explosionDistance <= self.explosionRadius) {
				// Apply damage based on distance (closer = more damage)
				var damageMultiplier = 1 - explosionDistance / self.explosionRadius * 0.5;
				var actualDamage = self.damage * damageMultiplier;
				enemy.health -= actualDamage;
				if (enemy.health <= 0) {
					enemy.health = 0;
				} else {
					enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
				}
			}
		}
	};
	return self;
});
var NextWaveButton = Container.expand(function () {
	var self = Container.call(this);
	var buttonBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 300;
	buttonBackground.height = 100;
	buttonBackground.tint = 0x0088FF;
	var buttonText = new Text2("Next Wave", {
		size: 50,
		fill: 0xFFFFFF,
		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 = 0x0088FF;
			self.alpha = 1;
		} else {
			self.enabled = false;
			self.visible = false;
			buttonBackground.tint = 0x888888;
			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!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 150;
		}
	};
	return self;
});
var Notification = Container.expand(function (message) {
	var self = Container.call(this);
	var notificationGraphics = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var notificationText = new Text2(message, {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	notificationText.anchor.set(0.5, 0.5);
	notificationGraphics.width = notificationText.width + 30;
	self.addChild(notificationText);
	self.alpha = 1;
	var fadeOutTime = 120;
	self.update = function () {
		if (fadeOutTime > 0) {
			fadeOutTime--;
			self.alpha = Math.min(fadeOutTime / 120 * 2, 1);
		} else {
			self.destroy();
		}
	};
	return self;
});
var SourceTower = Container.expand(function (towerType) {
	var self = Container.call(this);
	self.towerType = towerType || 'default';
	// Increase size of base for easier touch
	var baseGraphics = self.attachAsset('tower', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.3,
		scaleY: 1.3
	});
	switch (self.towerType) {
		case 'Lansen':
			baseGraphics.tint = 0x005293;
			break;
		case 'Draken':
			baseGraphics.tint = 0xFFD100;
			break;
		case 'Viggen':
			baseGraphics.tint = 0x00AA44;
			break;
		case 'Gripen':
			baseGraphics.tint = 0x666666;
			break;
		case 'Super Viggen':
			baseGraphics.tint = 0x0066CC;
			break;
		default:
			baseGraphics.tint = 0x005293;
	}
	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 typeLabel = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
		size: 50,
		fill: 0xFFFFFF,
		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: 0xFFD700,
		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 = gold >= getTowerCost(self.towerType);
		// Set opacity based on affordability
		self.alpha = canAfford ? 1 : 0.5;
	};
	return self;
});
var Tower = Container.expand(function (id) {
	var self = Container.call(this);
	self.id = id || 'default';
	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 'Draken':
				// Draken: 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 'Viggen':
				// Viggen: base 2, +0.2 per level (max ~4 blocks at max level)
				return (2 + (self.level - 1) * 0.2) * CELL_SIZE;
			case 'Lansen':
				// Lansen: base 2.5, +0.5 per level
				return (2.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'Gripen':
				// Gripen: base 3.5, +0.5 per level
				return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'Super Viggen':
				// Super Viggen: base 3.2, +0.5 per level
				return (3.2 + (self.level - 1) * 0.5) * CELL_SIZE;
			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 = 10;
	self.lastFired = 0;
	self.targetEnemy = null;
	switch (self.id) {
		case 'Lansen':
			self.fireRate = 30;
			self.damage = 5;
			self.range = 2.5 * CELL_SIZE;
			self.bulletSpeed = 7;
			break;
		case 'Draken':
			self.fireRate = 90;
			self.damage = 25;
			self.range = 5 * CELL_SIZE;
			self.bulletSpeed = 25;
			break;
		case 'Viggen':
			self.fireRate = 75;
			self.damage = 15;
			self.range = 2 * CELL_SIZE;
			self.bulletSpeed = 4;
			break;
		case 'Gripen':
			self.fireRate = 50;
			self.damage = 8;
			self.range = 3.5 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
		case 'Super Viggen':
			self.fireRate = 70;
			self.damage = 12;
			self.range = 3.2 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
	}
	var baseGraphics = self.attachAsset('tower', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	switch (self.id) {
		case 'Lansen':
			baseGraphics.tint = 0x005293;
			break;
		case 'Draken':
			baseGraphics.tint = 0xFFD100;
			break;
		case 'Viggen':
			baseGraphics.tint = 0x00AA44;
			break;
		case 'Gripen':
			baseGraphics.tint = 0x666666;
			break;
		case 'Super Viggen':
			baseGraphics.tint = 0x0066CC;
			break;
		default:
			baseGraphics.tint = 0x005293;
	}
	var levelIndicators = [];
	var maxDots = self.maxLevel;
	var dotSpacing = baseGraphics.width / (maxDots + 1);
	var dotSize = CELL_SIZE / 6;
	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 = -CELL_SIZE + dotSpacing * (i + 1);
		dot.y = CELL_SIZE * 0.7;
		self.addChild(dot);
		levelIndicators.push(dot);
	}
	var gunContainer = new Container();
	self.addChild(gunContainer);
	var gunGraphics = gunContainer.attachAsset('defense', {
		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 = 0xFFFFFF;
			} else {
				switch (self.id) {
					case 'Lansen':
						towerLevelIndicator.tint = 0x005293;
						break;
					case 'Draken':
						towerLevelIndicator.tint = 0xFFD100;
						break;
					case 'Viggen':
						towerLevelIndicator.tint = 0x00AA44;
						break;
					case 'Gripen':
						towerLevelIndicator.tint = 0x666666;
						break;
					case 'Super Viggen':
						towerLevelIndicator.tint = 0x0066CC;
						break;
					default:
						towerLevelIndicator.tint = 0x005293;
				}
			}
		}
	};
	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 (gold >= upgradeCost) {
				setGold(gold - upgradeCost);
				self.level++;
				// Apply specialized upgrades based on tower type and level
				applyTowerUpgrade(self);
				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 gold to upgrade!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.findTarget = function () {
		var closestEnemy = null;
		var closestScore = Infinity;
		var towerRange = self.getRange();
		var towerRangeSquared = towerRange * towerRange;
		// Early exit if no enemies
		if (enemies.length === 0) {
			self.targetEnemy = null;
			return null;
		}
		// Cache tower position
		var towerX = self.x;
		var towerY = self.y;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			// Quick bounds check before distance calculation
			var dx = enemy.x - towerX;
			var dy = enemy.y - towerY;
			// Skip if obviously out of range (Manhattan distance approximation)
			if (Math.abs(dx) > towerRange || Math.abs(dy) > towerRange) {
				continue;
			}
			var distanceSquared = dx * dx + dy * dy;
			// Use squared distance for initial check (faster)
			if (distanceSquared <= towerRangeSquared) {
				// 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 distToGoalSq = (goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY);
						// Use squared distance to goal as score (avoid sqrt)
						if (distToGoalSq < closestScore) {
							closestScore = distToGoalSq;
							closestEnemy = enemy;
						}
					} else {
						// If no flying target yet (shouldn't happen), prioritize by distance to tower
						if (distanceSquared < closestScore) {
							closestScore = distanceSquared;
							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 () {
		self.targetEnemy = self.findTarget();
		if (self.targetEnemy) {
			var dx = self.targetEnemy.x - self.x;
			var dy = self.targetEnemy.y - self.y;
			var angle = Math.atan2(dy, dx);
			gunContainer.rotation = angle;
			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;
		tween(upgradeMenu, {
			y: 2732 - 225
		}, {
			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;
				// Handle special firing modes
				var bulletsToFire = [];
				if (self.hasTripleShot) {
					// Triple shot: fire 3 bullets in a spread
					for (var shotIndex = 0; shotIndex < 3; shotIndex++) {
						var spreadAngle = gunContainer.rotation + (shotIndex - 1) * 0.3;
						var spreadX = self.x + Math.cos(spreadAngle) * 40;
						var spreadY = self.y + Math.sin(spreadAngle) * 40;
						bulletsToFire.push({
							x: spreadX,
							y: spreadY
						});
					}
				} else {
					// Normal single shot
					bulletsToFire.push({
						x: bulletX,
						y: bulletY
					});
				}
				// Fire all bullets
				for (var bulletIndex = 0; bulletIndex < bulletsToFire.length; bulletIndex++) {
					var bulletPos = bulletsToFire[bulletIndex];
					var bullet = new Bullet(bulletPos.x, bulletPos.y, self.targetEnemy, self.damage, self.bulletSpeed);
					// Set bullet type based on tower type
					bullet.type = self.id;
					// Apply specialized bullet properties
					bullet.hasPiercingBullets = self.hasPiercingBullets;
					bullet.hasExplosiveRounds = self.hasExplosiveRounds;
					bullet.hasSniperShots = self.hasSniperShots;
					bullet.hasArmorPiercing = self.hasArmorPiercing;
					bullet.hasRailgun = self.hasRailgun;
					bullet.splashRadius = self.splashRadius;
					bullet.hasBurningEffect = self.hasBurningEffect;
					bullet.hasChainExplosions = self.hasChainExplosions;
					bullet.hasNuclearWarhead = self.hasNuclearWarhead;
					bullet.slowPercentage = self.slowPercentage;
					bullet.hasFreezeEffect = self.hasFreezeEffect;
					bullet.hasIceShards = self.hasIceShards;
					bullet.slowDuration = self.slowDuration;
					bullet.hasAbsoluteZero = self.hasAbsoluteZero;
					bullet.poisonSpreads = self.poisonSpreads;
					bullet.hasToxicCloud = self.hasToxicCloud;
					bullet.poisonDamageMultiplier = self.poisonDamageMultiplier;
					bullet.hasCorrosiveAcid = self.hasCorrosiveAcid;
					bullet.hasPlagueSpread = self.hasPlagueSpread;
					// For Gripen tower, pass level for scaling slow effect
					if (self.id === 'Gripen') {
						bullet.sourceTowerLevel = self.level;
					}
					// Customize bullet appearance based on tower type
					switch (self.id) {
						case 'Lansen':
							bullet.children[0].tint = 0x005293;
							bullet.children[0].width = 20;
							bullet.children[0].height = 20;
							break;
						case 'Draken':
							bullet.children[0].tint = 0xFFD100;
							bullet.children[0].width = 15;
							bullet.children[0].height = 15;
							break;
						case 'Viggen':
							bullet.children[0].tint = 0x00AA44;
							bullet.children[0].width = 40;
							bullet.children[0].height = 40;
							break;
						case 'Gripen':
							bullet.children[0].tint = 0x666666;
							bullet.children[0].width = 35;
							bullet.children[0].height = 35;
							break;
						case 'Super Viggen':
							bullet.children[0].tint = 0x0066CC;
							bullet.children[0].width = 35;
							bullet.children[0].height = 35;
							break;
					}
					game.addChild(bullet);
					bullets.push(bullet);
					self.targetEnemy.bulletsTargetingThis.push(bullet);
				}
				// --- 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();
	};
	return self;
});
var TowerPreview = Container.expand(function () {
	var self = Container.call(this);
	var towerRange = 3;
	var rangeInPixels = towerRange * CELL_SIZE;
	self.towerType = 'default';
	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 = gold >= 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 'Lansen':
				previewGraphics.tint = 0x005293;
				break;
			case 'Draken':
				previewGraphics.tint = 0xFFD100;
				break;
			case 'Viggen':
				previewGraphics.tint = 0x00AA44;
				break;
			case 'Gripen':
				previewGraphics.tint = 0x666666;
				break;
			case 'Super Viggen':
				previewGraphics.tint = 0x0066CC;
				break;
			default:
				previewGraphics.tint = 0x005293;
		}
		if (!self.canPlace || !self.hasEnoughGold) {
			previewGraphics.tint = 0xFF0000;
		}
	};
	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 = gold >= 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;
	self.y = 2732 + 225;
	var menuBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	menuBackground.width = 2048;
	menuBackground.height = 500;
	menuBackground.tint = 0x444444;
	menuBackground.alpha = 0.9;
	var towerTypeText = new Text2(self.tower.id.charAt(0).toUpperCase() + self.tower.id.slice(1) + ' Tower', {
		size: 80,
		fill: 0xFFFFFF,
		weight: 800
	});
	towerTypeText.anchor.set(0, 0);
	towerTypeText.x = -840;
	towerTypeText.y = -160;
	self.addChild(towerTypeText);
	var statsText = new Text2('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s', {
		size: 70,
		fill: 0xFFFFFF,
		weight: 400
	});
	statsText.anchor.set(0, 0.5);
	statsText.x = -840;
	statsText.y = 50;
	self.addChild(statsText);
	var buttonsContainer = new Container();
	buttonsContainer.x = 500;
	self.addChild(buttonsContainer);
	var upgradeButton = new Container();
	buttonsContainer.addChild(upgradeButton);
	var buttonBackground = upgradeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 500;
	buttonBackground.height = 150;
	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 : gold >= upgradeCost ? 0x00AA00 : 0x888888;
	var upgradeDescription = isMaxLevel ? 'Max Level' : getTowerUpgradeDescription(self.tower.id, self.tower.level);
	var buttonText = new Text2(isMaxLevel ? 'Max Level' : upgradeDescription + '\nCost: ' + upgradeCost + ' gold', {
		size: 50,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	var sellButton = new Container();
	buttonsContainer.addChild(sellButton);
	var sellButtonBackground = sellButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	sellButtonBackground.width = 500;
	sellButtonBackground.height = 150;
	sellButtonBackground.tint = 0xCC0000;
	var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
	var sellValue = getTowerSellValue(totalInvestment);
	var sellButtonText = new Text2('Sell: +' + sellValue + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	sellButtonText.anchor.set(0.5, 0.5);
	sellButton.addChild(sellButtonText);
	upgradeButton.y = -85;
	sellButton.y = 85;
	var closeButton = new Container();
	self.addChild(closeButton);
	var closeBackground = closeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBackground.width = 90;
	closeBackground.height = 90;
	closeBackground.tint = 0xAA0000;
	var closeText = new Text2('X', {
		size: 68,
		fill: 0xFFFFFF,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	closeButton.x = menuBackground.width / 2 - 57;
	closeButton.y = -menuBackground.height / 2 + 57;
	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));
			}
			statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s');
			var newUpgradeDesc = getTowerUpgradeDescription(self.tower.id, self.tower.level);
			buttonText.setText(newUpgradeDesc + '\nCost: ' + upgradeCost + ' gold');
			var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
			var sellValue = Math.floor(totalInvestment * 0.6);
			sellButtonText.setText('Sell: +' + sellValue + ' gold');
			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);
		setGold(gold + sellValue);
		var notification = game.addChild(new Notification("Tower sold for " + sellValue + " gold!"));
		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) {
		hideUpgradeMenu(self);
		selectedTower = null;
		grid.renderDebug();
	};
	self.update = function () {
		if (self.tower.level >= self.tower.maxLevel) {
			if (buttonText.text !== 'Max Level') {
				buttonText.setText('Max Level');
				buttonBackground.tint = 0x888888;
			}
			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 = gold >= currentUpgradeCost;
		buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888;
		var newUpgradeDesc = getTowerUpgradeDescription(self.tower.id, self.tower.level);
		var newText = newUpgradeDesc + '\nCost: ' + currentUpgradeCost + ' gold';
		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('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	startBlock.width = blockWidth - 10;
	startBlock.height = 70 * 2;
	startBlock.tint = 0x00AA00;
	// 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: 0xFFFFFF,
		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) {
			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! Wave 1 incoming!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 150;
			// Show guide tip after a short delay
			LK.setTimeout(function () {
				if (guideSystem && !guideSystem.tipShown) {
					guideSystem.showGuide();
					guideSystem.tipShown = true;
				}
			}, 2000);
		}
	};
	for (var i = 0; i < totalWaves; i++) {
		var marker = new Container();
		var block = marker.attachAsset('notification', {
			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 = 0xAAAAAA;
			waveType = "Tanks";
			enemyType = "normal";
			enemyCount = 10;
		} else if (i === 1) {
			block.tint = 0x00AAFF;
			waveType = "T-34";
			enemyType = "fast";
			enemyCount = 10;
		} else if (i === 2) {
			block.tint = 0xAA0000;
			waveType = "KV-1";
			enemyType = "immune";
			enemyCount = 10;
		} else if (i === 3) {
			block.tint = 0xFFFF00;
			waveType = "MiG-21";
			enemyType = "flying";
			enemyCount = 10;
		} else if (i === 4) {
			block.tint = 0xFF00FF;
			waveType = "Infantry";
			enemyType = "swarm";
			enemyCount = 30;
		} else if (i === 5) {
			block.tint = 0x88FF88;
			waveType = "Geese";
			enemyType = "geese";
			enemyCount = 15;
		} else if (isBossWave) {
			// Boss waves: cycle through all boss types, last boss is always flying
			var bossTypes = ['normal', 'fast', 'immune', 'flying', 'geese'];
			var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
			if (i === totalWaves - 1) {
				// Last boss is always flying
				enemyType = 'flying';
				waveType = "Boss Flying";
				block.tint = 0xFFFF00;
			} else {
				enemyType = bossTypes[bossTypeIndex % bossTypes.length];
				switch (enemyType) {
					case 'normal':
						block.tint = 0xAAAAAA;
						waveType = "Boss T-55";
						break;
					case 'fast':
						block.tint = 0x00AAFF;
						waveType = "Boss T-34";
						break;
					case 'immune':
						block.tint = 0xAA0000;
						waveType = "Boss KV-1";
						break;
					case 'flying':
						block.tint = 0xFFFF00;
						waveType = "Boss MiG-21";
						break;
					case 'geese':
						block.tint = 0x88FF88;
						waveType = "Boss Geese";
						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 = 0xAAAAAA;
					break;
				case 'fast':
					block.tint = 0x00AAFF;
					break;
				case 'immune':
					block.tint = 0xAA0000;
					break;
				case 'flying':
					block.tint = 0xFFFF00;
					break;
				case 'geese':
					block.tint = 0x88FF88;
					break;
				default:
					block.tint = 0xFF0000;
					break;
			}
		} else if ((i + 1) % 5 === 0) {
			// Every 5th non-boss wave is fast tanks
			block.tint = 0x00AAFF;
			waveType = "T-34";
			enemyType = "fast";
			enemyCount = 10;
		} else if ((i + 1) % 4 === 0) {
			// Every 4th non-boss wave is heavy tanks
			block.tint = 0xAA0000;
			waveType = "KV-1";
			enemyType = "immune";
			enemyCount = 10;
		} else if ((i + 1) % 7 === 0) {
			// Every 7th non-boss wave is aircraft
			block.tint = 0xFFFF00;
			waveType = "MiG-21";
			enemyType = "flying";
			enemyCount = 10;
		} else if ((i + 1) % 8 === 0) {
			// Every 8th non-boss wave is geese
			block.tint = 0x88FF88;
			waveType = "Geese";
			enemyType = "geese";
			enemyCount = 15;
		} else if ((i + 1) % 3 === 0) {
			// Every 3rd non-boss wave is infantry
			block.tint = 0xFF00FF;
			waveType = "Infantry";
			enemyType = "swarm";
			enemyCount = 30;
		} else {
			block.tint = 0xAAAAAA;
			waveType = "Tanks";
			enemyType = "normal";
			enemyCount = 10;
		}
		// --- End new unified wave logic ---
		// 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;
		// Add shadow for wave type - 30% smaller than before
		var waveTypeShadow = new Text2(waveType, {
			size: 56,
			fill: 0x000000,
			weight: 800
		});
		waveTypeShadow.anchor.set(0.5, 0.5);
		waveTypeShadow.x = 4;
		waveTypeShadow.y = 4;
		marker.addChild(waveTypeShadow);
		// Add wave type text - 30% smaller than before
		var waveTypeText = new Text2(waveType, {
			size: 56,
			fill: 0xFFFFFF,
			weight: 800
		});
		waveTypeText.anchor.set(0.5, 0.5);
		waveTypeText.y = 0;
		marker.addChild(waveTypeText);
		// Add shadow for wave number - 20% larger than before
		var waveNumShadow = new Text2((i + 1).toString(), {
			size: 48,
			fill: 0x000000,
			weight: 800
		});
		waveNumShadow.anchor.set(1.0, 1.0);
		waveNumShadow.x = blockWidth / 2 - 16 + 5;
		waveNumShadow.y = block.height / 2 - 12 + 5;
		marker.addChild(waveNumShadow);
		// Main wave number text - 20% larger than before
		var waveNum = new Text2((i + 1).toString(), {
			size: 48,
			fill: 0xFFFFFF,
			weight: 800
		});
		waveNum.anchor.set(1.0, 1.0);
		waveNum.x = blockWidth / 2 - 16;
		waveNum.y = block.height / 2 - 12;
		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) {
		var type = self.getWaveType(waveNumber);
		var typeName = type.charAt(0).toUpperCase() + type.slice(1);
		// Add boss prefix for boss waves (every 10th wave)
		if (waveNumber % 10 === 0 && waveNumber > 0 && type !== 'swarm') {
			typeName = "BOSS";
		}
		return typeName;
	};
	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 = 0xffad0e;
	indicator.y = -65;
	var indicator2 = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	indicator2.width = blockWidth - 10;
	indicator2.height = 16;
	indicator2.tint = 0xffad0e;
	indicator2.y = 65;
	var leftWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	leftWall.width = 16;
	leftWall.height = 146;
	leftWall.tint = 0xffad0e;
	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 = 0xffad0e;
	rightWall.x = (blockWidth - 16) / 2;
	self.addChild(self.positionIndicator);
	self.update = function () {
		// Only update position every few frames to reduce calculations
		if (LK.ticks % 3 === 0) {
			var progress = waveTimer / nextWaveTime;
			var moveAmount = (progress + currentWave) * blockWidth;
			// Cache the calculation result
			if (self._lastMoveAmount !== moveAmount) {
				self._lastMoveAmount = moveAmount;
				for (var i = 0; i < self.waveMarkers.length; i++) {
					var marker = self.waveMarkers[i];
					marker.x = -moveAmount + i * blockWidth;
				}
			}
		}
		self.positionIndicator.x = 0;
		// Only update alpha every 10 frames to reduce overhead
		if (LK.ticks % 10 === 0) {
			for (var i = 1; i < Math.min(totalWaves + 1, self.waveMarkers.length); i++) {
				var marker = self.waveMarkers[i];
				var block = marker.children[0];
				var shouldBeFaded = i - 1 < currentWave;
				if (shouldBeFaded && block.alpha !== 0.5) {
					block.alpha = 0.5;
				} else if (!shouldBeFaded && block.alpha !== 1.0) {
					block.alpha = 1.0;
				}
			}
		}
		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 = grid.height - 150;
						// Play VoruThunder sound for MiG rounds
						var actualWaveType = self.getWaveType(currentWave);
						if (actualWaveType === 'flying') {
							LK.getSound('VoruThunder').play();
						}
					}
				}
			}
		};
		self.handleWaveProgression();
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x333333
});
/**** 
* Game Code
****/ 
var isHidingUpgradeMenu = false;
function hideUpgradeMenu(menu) {
	if (isHidingUpgradeMenu) {
		return;
	}
	isHidingUpgradeMenu = true;
	tween(menu, {
		y: 2732 + 225
	}, {
		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 missiles = [];
var defenses = [];
var selectedTower = null;
var gold = 80;
var lives = 20;
var score = 0;
var currentWave = 0;
var totalWaves = 50;
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 goldText = new Text2('Gold: ' + gold, {
	size: 60,
	fill: 0xFFD700,
	weight: 800
});
goldText.anchor.set(0.5, 0.5);
var livesText = new Text2('Lives: ' + lives, {
	size: 60,
	fill: 0x00FF00,
	weight: 800
});
livesText.anchor.set(0.5, 0.5);
var scoreText = new Text2('Score: ' + score, {
	size: 60,
	fill: 0xFF0000,
	weight: 800
});
scoreText.anchor.set(0.5, 0.5);
var topMargin = 50;
var centerX = 2048 / 2;
var spacing = 400;
LK.gui.top.addChild(goldText);
LK.gui.top.addChild(livesText);
LK.gui.top.addChild(scoreText);
livesText.x = 0;
livesText.y = topMargin;
goldText.x = -spacing;
goldText.y = topMargin;
scoreText.x = spacing;
scoreText.y = topMargin;
var lastGoldDisplay = -1;
var lastLivesDisplay = -1;
var lastScoreDisplay = -1;
function updateUI() {
	// Get current language from storage or default to English
	var currentLang = storage.language || 'EN';
	var translations = {
		'EN': {
			'gold': 'Gold',
			'lives': 'Lives',
			'score': 'Score'
		},
		'ES': {
			'gold': 'Oro',
			'lives': 'Vidas',
			'score': 'Puntuación'
		},
		'FR': {
			'gold': 'Or',
			'lives': 'Vies',
			'score': 'Score'
		},
		'DE': {
			'gold': 'Gold',
			'lives': 'Leben',
			'score': 'Punkte'
		},
		'RU': {
			'gold': 'Золото',
			'lives': 'Жизни',
			'score': 'Счёт'
		},
		'ZH': {
			'gold': '金币',
			'lives': '生命',
			'score': '分数'
		},
		'JP': {
			'gold': 'ゴールド',
			'lives': 'ライフ',
			'score': 'スコア'
		},
		'AR': {
			'gold': 'ذهب',
			'lives': 'الأرواح',
			'score': 'النتيجة'
		}
	};
	var langText = translations[currentLang] || translations['EN'];
	if (gold !== lastGoldDisplay) {
		goldText.setText(langText.gold + ': ' + gold);
		lastGoldDisplay = gold;
	}
	if (lives !== lastLivesDisplay) {
		livesText.setText(langText.lives + ': ' + lives);
		lastLivesDisplay = lives;
	}
	if (score !== lastScoreDisplay) {
		scoreText.setText(langText.score + ': ' + score);
		lastScoreDisplay = score;
	}
}
function setGold(value) {
	gold = 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);
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 = 5;
	switch (towerType) {
		case 'Lansen':
			cost = 15;
			break;
		case 'Draken':
			cost = 25;
			break;
		case 'Viggen':
			cost = 35;
			break;
		case 'Gripen':
			cost = 45;
			break;
		case 'Super Viggen':
			cost = 55;
			break;
	}
	return cost;
}
// Get specialized upgrade description for each tower type and level
function getTowerUpgradeDescription(towerType, currentLevel) {
	switch (towerType) {
		case 'Tunnan':
			switch (currentLevel) {
				case 1:
					return "Upgrade: +3 damage, +0.5 range";
				case 2:
					return "Upgrade: +5 damage, faster bullets";
				case 3:
					return "Upgrade: +7 damage, +15% fire rate";
				case 4:
					return "Upgrade: +10 damage, +0.5 range";
				case 5:
					return "ULTIMATE: Double damage, explosive rounds";
				default:
					return "Max Level";
			}
		case 'Lansen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Rapid fire mode, +50% fire rate";
				case 2:
					return "Upgrade: Piercing bullets (hit 2 enemies)";
				case 3:
					return "Upgrade: +3 damage, even faster fire";
				case 4:
					return "Upgrade: Triple shot burst";
				case 5:
					return "ULTIMATE: Minigun mode - constant fire";
				default:
					return "Max Level";
			}
		case 'Draken':
			switch (currentLevel) {
				case 1:
					return "Upgrade: +10 damage, +1 range";
				case 2:
					return "Upgrade: Sniper shots (2x crit chance)";
				case 3:
					return "Upgrade: +15 damage, faster bullets";
				case 4:
					return "Upgrade: Armor piercing (ignores 50% armor)";
				case 5:
					return "ULTIMATE: Railgun - pierces all enemies";
				default:
					return "Max Level";
			}
		case 'Viggen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Larger splash radius";
				case 2:
					return "Upgrade: +5 damage, burning effect";
				case 3:
					return "Upgrade: Chain explosions";
				case 4:
					return "Upgrade: +10 damage, bigger blast";
				case 5:
					return "ULTIMATE: Nuclear warhead - massive blast";
				default:
					return "Max Level";
			}
		case 'Gripen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Stronger slow (60% speed reduction)";
				case 2:
					return "Upgrade: Freeze effect (stops enemies briefly)";
				case 3:
					return "Upgrade: Ice shards (slows nearby enemies)";
				case 4:
					return "Upgrade: Permafrost (longer slow duration)";
				case 5:
					return "ULTIMATE: Absolute zero - area freeze";
				default:
					return "Max Level";
			}
		case 'Super Viggen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Poison spreads to nearby enemies";
				case 2:
					return "Upgrade: Toxic cloud (area poison)";
				case 3:
					return "Upgrade: +50% poison damage";
				case 4:
					return "Upgrade: Corrosive acid (armor reduction)";
				case 5:
					return "ULTIMATE: Plague spreader - chain poison";
				default:
					return "Max Level";
			}
		default:
			return currentLevel >= 6 ? "Max Level" : "Upgrade available";
	}
}
// Apply specialized upgrades based on tower type and level
function applyTowerUpgrade(tower) {
	switch (tower.id) {
		case 'Tunnan':
			switch (tower.level) {
				case 2:
					tower.damage += 3;
					tower.range += 0.5 * CELL_SIZE;
					break;
				case 3:
					tower.damage += 5;
					tower.bulletSpeed += 2;
					break;
				case 4:
					tower.damage += 7;
					tower.fireRate = Math.max(10, tower.fireRate * 0.85);
					break;
				case 5:
					tower.damage += 10;
					tower.range += 0.5 * CELL_SIZE;
					break;
				case 6:
					tower.damage *= 2;
					tower.hasExplosiveRounds = true;
					break;
			}
			break;
		case 'Lansen':
			switch (tower.level) {
				case 2:
					tower.fireRate = Math.max(5, tower.fireRate * 0.5);
					break;
				case 3:
					tower.hasPiercingBullets = true;
					break;
				case 4:
					tower.damage += 3;
					tower.fireRate = Math.max(3, tower.fireRate * 0.8);
					break;
				case 5:
					tower.hasTripleShot = true;
					break;
				case 6:
					tower.hasMinigunMode = true;
					tower.fireRate = 2;
					break;
			}
			break;
		case 'Draken':
			switch (tower.level) {
				case 2:
					tower.damage += 10;
					tower.range += 1 * CELL_SIZE;
					break;
				case 3:
					tower.hasSniperShots = true;
					break;
				case 4:
					tower.damage += 15;
					tower.bulletSpeed += 5;
					break;
				case 5:
					tower.hasArmorPiercing = true;
					break;
				case 6:
					tower.hasRailgun = true;
					break;
			}
			break;
		case 'Viggen':
			switch (tower.level) {
				case 2:
					tower.splashRadius = (tower.splashRadius || CELL_SIZE * 1.5) + CELL_SIZE * 0.5;
					break;
				case 3:
					tower.damage += 5;
					tower.hasBurningEffect = true;
					break;
				case 4:
					tower.hasChainExplosions = true;
					break;
				case 5:
					tower.damage += 10;
					tower.splashRadius = (tower.splashRadius || CELL_SIZE * 1.5) + CELL_SIZE * 0.5;
					break;
				case 6:
					tower.hasNuclearWarhead = true;
					tower.splashRadius = CELL_SIZE * 4;
					break;
			}
			break;
		case 'Gripen':
			switch (tower.level) {
				case 2:
					tower.slowPercentage = 0.6;
					break;
				case 3:
					tower.hasFreezeEffect = true;
					break;
				case 4:
					tower.hasIceShards = true;
					break;
				case 5:
					tower.slowDuration = 300; // 5 seconds
					break;
				case 6:
					tower.hasAbsoluteZero = true;
					break;
			}
			break;
		case 'Super Viggen':
			switch (tower.level) {
				case 2:
					tower.poisonSpreads = true;
					break;
				case 3:
					tower.hasToxicCloud = true;
					break;
				case 4:
					tower.poisonDamageMultiplier = 1.5;
					break;
				case 5:
					tower.hasCorrosiveAcid = true;
					break;
				case 6:
					tower.hasPlagueSpread = true;
					break;
			}
			break;
	}
}
function getTowerSellValue(totalValue) {
	return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
}
function launchMissile(startX, startY, targetX, targetY, damage, speed, explosionRadius) {
	var missile = new Missile(startX, startY, targetX, targetY, damage, speed, explosionRadius);
	game.addChild(missile);
	missiles.push(missile);
	return missile;
}
function placeTower(gridX, gridY, towerType) {
	var towerCost = getTowerCost(towerType);
	if (gold >= towerCost) {
		var tower = new Tower(towerType || 'Tunnan');
		tower.placeOnGrid(gridX, gridY);
		towerLayer.addChild(tower);
		towers.push(tower);
		setGold(gold - towerCost);
		grid.pathFind();
		grid.renderDebug();
		return true;
	} else {
		var notification = game.addChild(new Notification("Not enough gold!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		return false;
	}
}
game.down = function (x, y, obj) {
	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) {
			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 (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) {
	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.height - 50;
		}
		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;
game.addChild(waveIndicator);
var nextWaveButtonContainer = new Container();
var nextWaveButton = new NextWaveButton();
nextWaveButton.x = 2048 - 200;
nextWaveButton.y = 2732 - 100 + 20;
nextWaveButtonContainer.addChild(nextWaveButton);
game.addChild(nextWaveButtonContainer);
// Add Hawk Button
var hawkPressCount = 0;
var hawkButton = new Container();
var hawkButtonBackground = hawkButton.attachAsset('notification', {
	anchorX: 0.5,
	anchorY: 0.5
});
hawkButtonBackground.width = 250;
hawkButtonBackground.height = 120;
hawkButtonBackground.tint = 0x8B4513; // Brown color
var hawkButtonText = new Text2("🦅", {
	size: 80,
	fill: 0xFFFFFF,
	weight: 800
});
hawkButtonText.anchor.set(0.5, 0.5);
hawkButton.addChild(hawkButtonText);
hawkButton.x = 200;
hawkButton.y = 2732 - 150;
game.addChild(hawkButton);
// Add Language Button
var languageButton = new LanguageButton();
languageButton.x = 380; // Position to the right of hawk button
languageButton.y = 2732 - 150; // Same Y position as hawk button
game.addChild(languageButton);
// Add Guide Button
var guideButton = new Container();
var guideButtonBackground = guideButton.attachAsset('notification', {
	anchorX: 0.5,
	anchorY: 0.5
});
guideButtonBackground.width = 120;
guideButtonBackground.height = 80;
guideButtonBackground.tint = 0x9B59B6; // Purple color
var guideButtonText = new Text2('?', {
	size: 50,
	fill: 0xFFFFFF,
	weight: 800
});
guideButtonText.anchor.set(0.5, 0.5);
guideButton.addChild(guideButtonText);
guideButton.x = 800; // Position to the right of missile button
guideButton.y = 2732 - 150; // Same Y position
game.addChild(guideButton);
// Add Guide System
var guideSystem = new GuideSystem();
guideSystem.x = 2048 / 2;
guideSystem.y = 2732 / 2;
game.addChild(guideSystem);
guideButton.down = function () {
	guideSystem.showGuide();
	// Visual feedback
	tween(guideButton, {
		scaleX: 0.9,
		scaleY: 0.9
	}, {
		duration: 100,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(guideButton, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 100,
				easing: tween.easeOut
			});
		}
	});
};
// Add Missile Button
var missileButton = new Container();
var missileButtonBackground = missileButton.attachAsset('notification', {
	anchorX: 0.5,
	anchorY: 0.5
});
missileButtonBackground.width = 200;
missileButtonBackground.height = 100;
missileButtonBackground.tint = 0xFF4444; // Red color
var missileButtonText = new Text2('MISSILE', {
	size: 50,
	fill: 0xFFFFFF,
	weight: 800
});
missileButtonText.anchor.set(0.5, 0.5);
missileButton.addChild(missileButtonText);
missileButton.x = 580; // Position to the right of language button
missileButton.y = 2732 - 150; // Same Y position
game.addChild(missileButton);
missileButton.down = function () {
	// Find strongest enemy to target
	var strongestEnemy = null;
	var highestHealth = 0;
	for (var i = 0; i < enemies.length; i++) {
		if (enemies[i].health > highestHealth) {
			highestHealth = enemies[i].health;
			strongestEnemy = enemies[i];
		}
	}
	if (strongestEnemy && gold >= 50) {
		// Missile costs 50 gold
		setGold(gold - 50);
		launchMissile(2048 / 2, 0, strongestEnemy.x, strongestEnemy.y, 100, 4, CELL_SIZE * 2.5);
		// Visual feedback
		tween(missileButton, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(missileButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100,
					easing: tween.easeOut
				});
			}
		});
		var notification = game.addChild(new Notification('Missile launched!'));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	} else if (!strongestEnemy) {
		var notification = game.addChild(new Notification('No targets available!'));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	} else {
		var notification = game.addChild(new Notification('Need 50 gold for missile!'));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	}
};
hawkButton.down = function () {
	hawkPressCount++;
	// Visual feedback
	tween(hawkButton, {
		scaleX: 0.9,
		scaleY: 0.9
	}, {
		duration: 100,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(hawkButton, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 100,
				easing: tween.easeOut
			});
		}
	});
	if (hawkPressCount >= 5) {
		// HAWK JUMPSCARE!
		var hawkJumpscare = new Container();
		// Create large hawk sprite
		var hawkSprite = hawkJumpscare.attachAsset('hawk', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		hawkSprite.width = 800;
		hawkSprite.height = 800;
		// Position at center
		hawkJumpscare.x = 2048 / 2;
		hawkJumpscare.y = 2732 / 2;
		hawkJumpscare.scaleX = 0.1;
		hawkJumpscare.scaleY = 0.1;
		hawkJumpscare.alpha = 0;
		game.addChild(hawkJumpscare);
		// Jumpscare animation
		tween(hawkJumpscare, {
			scaleX: 2,
			scaleY: 2,
			alpha: 1
		}, {
			duration: 200,
			easing: tween.backOut,
			onFinish: function onFinish() {
				// Flash screen red
				LK.effects.flashScreen(0xFF0000, 500);
				// Hold for a moment then fade out
				tween(hawkJumpscare, {
					alpha: 0,
					scaleX: 0.5,
					scaleY: 0.5
				}, {
					duration: 1000,
					delay: 800,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						hawkJumpscare.destroy();
					}
				});
			}
		});
		// Reset counter
		hawkPressCount = 0;
		// Show notification
		var notification = game.addChild(new Notification("🦅 HAWK ATTACK! 🦅"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	}
};
var towerTypes = ['Tunnan', 'Lansen', 'Draken', 'Viggen', 'Gripen', 'Super Viggen'];
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;
// Play background music
LK.playMusic('JollyTug');
game.update = function () {
	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 = grid.height - 200;
			}
			// 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);
				}
				// Scale difficulty with wave number but don't apply to boss
				// as bosses already have their health multiplier
				// Use exponential scaling for health
				var healthMultiplier = Math.pow(1.12, currentWave); // ~20% increase per wave
				enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
				enemy.health = enemy.maxHealth;
				// Increment speed slightly with wave number
				//enemy.speed = enemy.speed + currentWave * 0.002;
				// 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;
		}
	}
	// Batch enemy processing for better performance
	var deadEnemies = [];
	var escapedEnemies = [];
	var uiNeedsUpdate = false;
	for (var a = 0; a < enemies.length; a++) {
		var enemy = enemies[a];
		if (enemy.health <= 0) {
			deadEnemies.push({
				enemy: enemy,
				index: a
			});
		} else if (grid.updateEnemy(enemy)) {
			escapedEnemies.push({
				enemy: enemy,
				index: a
			});
		}
	}
	// Process dead enemies in batch
	for (var i = 0; i < deadEnemies.length; i++) {
		var deadData = deadEnemies[i];
		var enemy = deadData.enemy;
		for (var j = 0; j < enemy.bulletsTargetingThis.length; j++) {
			var bullet = enemy.bulletsTargetingThis[j];
			bullet.targetEnemy = null;
		}
		// Boss enemies give more gold and score
		var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
		var goldIndicator = new GoldIndicator(goldEarned, enemy.x, enemy.y);
		game.addChild(goldIndicator);
		setGold(gold + goldEarned);
		// Give more score for defeating a boss
		var scoreValue = enemy.isBoss ? 100 : 5;
		score += scoreValue;
		uiNeedsUpdate = true;
		// Add a notification for boss defeat
		if (enemy.isBoss) {
			var notification = game.addChild(new Notification("Boss defeated! +" + goldEarned + " gold!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 150;
		}
		// 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);
		}
	}
	// Process escaped enemies in batch
	for (var i = 0; i < escapedEnemies.length; i++) {
		var escapedData = escapedEnemies[i];
		var enemy = escapedData.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);
		}
		lives = Math.max(0, lives - 1);
		uiNeedsUpdate = true;
	}
	// Remove enemies from array in reverse order (highest index first)
	var allRemovals = deadEnemies.concat(escapedEnemies);
	allRemovals.sort(function (a, b) {
		return b.index - a.index;
	});
	for (var i = 0; i < allRemovals.length; i++) {
		enemies.splice(allRemovals[i].index, 1);
	}
	// Update UI only once if needed
	if (uiNeedsUpdate) {
		updateUI();
	}
	// Check game over only once
	if (lives <= 0) {
		LK.showGameOver();
	}
	// Optimize bullet cleanup - batch removals
	var bulletsToRemove = [];
	for (var i = 0; i < bullets.length; i++) {
		if (!bullets[i].parent) {
			bulletsToRemove.push(i);
			if (bullets[i].targetEnemy) {
				var targetEnemy = bullets[i].targetEnemy;
				var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
				if (bulletIndex !== -1) {
					targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
				}
			}
		}
	}
	// Remove bullets in reverse order to maintain indices
	for (var i = bulletsToRemove.length - 1; i >= 0; i--) {
		bullets.splice(bulletsToRemove[i], 1);
	}
	// Optimize missile cleanup - batch removals
	var missilesToRemove = [];
	for (var i = 0; i < missiles.length; i++) {
		if (!missiles[i].parent) {
			missilesToRemove.push(i);
		}
	}
	// Remove missiles in reverse order to maintain indices
	for (var i = missilesToRemove.length - 1; i >= 0; i--) {
		missiles.splice(missilesToRemove[i], 1);
	}
	if (towerPreview.visible) {
		towerPreview.checkPlacement();
	}
	if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) {
		LK.showYouWin();
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
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;
		}
		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
			self.targetEnemy.health -= self.damage;
			if (self.targetEnemy.health <= 0) {
				self.targetEnemy.health = 0;
			} else {
				self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70;
			}
			// Apply special effects based on bullet type
			if (self.type === 'splash') {
				// Create visual splash effect
				var splashEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'splash');
				game.addChild(splashEffect);
				// Splash damage to nearby enemies
				var splashRadius = CELL_SIZE * 1.5;
				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 {
								otherEnemy.healthBar.width = otherEnemy.health / otherEnemy.maxHealth * 70;
							}
						}
					}
				}
			} else if (self.type === 'slow') {
				// Prevent slow effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create visual slow effect
					var slowEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'slow');
					game.addChild(slowEffect);
					// Apply slow effect
					// Make slow percentage scale with tower level (default 50%, up to 80% at max level)
					var slowPct = 0.5;
					if (self.sourceTowerLevel !== undefined) {
						// Scale: 50% at level 1, 60% at 2, 65% at 3, 70% at 4, 75% at 5, 80% at 6
						var slowLevels = [0.5, 0.6, 0.65, 0.7, 0.75, 0.8];
						var idx = Math.max(0, Math.min(5, self.sourceTowerLevel - 1));
						slowPct = slowLevels[idx];
					}
					if (!self.targetEnemy.slowed) {
						self.targetEnemy.originalSpeed = self.targetEnemy.speed;
						self.targetEnemy.speed *= 1 - slowPct; // Slow by X%
						self.targetEnemy.slowed = true;
						self.targetEnemy.slowDuration = 180; // 3 seconds at 60 FPS
					} else {
						self.targetEnemy.slowDuration = 180; // Reset duration
					}
				}
			} else if (self.type === 'poison') {
				// Prevent poison effect on immune enemies
				if (!self.targetEnemy.isImmune) {
					// Create visual poison effect
					var poisonEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'poison');
					game.addChild(poisonEffect);
					// Apply poison 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
				}
			} else if (self.type === 'sniper') {
				// Create visual critical hit effect for sniper
				var sniperEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'sniper');
				game.addChild(sniperEffect);
			}
			self.destroy();
		} else {
			var angle = Math.atan2(dy, dx);
			self.x += Math.cos(angle) * self.speed;
			self.y += Math.sin(angle) * self.speed;
		}
	};
	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 = [];
	var numberLabel = new Text2('0', {
		size: 30,
		fill: 0xFFFFFF,
		weight: 800
	});
	numberLabel.anchor.set(.5, .5);
	self.addChild(numberLabel);
	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();
						numberLabel.setText("-");
						cellGraphics.tint = 0x880000;
						return;
					}
					numberLabel.visible = true;
					var tint = Math.floor(data.score / maxScore * 0x88);
					var towerInRangeHighlight = false;
					if (selectedTower && data.towersInRange && data.towersInRange.indexOf(selectedTower) !== -1) {
						towerInRangeHighlight = true;
						cellGraphics.tint = 0x0088ff;
					} else {
						cellGraphics.tint = 0x88 - tint << 8 | tint;
					}
					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;
						var angle = Math.atan2(oy, ox);
						if (!debugArrows[a]) {
							debugArrows[a] = LK.getAsset('arrow', {
								anchorX: -.5,
								anchorY: 0.5
							});
							debugArrows[a].alpha = .5;
							self.addChildAt(debugArrows[a], 1);
						}
						debugArrows[a].rotation = angle;
					}
					break;
				}
			case 1:
				{
					self.removeArrows();
					cellGraphics.tint = 0xaaaaaa;
					numberLabel.visible = false;
					break;
				}
			case 3:
				{
					self.removeArrows();
					cellGraphics.tint = 0x008800;
					numberLabel.visible = false;
					break;
				}
		}
		numberLabel.setText(Math.floor(data.score / 1000) / 10);
	};
});
// 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 'poison':
			effectGraphics.tint = 0x00FFAA;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'sniper':
			effectGraphics.tint = 0xFF5500;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'missile_explosion':
			effectGraphics.tint = 0xFF0000;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 3;
			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
	switch (self.type) {
		case 'fast':
			self.speed *= 2; // Soviet fast tanks (T-34)
			self.maxHealth = 100;
			break;
		case 'immune':
			self.isImmune = true; // Soviet heavy tanks (KV-1)
			self.maxHealth = 80;
			break;
		case 'flying':
			self.isFlying = true; // Soviet aircraft (MiG-21)
			self.maxHealth = 80;
			break;
		case 'swarm':
			self.maxHealth = 50; // Soviet infantry squads
			break;
		case 'geese':
			self.isFlying = true; // Geese can fly
			self.maxHealth = 40; // Slightly weaker than normal
			self.speed *= 1.3; // Faster than normal enemies
			break;
		case 'normal':
		default:
			// Soviet medium tanks (T-55)
			break;
	}
	if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') {
		self.isBoss = true;
		// Boss enemies have 20x health and are larger
		self.maxHealth *= 20;
		// Slower speed for bosses
		self.speed = self.speed * 0.7;
	}
	self.health = self.maxHealth;
	// Get appropriate asset for this enemy type
	var assetId = 'enemy';
	if (self.type !== 'normal') {
		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
		var shadowGraphics = self.shadow.attachAsset(assetId || 'enemy', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow effect
		shadowGraphics.tint = 0x000000; // Black shadow
		shadowGraphics.alpha = 0.4; // 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('healthBarOutline', {
		anchorX: 0,
		anchorY: 0.5
	});
	var healthBarBG = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	var healthBar = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	healthBarBG.y = healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	healthBarOutline.x = -healthBarOutline.width / 2;
	healthBarBG.x = healthBar.x = -healthBar.width / 2 - .5;
	healthBar.tint = 0x00ff00;
	healthBarBG.tint = 0xff0000;
	self.healthBar = healthBar;
	self.update = function () {
		if (self.health <= 0) {
			self.health = 0;
			self.healthBar.width = 0;
			return; // Early exit for dead enemies
		}
		// Cache enemy graphics reference for performance
		var graphics = self.children[0];
		if (!graphics) return;
		// Track if we need to update tint (expensive operation)
		var needTintUpdate = false;
		var newTint = 0xFFFFFF;
		// Handle slow effect
		if (self.isImmune) {
			// Immune enemies cannot be slowed or poisoned, clear any such effects
			if (self.slowed || self.poisoned) {
				self.slowed = false;
				self.slowEffect = false;
				self.poisoned = false;
				self.poisonEffect = false;
				// Reset speed to original if needed
				if (self.originalSpeed !== undefined) {
					self.speed = self.originalSpeed;
				}
				needTintUpdate = true;
			}
		} else {
			// Handle slow effect
			if (self.slowed) {
				// Visual indication of slowed status
				if (!self.slowEffect) {
					self.slowEffect = true;
					needTintUpdate = true;
				}
				self.slowDuration--;
				if (self.slowDuration <= 0) {
					self.speed = self.originalSpeed;
					self.slowed = false;
					self.slowEffect = false;
					needTintUpdate = true;
				}
			}
			// Handle poison effect (only every 30 frames for damage)
			if (self.poisoned) {
				// Visual indication of poisoned status
				if (!self.poisonEffect) {
					self.poisonEffect = true;
					needTintUpdate = true;
				}
				// Apply poison damage every 30 frames (twice per second)
				if (LK.ticks % 30 === 0) {
					self.health -= self.poisonDamage;
					if (self.health <= 0) {
						self.health = 0;
						return; // Early exit for newly dead enemies
					}
					self.healthBar.width = self.health / self.maxHealth * 70;
				}
				self.poisonDuration--;
				if (self.poisonDuration <= 0) {
					self.poisoned = false;
					self.poisonEffect = false;
					needTintUpdate = true;
				}
			}
		}
		// Set tint based on effect status (only if needed)
		if (needTintUpdate) {
			if (self.isImmune) {
				newTint = 0xFFFFFF;
			} else if (self.poisoned && self.slowed) {
				// Combine poison (0x00FFAA) and slow (0x9900FF) colors
				// Simple average: R: (0+153)/2=76, G: (255+0)/2=127, B: (170+255)/2=212
				newTint = 0x4C7FD4;
			} else if (self.poisoned) {
				newTint = 0x00FFAA;
			} else if (self.slowed) {
				newTint = 0x9900FF;
			} else {
				newTint = 0xFFFFFF;
			}
			graphics.tint = newTint;
		}
		// Only update rotation if we have a target and significant movement
		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 (graphics.targetRotation === undefined) {
					graphics.targetRotation = angle;
					graphics.rotation = angle;
				} else {
					if (Math.abs(angle - graphics.targetRotation) > 0.1) {
						// Increased threshold to reduce rotation updates
						tween.stop(graphics, {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = graphics.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;
						}
						graphics.targetRotation = angle;
						tween(graphics, {
							rotation: currentRotation + angleDiff
						}, {
							duration: 300,
							easing: tween.easeOut
						});
					}
				}
			}
		}
		// Only update health bar position if graphics height changed (rare)
		if (!self._lastGraphicsHeight || self._lastGraphicsHeight !== graphics.height) {
			healthBarOutline.y = healthBarBG.y = healthBar.y = -graphics.height / 2 - 10;
			self._lastGraphicsHeight = graphics.height;
		}
	};
	return self;
});
var GoldIndicator = 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 goldText = new Text2("+" + value, {
		size: 45,
		fill: 0xFFD700,
		weight: 800
	});
	goldText.anchor.set(0.5, 0.5);
	self.addChild(goldText);
	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 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;
			}
		}
		// Pre-filter ground enemies to reduce loop iterations
		var groundEnemies = [];
		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;
			}
			groundEnemies.push(enemy);
		}
		// Check path validity for ground enemies only
		for (var a = 0; a < groundEnemies.length; a++) {
			var enemy = groundEnemies[a];
			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 GuideSystem = Container.expand(function () {
	var self = Container.call(this);
	self.currentTip = 0;
	self.tips = ["Welcome to Tower Defense! Place towers to stop enemies.", "Drag towers from the bottom to build them on the battlefield.", "Different towers have different strengths - experiment!", "Upgrade towers by clicking on them after placement.", "The brown button with an eagle gives you 70 gold if pressed enough!", "Flying enemies can only be hit by certain tower types.", "Boss waves appear every 10 rounds - prepare accordingly!", "Use missiles for emergency situations - they cost 50 gold."];
	self.visible = false;
	self.tipShown = false;
	// Background
	var guideBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	guideBackground.width = 1800;
	guideBackground.height = 300;
	guideBackground.tint = 0x2C3E50;
	guideBackground.alpha = 0.95;
	// Title
	var titleText = new Text2("Game Guide", {
		size: 80,
		fill: 0xFFD700,
		weight: 800
	});
	titleText.anchor.set(0.5, 0.5);
	titleText.y = -80;
	self.addChild(titleText);
	// Tip text
	var tipText = new Text2("", {
		size: 60,
		fill: 0xFFFFFF,
		weight: 400
	});
	tipText.anchor.set(0.5, 0.5);
	tipText.y = 0;
	self.addChild(tipText);
	// Navigation buttons
	var prevButton = new Container();
	var prevBg = prevButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	prevBg.width = 200;
	prevBg.height = 80;
	prevBg.tint = 0x3498DB;
	var prevText = new Text2("Previous", {
		size: 45,
		fill: 0xFFFFFF,
		weight: 800
	});
	prevText.anchor.set(0.5, 0.5);
	prevButton.addChild(prevText);
	prevButton.x = -400;
	prevButton.y = 80;
	self.addChild(prevButton);
	var nextButton = new Container();
	var nextBg = nextButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	nextBg.width = 200;
	nextBg.height = 80;
	nextBg.tint = 0x3498DB;
	var nextText = new Text2("Next", {
		size: 45,
		fill: 0xFFFFFF,
		weight: 800
	});
	nextText.anchor.set(0.5, 0.5);
	nextButton.addChild(nextText);
	nextButton.x = 0;
	nextButton.y = 80;
	self.addChild(nextButton);
	var closeButton = new Container();
	var closeBg = closeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBg.width = 200;
	closeBg.height = 80;
	closeBg.tint = 0xE74C3C;
	var closeText = new Text2("Close", {
		size: 45,
		fill: 0xFFFFFF,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	closeButton.x = 400;
	closeButton.y = 80;
	self.addChild(closeButton);
	self.updateTip = function () {
		tipText.setText(self.tips[self.currentTip]);
		// Update button states
		prevBg.tint = self.currentTip > 0 ? 0x3498DB : 0x95A5A6;
		nextBg.tint = self.currentTip < self.tips.length - 1 ? 0x3498DB : 0x95A5A6;
	};
	self.showGuide = function () {
		self.visible = true;
		self.currentTip = 0;
		self.updateTip();
		// Animate in
		self.alpha = 0;
		self.scaleX = 0.8;
		self.scaleY = 0.8;
		tween(self, {
			alpha: 1,
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 300,
			easing: tween.backOut
		});
	};
	self.hideGuide = function () {
		tween(self, {
			alpha: 0,
			scaleX: 0.8,
			scaleY: 0.8
		}, {
			duration: 200,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.visible = false;
			}
		});
	};
	prevButton.down = function () {
		if (self.currentTip > 0) {
			self.currentTip--;
			self.updateTip();
			// Visual feedback
			tween(prevButton, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 100,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(prevButton, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 100,
						easing: tween.easeOut
					});
				}
			});
		}
	};
	nextButton.down = function () {
		if (self.currentTip < self.tips.length - 1) {
			self.currentTip++;
			self.updateTip();
			// Visual feedback
			tween(nextButton, {
				scaleX: 0.9,
				scaleY: 0.9
			}, {
				duration: 100,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(nextButton, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 100,
						easing: tween.easeOut
					});
				}
			});
		}
	};
	closeButton.down = function () {
		self.hideGuide();
		// Visual feedback
		tween(closeButton, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(closeButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100,
					easing: tween.easeOut
				});
			}
		});
	};
	return self;
});
var LanguageButton = Container.expand(function () {
	var self = Container.call(this);
	// Load saved language or default to English
	self.currentLanguage = storage.language || 'EN';
	var buttonBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 120;
	buttonBackground.height = 80;
	buttonBackground.tint = 0x4169E1; // Royal blue
	var flagText = new Text2(self.currentLanguage, {
		size: 40,
		fill: 0xFFFFFF,
		weight: 800
	});
	flagText.anchor.set(0.5, 0.5);
	self.addChild(flagText);
	// Available languages
	self.languages = ['EN', 'ES', 'FR', 'DE', 'RU', 'ZH', 'JP', 'AR'];
	self.languageNames = {
		'EN': 'English',
		'ES': 'Español',
		'FR': 'Français',
		'DE': 'Deutsch',
		'RU': 'Русский',
		'ZH': '中文',
		'JP': '日本語',
		'AR': 'العربية'
	};
	// Translation dictionary for key game text
	self.translations = {
		'EN': {
			'nextWave': 'Next Wave',
			'gold': 'Gold',
			'lives': 'Lives',
			'score': 'Score',
			'startGame': 'Start Game',
			'started': 'Started!',
			'hawkButton': '🦅'
		},
		'ES': {
			'nextWave': 'Próxima Ola',
			'gold': 'Oro',
			'lives': 'Vidas',
			'score': 'Puntuación',
			'startGame': 'Comenzar Juego',
			'started': '¡Comenzado!',
			'hawkButton': '🦅'
		},
		'FR': {
			'nextWave': 'Vague Suivante',
			'gold': 'Or',
			'lives': 'Vies',
			'score': 'Score',
			'startGame': 'Commencer',
			'started': 'Commencé!',
			'hawkButton': '🦅'
		},
		'DE': {
			'nextWave': 'Nächste Welle',
			'gold': 'Gold',
			'lives': 'Leben',
			'score': 'Punkte',
			'startGame': 'Spiel Starten',
			'started': 'Gestartet!',
			'hawkButton': '🦅'
		},
		'RU': {
			'nextWave': 'Следующая Волна',
			'gold': 'Золото',
			'lives': 'Жизни',
			'score': 'Счёт',
			'startGame': 'Начать Игру',
			'started': 'Начато!',
			'hawkButton': '🦅'
		},
		'ZH': {
			'nextWave': '下一波',
			'gold': '金币',
			'lives': '生命',
			'score': '分数',
			'startGame': '开始游戏',
			'started': '已开始!',
			'hawkButton': '🦅'
		},
		'JP': {
			'nextWave': '次の波',
			'gold': 'ゴールド',
			'lives': 'ライフ',
			'score': 'スコア',
			'startGame': 'ゲーム開始',
			'started': '開始!',
			'hawkButton': '🦅'
		},
		'AR': {
			'nextWave': 'الموجة التالية',
			'gold': 'ذهب',
			'lives': 'الأرواح',
			'score': 'النتيجة',
			'startGame': 'بدء اللعبة',
			'started': 'بدأت!',
			'hawkButton': '🦅'
		}
	};
	// Update game language function
	self.updateGameLanguage = function () {
		var currentLang = self.translations[self.currentLanguage] || self.translations['EN'];
		// Update UI text elements
		if (goldText) {
			goldText.setText(currentLang.gold + ': ' + gold);
		}
		if (livesText) {
			livesText.setText(currentLang.lives + ': ' + lives);
		}
		if (scoreText) {
			scoreText.setText(currentLang.score + ': ' + score);
		}
		// Update hawk button text
		if (hawkButtonText) {
			hawkButtonText.setText(currentLang.hawkButton);
		}
		// Update next wave button if it exists
		if (nextWaveButton && nextWaveButton.children && nextWaveButton.children[1]) {
			nextWaveButton.children[1].setText(currentLang.nextWave);
		}
		// Update wave indicator start button if it exists
		if (waveIndicator && waveIndicator.waveMarkers && waveIndicator.waveMarkers[0]) {
			var startMarker = waveIndicator.waveMarkers[0];
			if (startMarker.children[1]) {
				startMarker.children[1].setText(currentLang.startGame);
			}
			if (startMarker.children[2]) {
				startMarker.children[2].setText(currentLang.startGame);
			}
		}
	};
	self.down = function () {
		// Cycle to next language
		var currentIndex = self.languages.indexOf(self.currentLanguage);
		var nextIndex = (currentIndex + 1) % self.languages.length;
		self.currentLanguage = self.languages[nextIndex];
		// Save to storage
		storage.language = self.currentLanguage;
		// Update display
		flagText.setText(self.currentLanguage);
		// Update all game text with new language
		self.updateGameLanguage();
		// Visual feedback
		tween(self, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(self, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100,
					easing: tween.easeIn
				});
			}
		});
		// Show notification with language name
		var languageName = self.languageNames[self.currentLanguage];
		var notification = game.addChild(new Notification("Language: " + languageName));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
		// Flash the button with the cultural colors
		var culturalColors = {
			'EN': 0x0052CC,
			// Blue
			'ES': 0xFFD700,
			// Gold
			'FR': 0x0055A4,
			// French blue
			'DE': 0x000000,
			// Black
			'RU': 0xDA020E,
			// Red
			'ZH': 0xFF0000,
			// Red
			'JP': 0xFF0000,
			// Red
			'AR': 0x00FF00 // Green
		};
		var originalTint = buttonBackground.tint;
		var culturalColor = culturalColors[self.currentLanguage] || 0x4169E1;
		tween(buttonBackground, {
			tint: culturalColor
		}, {
			duration: 200,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(buttonBackground, {
					tint: originalTint
				}, {
					duration: 300,
					easing: tween.easeIn
				});
			}
		});
	};
	return self;
});
var Missile = Container.expand(function (startX, startY, targetX, targetY, damage, speed, explosionRadius) {
	var self = Container.call(this);
	self.targetX = targetX || 0;
	self.targetY = targetY || 0;
	self.damage = damage || 50;
	self.speed = speed || 3;
	self.explosionRadius = explosionRadius || CELL_SIZE * 2;
	self.x = startX;
	self.y = startY;
	var missileGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	missileGraphics.tint = 0xFF4444; // Red color for missiles
	missileGraphics.width = 40;
	missileGraphics.height = 40;
	// Calculate trajectory
	var dx = self.targetX - self.x;
	var dy = self.targetY - self.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	self.directionX = dx / distance;
	self.directionY = dy / distance;
	// Rotate missile to face target
	var angle = Math.atan2(dy, dx);
	missileGraphics.rotation = angle;
	self.update = function () {
		// Move towards target
		self.x += self.directionX * self.speed;
		self.y += self.directionY * self.speed;
		// Check if reached target area
		var currentDx = self.targetX - self.x;
		var currentDy = self.targetY - self.y;
		var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy);
		if (currentDistance < self.speed * 2) {
			// Explode at target location
			self.explode();
			self.destroy();
		}
	};
	self.explode = function () {
		// Create explosion effect
		var explosionEffect = new EffectIndicator(self.x, self.y, 'missile_explosion');
		game.addChild(explosionEffect);
		// Apply splash damage to all enemies in radius
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var explosionDx = enemy.x - self.x;
			var explosionDy = enemy.y - self.y;
			var explosionDistance = Math.sqrt(explosionDx * explosionDx + explosionDy * explosionDy);
			if (explosionDistance <= self.explosionRadius) {
				// Apply damage based on distance (closer = more damage)
				var damageMultiplier = 1 - explosionDistance / self.explosionRadius * 0.5;
				var actualDamage = self.damage * damageMultiplier;
				enemy.health -= actualDamage;
				if (enemy.health <= 0) {
					enemy.health = 0;
				} else {
					enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
				}
			}
		}
	};
	return self;
});
var NextWaveButton = Container.expand(function () {
	var self = Container.call(this);
	var buttonBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 300;
	buttonBackground.height = 100;
	buttonBackground.tint = 0x0088FF;
	var buttonText = new Text2("Next Wave", {
		size: 50,
		fill: 0xFFFFFF,
		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 = 0x0088FF;
			self.alpha = 1;
		} else {
			self.enabled = false;
			self.visible = false;
			buttonBackground.tint = 0x888888;
			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!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 150;
		}
	};
	return self;
});
var Notification = Container.expand(function (message) {
	var self = Container.call(this);
	var notificationGraphics = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var notificationText = new Text2(message, {
		size: 50,
		fill: 0x000000,
		weight: 800
	});
	notificationText.anchor.set(0.5, 0.5);
	notificationGraphics.width = notificationText.width + 30;
	self.addChild(notificationText);
	self.alpha = 1;
	var fadeOutTime = 120;
	self.update = function () {
		if (fadeOutTime > 0) {
			fadeOutTime--;
			self.alpha = Math.min(fadeOutTime / 120 * 2, 1);
		} else {
			self.destroy();
		}
	};
	return self;
});
var SourceTower = Container.expand(function (towerType) {
	var self = Container.call(this);
	self.towerType = towerType || 'default';
	// Increase size of base for easier touch
	var baseGraphics = self.attachAsset('tower', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.3,
		scaleY: 1.3
	});
	switch (self.towerType) {
		case 'Lansen':
			baseGraphics.tint = 0x005293;
			break;
		case 'Draken':
			baseGraphics.tint = 0xFFD100;
			break;
		case 'Viggen':
			baseGraphics.tint = 0x00AA44;
			break;
		case 'Gripen':
			baseGraphics.tint = 0x666666;
			break;
		case 'Super Viggen':
			baseGraphics.tint = 0x0066CC;
			break;
		default:
			baseGraphics.tint = 0x005293;
	}
	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 typeLabel = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
		size: 50,
		fill: 0xFFFFFF,
		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: 0xFFD700,
		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 = gold >= getTowerCost(self.towerType);
		// Set opacity based on affordability
		self.alpha = canAfford ? 1 : 0.5;
	};
	return self;
});
var Tower = Container.expand(function (id) {
	var self = Container.call(this);
	self.id = id || 'default';
	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 'Draken':
				// Draken: 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 'Viggen':
				// Viggen: base 2, +0.2 per level (max ~4 blocks at max level)
				return (2 + (self.level - 1) * 0.2) * CELL_SIZE;
			case 'Lansen':
				// Lansen: base 2.5, +0.5 per level
				return (2.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'Gripen':
				// Gripen: base 3.5, +0.5 per level
				return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'Super Viggen':
				// Super Viggen: base 3.2, +0.5 per level
				return (3.2 + (self.level - 1) * 0.5) * CELL_SIZE;
			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 = 10;
	self.lastFired = 0;
	self.targetEnemy = null;
	switch (self.id) {
		case 'Lansen':
			self.fireRate = 30;
			self.damage = 5;
			self.range = 2.5 * CELL_SIZE;
			self.bulletSpeed = 7;
			break;
		case 'Draken':
			self.fireRate = 90;
			self.damage = 25;
			self.range = 5 * CELL_SIZE;
			self.bulletSpeed = 25;
			break;
		case 'Viggen':
			self.fireRate = 75;
			self.damage = 15;
			self.range = 2 * CELL_SIZE;
			self.bulletSpeed = 4;
			break;
		case 'Gripen':
			self.fireRate = 50;
			self.damage = 8;
			self.range = 3.5 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
		case 'Super Viggen':
			self.fireRate = 70;
			self.damage = 12;
			self.range = 3.2 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
	}
	var baseGraphics = self.attachAsset('tower', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	switch (self.id) {
		case 'Lansen':
			baseGraphics.tint = 0x005293;
			break;
		case 'Draken':
			baseGraphics.tint = 0xFFD100;
			break;
		case 'Viggen':
			baseGraphics.tint = 0x00AA44;
			break;
		case 'Gripen':
			baseGraphics.tint = 0x666666;
			break;
		case 'Super Viggen':
			baseGraphics.tint = 0x0066CC;
			break;
		default:
			baseGraphics.tint = 0x005293;
	}
	var levelIndicators = [];
	var maxDots = self.maxLevel;
	var dotSpacing = baseGraphics.width / (maxDots + 1);
	var dotSize = CELL_SIZE / 6;
	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 = -CELL_SIZE + dotSpacing * (i + 1);
		dot.y = CELL_SIZE * 0.7;
		self.addChild(dot);
		levelIndicators.push(dot);
	}
	var gunContainer = new Container();
	self.addChild(gunContainer);
	var gunGraphics = gunContainer.attachAsset('defense', {
		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 = 0xFFFFFF;
			} else {
				switch (self.id) {
					case 'Lansen':
						towerLevelIndicator.tint = 0x005293;
						break;
					case 'Draken':
						towerLevelIndicator.tint = 0xFFD100;
						break;
					case 'Viggen':
						towerLevelIndicator.tint = 0x00AA44;
						break;
					case 'Gripen':
						towerLevelIndicator.tint = 0x666666;
						break;
					case 'Super Viggen':
						towerLevelIndicator.tint = 0x0066CC;
						break;
					default:
						towerLevelIndicator.tint = 0x005293;
				}
			}
		}
	};
	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 (gold >= upgradeCost) {
				setGold(gold - upgradeCost);
				self.level++;
				// Apply specialized upgrades based on tower type and level
				applyTowerUpgrade(self);
				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 gold to upgrade!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.findTarget = function () {
		var closestEnemy = null;
		var closestScore = Infinity;
		var towerRange = self.getRange();
		var towerRangeSquared = towerRange * towerRange;
		// Early exit if no enemies
		if (enemies.length === 0) {
			self.targetEnemy = null;
			return null;
		}
		// Cache tower position
		var towerX = self.x;
		var towerY = self.y;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			// Quick bounds check before distance calculation
			var dx = enemy.x - towerX;
			var dy = enemy.y - towerY;
			// Skip if obviously out of range (Manhattan distance approximation)
			if (Math.abs(dx) > towerRange || Math.abs(dy) > towerRange) {
				continue;
			}
			var distanceSquared = dx * dx + dy * dy;
			// Use squared distance for initial check (faster)
			if (distanceSquared <= towerRangeSquared) {
				// 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 distToGoalSq = (goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY);
						// Use squared distance to goal as score (avoid sqrt)
						if (distToGoalSq < closestScore) {
							closestScore = distToGoalSq;
							closestEnemy = enemy;
						}
					} else {
						// If no flying target yet (shouldn't happen), prioritize by distance to tower
						if (distanceSquared < closestScore) {
							closestScore = distanceSquared;
							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 () {
		self.targetEnemy = self.findTarget();
		if (self.targetEnemy) {
			var dx = self.targetEnemy.x - self.x;
			var dy = self.targetEnemy.y - self.y;
			var angle = Math.atan2(dy, dx);
			gunContainer.rotation = angle;
			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;
		tween(upgradeMenu, {
			y: 2732 - 225
		}, {
			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;
				// Handle special firing modes
				var bulletsToFire = [];
				if (self.hasTripleShot) {
					// Triple shot: fire 3 bullets in a spread
					for (var shotIndex = 0; shotIndex < 3; shotIndex++) {
						var spreadAngle = gunContainer.rotation + (shotIndex - 1) * 0.3;
						var spreadX = self.x + Math.cos(spreadAngle) * 40;
						var spreadY = self.y + Math.sin(spreadAngle) * 40;
						bulletsToFire.push({
							x: spreadX,
							y: spreadY
						});
					}
				} else {
					// Normal single shot
					bulletsToFire.push({
						x: bulletX,
						y: bulletY
					});
				}
				// Fire all bullets
				for (var bulletIndex = 0; bulletIndex < bulletsToFire.length; bulletIndex++) {
					var bulletPos = bulletsToFire[bulletIndex];
					var bullet = new Bullet(bulletPos.x, bulletPos.y, self.targetEnemy, self.damage, self.bulletSpeed);
					// Set bullet type based on tower type
					bullet.type = self.id;
					// Apply specialized bullet properties
					bullet.hasPiercingBullets = self.hasPiercingBullets;
					bullet.hasExplosiveRounds = self.hasExplosiveRounds;
					bullet.hasSniperShots = self.hasSniperShots;
					bullet.hasArmorPiercing = self.hasArmorPiercing;
					bullet.hasRailgun = self.hasRailgun;
					bullet.splashRadius = self.splashRadius;
					bullet.hasBurningEffect = self.hasBurningEffect;
					bullet.hasChainExplosions = self.hasChainExplosions;
					bullet.hasNuclearWarhead = self.hasNuclearWarhead;
					bullet.slowPercentage = self.slowPercentage;
					bullet.hasFreezeEffect = self.hasFreezeEffect;
					bullet.hasIceShards = self.hasIceShards;
					bullet.slowDuration = self.slowDuration;
					bullet.hasAbsoluteZero = self.hasAbsoluteZero;
					bullet.poisonSpreads = self.poisonSpreads;
					bullet.hasToxicCloud = self.hasToxicCloud;
					bullet.poisonDamageMultiplier = self.poisonDamageMultiplier;
					bullet.hasCorrosiveAcid = self.hasCorrosiveAcid;
					bullet.hasPlagueSpread = self.hasPlagueSpread;
					// For Gripen tower, pass level for scaling slow effect
					if (self.id === 'Gripen') {
						bullet.sourceTowerLevel = self.level;
					}
					// Customize bullet appearance based on tower type
					switch (self.id) {
						case 'Lansen':
							bullet.children[0].tint = 0x005293;
							bullet.children[0].width = 20;
							bullet.children[0].height = 20;
							break;
						case 'Draken':
							bullet.children[0].tint = 0xFFD100;
							bullet.children[0].width = 15;
							bullet.children[0].height = 15;
							break;
						case 'Viggen':
							bullet.children[0].tint = 0x00AA44;
							bullet.children[0].width = 40;
							bullet.children[0].height = 40;
							break;
						case 'Gripen':
							bullet.children[0].tint = 0x666666;
							bullet.children[0].width = 35;
							bullet.children[0].height = 35;
							break;
						case 'Super Viggen':
							bullet.children[0].tint = 0x0066CC;
							bullet.children[0].width = 35;
							bullet.children[0].height = 35;
							break;
					}
					game.addChild(bullet);
					bullets.push(bullet);
					self.targetEnemy.bulletsTargetingThis.push(bullet);
				}
				// --- 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();
	};
	return self;
});
var TowerPreview = Container.expand(function () {
	var self = Container.call(this);
	var towerRange = 3;
	var rangeInPixels = towerRange * CELL_SIZE;
	self.towerType = 'default';
	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 = gold >= 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 'Lansen':
				previewGraphics.tint = 0x005293;
				break;
			case 'Draken':
				previewGraphics.tint = 0xFFD100;
				break;
			case 'Viggen':
				previewGraphics.tint = 0x00AA44;
				break;
			case 'Gripen':
				previewGraphics.tint = 0x666666;
				break;
			case 'Super Viggen':
				previewGraphics.tint = 0x0066CC;
				break;
			default:
				previewGraphics.tint = 0x005293;
		}
		if (!self.canPlace || !self.hasEnoughGold) {
			previewGraphics.tint = 0xFF0000;
		}
	};
	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 = gold >= 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;
	self.y = 2732 + 225;
	var menuBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	menuBackground.width = 2048;
	menuBackground.height = 500;
	menuBackground.tint = 0x444444;
	menuBackground.alpha = 0.9;
	var towerTypeText = new Text2(self.tower.id.charAt(0).toUpperCase() + self.tower.id.slice(1) + ' Tower', {
		size: 80,
		fill: 0xFFFFFF,
		weight: 800
	});
	towerTypeText.anchor.set(0, 0);
	towerTypeText.x = -840;
	towerTypeText.y = -160;
	self.addChild(towerTypeText);
	var statsText = new Text2('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s', {
		size: 70,
		fill: 0xFFFFFF,
		weight: 400
	});
	statsText.anchor.set(0, 0.5);
	statsText.x = -840;
	statsText.y = 50;
	self.addChild(statsText);
	var buttonsContainer = new Container();
	buttonsContainer.x = 500;
	self.addChild(buttonsContainer);
	var upgradeButton = new Container();
	buttonsContainer.addChild(upgradeButton);
	var buttonBackground = upgradeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBackground.width = 500;
	buttonBackground.height = 150;
	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 : gold >= upgradeCost ? 0x00AA00 : 0x888888;
	var upgradeDescription = isMaxLevel ? 'Max Level' : getTowerUpgradeDescription(self.tower.id, self.tower.level);
	var buttonText = new Text2(isMaxLevel ? 'Max Level' : upgradeDescription + '\nCost: ' + upgradeCost + ' gold', {
		size: 50,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	var sellButton = new Container();
	buttonsContainer.addChild(sellButton);
	var sellButtonBackground = sellButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	sellButtonBackground.width = 500;
	sellButtonBackground.height = 150;
	sellButtonBackground.tint = 0xCC0000;
	var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
	var sellValue = getTowerSellValue(totalInvestment);
	var sellButtonText = new Text2('Sell: +' + sellValue + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	sellButtonText.anchor.set(0.5, 0.5);
	sellButton.addChild(sellButtonText);
	upgradeButton.y = -85;
	sellButton.y = 85;
	var closeButton = new Container();
	self.addChild(closeButton);
	var closeBackground = closeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBackground.width = 90;
	closeBackground.height = 90;
	closeBackground.tint = 0xAA0000;
	var closeText = new Text2('X', {
		size: 68,
		fill: 0xFFFFFF,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	closeButton.x = menuBackground.width / 2 - 57;
	closeButton.y = -menuBackground.height / 2 + 57;
	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));
			}
			statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s');
			var newUpgradeDesc = getTowerUpgradeDescription(self.tower.id, self.tower.level);
			buttonText.setText(newUpgradeDesc + '\nCost: ' + upgradeCost + ' gold');
			var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
			var sellValue = Math.floor(totalInvestment * 0.6);
			sellButtonText.setText('Sell: +' + sellValue + ' gold');
			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);
		setGold(gold + sellValue);
		var notification = game.addChild(new Notification("Tower sold for " + sellValue + " gold!"));
		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) {
		hideUpgradeMenu(self);
		selectedTower = null;
		grid.renderDebug();
	};
	self.update = function () {
		if (self.tower.level >= self.tower.maxLevel) {
			if (buttonText.text !== 'Max Level') {
				buttonText.setText('Max Level');
				buttonBackground.tint = 0x888888;
			}
			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 = gold >= currentUpgradeCost;
		buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888;
		var newUpgradeDesc = getTowerUpgradeDescription(self.tower.id, self.tower.level);
		var newText = newUpgradeDesc + '\nCost: ' + currentUpgradeCost + ' gold';
		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('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	startBlock.width = blockWidth - 10;
	startBlock.height = 70 * 2;
	startBlock.tint = 0x00AA00;
	// 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: 0xFFFFFF,
		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) {
			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! Wave 1 incoming!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 150;
			// Show guide tip after a short delay
			LK.setTimeout(function () {
				if (guideSystem && !guideSystem.tipShown) {
					guideSystem.showGuide();
					guideSystem.tipShown = true;
				}
			}, 2000);
		}
	};
	for (var i = 0; i < totalWaves; i++) {
		var marker = new Container();
		var block = marker.attachAsset('notification', {
			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 = 0xAAAAAA;
			waveType = "Tanks";
			enemyType = "normal";
			enemyCount = 10;
		} else if (i === 1) {
			block.tint = 0x00AAFF;
			waveType = "T-34";
			enemyType = "fast";
			enemyCount = 10;
		} else if (i === 2) {
			block.tint = 0xAA0000;
			waveType = "KV-1";
			enemyType = "immune";
			enemyCount = 10;
		} else if (i === 3) {
			block.tint = 0xFFFF00;
			waveType = "MiG-21";
			enemyType = "flying";
			enemyCount = 10;
		} else if (i === 4) {
			block.tint = 0xFF00FF;
			waveType = "Infantry";
			enemyType = "swarm";
			enemyCount = 30;
		} else if (i === 5) {
			block.tint = 0x88FF88;
			waveType = "Geese";
			enemyType = "geese";
			enemyCount = 15;
		} else if (isBossWave) {
			// Boss waves: cycle through all boss types, last boss is always flying
			var bossTypes = ['normal', 'fast', 'immune', 'flying', 'geese'];
			var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
			if (i === totalWaves - 1) {
				// Last boss is always flying
				enemyType = 'flying';
				waveType = "Boss Flying";
				block.tint = 0xFFFF00;
			} else {
				enemyType = bossTypes[bossTypeIndex % bossTypes.length];
				switch (enemyType) {
					case 'normal':
						block.tint = 0xAAAAAA;
						waveType = "Boss T-55";
						break;
					case 'fast':
						block.tint = 0x00AAFF;
						waveType = "Boss T-34";
						break;
					case 'immune':
						block.tint = 0xAA0000;
						waveType = "Boss KV-1";
						break;
					case 'flying':
						block.tint = 0xFFFF00;
						waveType = "Boss MiG-21";
						break;
					case 'geese':
						block.tint = 0x88FF88;
						waveType = "Boss Geese";
						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 = 0xAAAAAA;
					break;
				case 'fast':
					block.tint = 0x00AAFF;
					break;
				case 'immune':
					block.tint = 0xAA0000;
					break;
				case 'flying':
					block.tint = 0xFFFF00;
					break;
				case 'geese':
					block.tint = 0x88FF88;
					break;
				default:
					block.tint = 0xFF0000;
					break;
			}
		} else if ((i + 1) % 5 === 0) {
			// Every 5th non-boss wave is fast tanks
			block.tint = 0x00AAFF;
			waveType = "T-34";
			enemyType = "fast";
			enemyCount = 10;
		} else if ((i + 1) % 4 === 0) {
			// Every 4th non-boss wave is heavy tanks
			block.tint = 0xAA0000;
			waveType = "KV-1";
			enemyType = "immune";
			enemyCount = 10;
		} else if ((i + 1) % 7 === 0) {
			// Every 7th non-boss wave is aircraft
			block.tint = 0xFFFF00;
			waveType = "MiG-21";
			enemyType = "flying";
			enemyCount = 10;
		} else if ((i + 1) % 8 === 0) {
			// Every 8th non-boss wave is geese
			block.tint = 0x88FF88;
			waveType = "Geese";
			enemyType = "geese";
			enemyCount = 15;
		} else if ((i + 1) % 3 === 0) {
			// Every 3rd non-boss wave is infantry
			block.tint = 0xFF00FF;
			waveType = "Infantry";
			enemyType = "swarm";
			enemyCount = 30;
		} else {
			block.tint = 0xAAAAAA;
			waveType = "Tanks";
			enemyType = "normal";
			enemyCount = 10;
		}
		// --- End new unified wave logic ---
		// 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;
		// Add shadow for wave type - 30% smaller than before
		var waveTypeShadow = new Text2(waveType, {
			size: 56,
			fill: 0x000000,
			weight: 800
		});
		waveTypeShadow.anchor.set(0.5, 0.5);
		waveTypeShadow.x = 4;
		waveTypeShadow.y = 4;
		marker.addChild(waveTypeShadow);
		// Add wave type text - 30% smaller than before
		var waveTypeText = new Text2(waveType, {
			size: 56,
			fill: 0xFFFFFF,
			weight: 800
		});
		waveTypeText.anchor.set(0.5, 0.5);
		waveTypeText.y = 0;
		marker.addChild(waveTypeText);
		// Add shadow for wave number - 20% larger than before
		var waveNumShadow = new Text2((i + 1).toString(), {
			size: 48,
			fill: 0x000000,
			weight: 800
		});
		waveNumShadow.anchor.set(1.0, 1.0);
		waveNumShadow.x = blockWidth / 2 - 16 + 5;
		waveNumShadow.y = block.height / 2 - 12 + 5;
		marker.addChild(waveNumShadow);
		// Main wave number text - 20% larger than before
		var waveNum = new Text2((i + 1).toString(), {
			size: 48,
			fill: 0xFFFFFF,
			weight: 800
		});
		waveNum.anchor.set(1.0, 1.0);
		waveNum.x = blockWidth / 2 - 16;
		waveNum.y = block.height / 2 - 12;
		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) {
		var type = self.getWaveType(waveNumber);
		var typeName = type.charAt(0).toUpperCase() + type.slice(1);
		// Add boss prefix for boss waves (every 10th wave)
		if (waveNumber % 10 === 0 && waveNumber > 0 && type !== 'swarm') {
			typeName = "BOSS";
		}
		return typeName;
	};
	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 = 0xffad0e;
	indicator.y = -65;
	var indicator2 = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	indicator2.width = blockWidth - 10;
	indicator2.height = 16;
	indicator2.tint = 0xffad0e;
	indicator2.y = 65;
	var leftWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	leftWall.width = 16;
	leftWall.height = 146;
	leftWall.tint = 0xffad0e;
	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 = 0xffad0e;
	rightWall.x = (blockWidth - 16) / 2;
	self.addChild(self.positionIndicator);
	self.update = function () {
		// Only update position every few frames to reduce calculations
		if (LK.ticks % 3 === 0) {
			var progress = waveTimer / nextWaveTime;
			var moveAmount = (progress + currentWave) * blockWidth;
			// Cache the calculation result
			if (self._lastMoveAmount !== moveAmount) {
				self._lastMoveAmount = moveAmount;
				for (var i = 0; i < self.waveMarkers.length; i++) {
					var marker = self.waveMarkers[i];
					marker.x = -moveAmount + i * blockWidth;
				}
			}
		}
		self.positionIndicator.x = 0;
		// Only update alpha every 10 frames to reduce overhead
		if (LK.ticks % 10 === 0) {
			for (var i = 1; i < Math.min(totalWaves + 1, self.waveMarkers.length); i++) {
				var marker = self.waveMarkers[i];
				var block = marker.children[0];
				var shouldBeFaded = i - 1 < currentWave;
				if (shouldBeFaded && block.alpha !== 0.5) {
					block.alpha = 0.5;
				} else if (!shouldBeFaded && block.alpha !== 1.0) {
					block.alpha = 1.0;
				}
			}
		}
		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 = grid.height - 150;
						// Play VoruThunder sound for MiG rounds
						var actualWaveType = self.getWaveType(currentWave);
						if (actualWaveType === 'flying') {
							LK.getSound('VoruThunder').play();
						}
					}
				}
			}
		};
		self.handleWaveProgression();
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x333333
});
/**** 
* Game Code
****/ 
var isHidingUpgradeMenu = false;
function hideUpgradeMenu(menu) {
	if (isHidingUpgradeMenu) {
		return;
	}
	isHidingUpgradeMenu = true;
	tween(menu, {
		y: 2732 + 225
	}, {
		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 missiles = [];
var defenses = [];
var selectedTower = null;
var gold = 80;
var lives = 20;
var score = 0;
var currentWave = 0;
var totalWaves = 50;
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 goldText = new Text2('Gold: ' + gold, {
	size: 60,
	fill: 0xFFD700,
	weight: 800
});
goldText.anchor.set(0.5, 0.5);
var livesText = new Text2('Lives: ' + lives, {
	size: 60,
	fill: 0x00FF00,
	weight: 800
});
livesText.anchor.set(0.5, 0.5);
var scoreText = new Text2('Score: ' + score, {
	size: 60,
	fill: 0xFF0000,
	weight: 800
});
scoreText.anchor.set(0.5, 0.5);
var topMargin = 50;
var centerX = 2048 / 2;
var spacing = 400;
LK.gui.top.addChild(goldText);
LK.gui.top.addChild(livesText);
LK.gui.top.addChild(scoreText);
livesText.x = 0;
livesText.y = topMargin;
goldText.x = -spacing;
goldText.y = topMargin;
scoreText.x = spacing;
scoreText.y = topMargin;
var lastGoldDisplay = -1;
var lastLivesDisplay = -1;
var lastScoreDisplay = -1;
function updateUI() {
	// Get current language from storage or default to English
	var currentLang = storage.language || 'EN';
	var translations = {
		'EN': {
			'gold': 'Gold',
			'lives': 'Lives',
			'score': 'Score'
		},
		'ES': {
			'gold': 'Oro',
			'lives': 'Vidas',
			'score': 'Puntuación'
		},
		'FR': {
			'gold': 'Or',
			'lives': 'Vies',
			'score': 'Score'
		},
		'DE': {
			'gold': 'Gold',
			'lives': 'Leben',
			'score': 'Punkte'
		},
		'RU': {
			'gold': 'Золото',
			'lives': 'Жизни',
			'score': 'Счёт'
		},
		'ZH': {
			'gold': '金币',
			'lives': '生命',
			'score': '分数'
		},
		'JP': {
			'gold': 'ゴールド',
			'lives': 'ライフ',
			'score': 'スコア'
		},
		'AR': {
			'gold': 'ذهب',
			'lives': 'الأرواح',
			'score': 'النتيجة'
		}
	};
	var langText = translations[currentLang] || translations['EN'];
	if (gold !== lastGoldDisplay) {
		goldText.setText(langText.gold + ': ' + gold);
		lastGoldDisplay = gold;
	}
	if (lives !== lastLivesDisplay) {
		livesText.setText(langText.lives + ': ' + lives);
		lastLivesDisplay = lives;
	}
	if (score !== lastScoreDisplay) {
		scoreText.setText(langText.score + ': ' + score);
		lastScoreDisplay = score;
	}
}
function setGold(value) {
	gold = 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);
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 = 5;
	switch (towerType) {
		case 'Lansen':
			cost = 15;
			break;
		case 'Draken':
			cost = 25;
			break;
		case 'Viggen':
			cost = 35;
			break;
		case 'Gripen':
			cost = 45;
			break;
		case 'Super Viggen':
			cost = 55;
			break;
	}
	return cost;
}
// Get specialized upgrade description for each tower type and level
function getTowerUpgradeDescription(towerType, currentLevel) {
	switch (towerType) {
		case 'Tunnan':
			switch (currentLevel) {
				case 1:
					return "Upgrade: +3 damage, +0.5 range";
				case 2:
					return "Upgrade: +5 damage, faster bullets";
				case 3:
					return "Upgrade: +7 damage, +15% fire rate";
				case 4:
					return "Upgrade: +10 damage, +0.5 range";
				case 5:
					return "ULTIMATE: Double damage, explosive rounds";
				default:
					return "Max Level";
			}
		case 'Lansen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Rapid fire mode, +50% fire rate";
				case 2:
					return "Upgrade: Piercing bullets (hit 2 enemies)";
				case 3:
					return "Upgrade: +3 damage, even faster fire";
				case 4:
					return "Upgrade: Triple shot burst";
				case 5:
					return "ULTIMATE: Minigun mode - constant fire";
				default:
					return "Max Level";
			}
		case 'Draken':
			switch (currentLevel) {
				case 1:
					return "Upgrade: +10 damage, +1 range";
				case 2:
					return "Upgrade: Sniper shots (2x crit chance)";
				case 3:
					return "Upgrade: +15 damage, faster bullets";
				case 4:
					return "Upgrade: Armor piercing (ignores 50% armor)";
				case 5:
					return "ULTIMATE: Railgun - pierces all enemies";
				default:
					return "Max Level";
			}
		case 'Viggen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Larger splash radius";
				case 2:
					return "Upgrade: +5 damage, burning effect";
				case 3:
					return "Upgrade: Chain explosions";
				case 4:
					return "Upgrade: +10 damage, bigger blast";
				case 5:
					return "ULTIMATE: Nuclear warhead - massive blast";
				default:
					return "Max Level";
			}
		case 'Gripen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Stronger slow (60% speed reduction)";
				case 2:
					return "Upgrade: Freeze effect (stops enemies briefly)";
				case 3:
					return "Upgrade: Ice shards (slows nearby enemies)";
				case 4:
					return "Upgrade: Permafrost (longer slow duration)";
				case 5:
					return "ULTIMATE: Absolute zero - area freeze";
				default:
					return "Max Level";
			}
		case 'Super Viggen':
			switch (currentLevel) {
				case 1:
					return "Upgrade: Poison spreads to nearby enemies";
				case 2:
					return "Upgrade: Toxic cloud (area poison)";
				case 3:
					return "Upgrade: +50% poison damage";
				case 4:
					return "Upgrade: Corrosive acid (armor reduction)";
				case 5:
					return "ULTIMATE: Plague spreader - chain poison";
				default:
					return "Max Level";
			}
		default:
			return currentLevel >= 6 ? "Max Level" : "Upgrade available";
	}
}
// Apply specialized upgrades based on tower type and level
function applyTowerUpgrade(tower) {
	switch (tower.id) {
		case 'Tunnan':
			switch (tower.level) {
				case 2:
					tower.damage += 3;
					tower.range += 0.5 * CELL_SIZE;
					break;
				case 3:
					tower.damage += 5;
					tower.bulletSpeed += 2;
					break;
				case 4:
					tower.damage += 7;
					tower.fireRate = Math.max(10, tower.fireRate * 0.85);
					break;
				case 5:
					tower.damage += 10;
					tower.range += 0.5 * CELL_SIZE;
					break;
				case 6:
					tower.damage *= 2;
					tower.hasExplosiveRounds = true;
					break;
			}
			break;
		case 'Lansen':
			switch (tower.level) {
				case 2:
					tower.fireRate = Math.max(5, tower.fireRate * 0.5);
					break;
				case 3:
					tower.hasPiercingBullets = true;
					break;
				case 4:
					tower.damage += 3;
					tower.fireRate = Math.max(3, tower.fireRate * 0.8);
					break;
				case 5:
					tower.hasTripleShot = true;
					break;
				case 6:
					tower.hasMinigunMode = true;
					tower.fireRate = 2;
					break;
			}
			break;
		case 'Draken':
			switch (tower.level) {
				case 2:
					tower.damage += 10;
					tower.range += 1 * CELL_SIZE;
					break;
				case 3:
					tower.hasSniperShots = true;
					break;
				case 4:
					tower.damage += 15;
					tower.bulletSpeed += 5;
					break;
				case 5:
					tower.hasArmorPiercing = true;
					break;
				case 6:
					tower.hasRailgun = true;
					break;
			}
			break;
		case 'Viggen':
			switch (tower.level) {
				case 2:
					tower.splashRadius = (tower.splashRadius || CELL_SIZE * 1.5) + CELL_SIZE * 0.5;
					break;
				case 3:
					tower.damage += 5;
					tower.hasBurningEffect = true;
					break;
				case 4:
					tower.hasChainExplosions = true;
					break;
				case 5:
					tower.damage += 10;
					tower.splashRadius = (tower.splashRadius || CELL_SIZE * 1.5) + CELL_SIZE * 0.5;
					break;
				case 6:
					tower.hasNuclearWarhead = true;
					tower.splashRadius = CELL_SIZE * 4;
					break;
			}
			break;
		case 'Gripen':
			switch (tower.level) {
				case 2:
					tower.slowPercentage = 0.6;
					break;
				case 3:
					tower.hasFreezeEffect = true;
					break;
				case 4:
					tower.hasIceShards = true;
					break;
				case 5:
					tower.slowDuration = 300; // 5 seconds
					break;
				case 6:
					tower.hasAbsoluteZero = true;
					break;
			}
			break;
		case 'Super Viggen':
			switch (tower.level) {
				case 2:
					tower.poisonSpreads = true;
					break;
				case 3:
					tower.hasToxicCloud = true;
					break;
				case 4:
					tower.poisonDamageMultiplier = 1.5;
					break;
				case 5:
					tower.hasCorrosiveAcid = true;
					break;
				case 6:
					tower.hasPlagueSpread = true;
					break;
			}
			break;
	}
}
function getTowerSellValue(totalValue) {
	return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
}
function launchMissile(startX, startY, targetX, targetY, damage, speed, explosionRadius) {
	var missile = new Missile(startX, startY, targetX, targetY, damage, speed, explosionRadius);
	game.addChild(missile);
	missiles.push(missile);
	return missile;
}
function placeTower(gridX, gridY, towerType) {
	var towerCost = getTowerCost(towerType);
	if (gold >= towerCost) {
		var tower = new Tower(towerType || 'Tunnan');
		tower.placeOnGrid(gridX, gridY);
		towerLayer.addChild(tower);
		towers.push(tower);
		setGold(gold - towerCost);
		grid.pathFind();
		grid.renderDebug();
		return true;
	} else {
		var notification = game.addChild(new Notification("Not enough gold!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		return false;
	}
}
game.down = function (x, y, obj) {
	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) {
			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 (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) {
	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.height - 50;
		}
		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;
game.addChild(waveIndicator);
var nextWaveButtonContainer = new Container();
var nextWaveButton = new NextWaveButton();
nextWaveButton.x = 2048 - 200;
nextWaveButton.y = 2732 - 100 + 20;
nextWaveButtonContainer.addChild(nextWaveButton);
game.addChild(nextWaveButtonContainer);
// Add Hawk Button
var hawkPressCount = 0;
var hawkButton = new Container();
var hawkButtonBackground = hawkButton.attachAsset('notification', {
	anchorX: 0.5,
	anchorY: 0.5
});
hawkButtonBackground.width = 250;
hawkButtonBackground.height = 120;
hawkButtonBackground.tint = 0x8B4513; // Brown color
var hawkButtonText = new Text2("🦅", {
	size: 80,
	fill: 0xFFFFFF,
	weight: 800
});
hawkButtonText.anchor.set(0.5, 0.5);
hawkButton.addChild(hawkButtonText);
hawkButton.x = 200;
hawkButton.y = 2732 - 150;
game.addChild(hawkButton);
// Add Language Button
var languageButton = new LanguageButton();
languageButton.x = 380; // Position to the right of hawk button
languageButton.y = 2732 - 150; // Same Y position as hawk button
game.addChild(languageButton);
// Add Guide Button
var guideButton = new Container();
var guideButtonBackground = guideButton.attachAsset('notification', {
	anchorX: 0.5,
	anchorY: 0.5
});
guideButtonBackground.width = 120;
guideButtonBackground.height = 80;
guideButtonBackground.tint = 0x9B59B6; // Purple color
var guideButtonText = new Text2('?', {
	size: 50,
	fill: 0xFFFFFF,
	weight: 800
});
guideButtonText.anchor.set(0.5, 0.5);
guideButton.addChild(guideButtonText);
guideButton.x = 800; // Position to the right of missile button
guideButton.y = 2732 - 150; // Same Y position
game.addChild(guideButton);
// Add Guide System
var guideSystem = new GuideSystem();
guideSystem.x = 2048 / 2;
guideSystem.y = 2732 / 2;
game.addChild(guideSystem);
guideButton.down = function () {
	guideSystem.showGuide();
	// Visual feedback
	tween(guideButton, {
		scaleX: 0.9,
		scaleY: 0.9
	}, {
		duration: 100,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(guideButton, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 100,
				easing: tween.easeOut
			});
		}
	});
};
// Add Missile Button
var missileButton = new Container();
var missileButtonBackground = missileButton.attachAsset('notification', {
	anchorX: 0.5,
	anchorY: 0.5
});
missileButtonBackground.width = 200;
missileButtonBackground.height = 100;
missileButtonBackground.tint = 0xFF4444; // Red color
var missileButtonText = new Text2('MISSILE', {
	size: 50,
	fill: 0xFFFFFF,
	weight: 800
});
missileButtonText.anchor.set(0.5, 0.5);
missileButton.addChild(missileButtonText);
missileButton.x = 580; // Position to the right of language button
missileButton.y = 2732 - 150; // Same Y position
game.addChild(missileButton);
missileButton.down = function () {
	// Find strongest enemy to target
	var strongestEnemy = null;
	var highestHealth = 0;
	for (var i = 0; i < enemies.length; i++) {
		if (enemies[i].health > highestHealth) {
			highestHealth = enemies[i].health;
			strongestEnemy = enemies[i];
		}
	}
	if (strongestEnemy && gold >= 50) {
		// Missile costs 50 gold
		setGold(gold - 50);
		launchMissile(2048 / 2, 0, strongestEnemy.x, strongestEnemy.y, 100, 4, CELL_SIZE * 2.5);
		// Visual feedback
		tween(missileButton, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(missileButton, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 100,
					easing: tween.easeOut
				});
			}
		});
		var notification = game.addChild(new Notification('Missile launched!'));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	} else if (!strongestEnemy) {
		var notification = game.addChild(new Notification('No targets available!'));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	} else {
		var notification = game.addChild(new Notification('Need 50 gold for missile!'));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	}
};
hawkButton.down = function () {
	hawkPressCount++;
	// Visual feedback
	tween(hawkButton, {
		scaleX: 0.9,
		scaleY: 0.9
	}, {
		duration: 100,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(hawkButton, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 100,
				easing: tween.easeOut
			});
		}
	});
	if (hawkPressCount >= 5) {
		// HAWK JUMPSCARE!
		var hawkJumpscare = new Container();
		// Create large hawk sprite
		var hawkSprite = hawkJumpscare.attachAsset('hawk', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		hawkSprite.width = 800;
		hawkSprite.height = 800;
		// Position at center
		hawkJumpscare.x = 2048 / 2;
		hawkJumpscare.y = 2732 / 2;
		hawkJumpscare.scaleX = 0.1;
		hawkJumpscare.scaleY = 0.1;
		hawkJumpscare.alpha = 0;
		game.addChild(hawkJumpscare);
		// Jumpscare animation
		tween(hawkJumpscare, {
			scaleX: 2,
			scaleY: 2,
			alpha: 1
		}, {
			duration: 200,
			easing: tween.backOut,
			onFinish: function onFinish() {
				// Flash screen red
				LK.effects.flashScreen(0xFF0000, 500);
				// Hold for a moment then fade out
				tween(hawkJumpscare, {
					alpha: 0,
					scaleX: 0.5,
					scaleY: 0.5
				}, {
					duration: 1000,
					delay: 800,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						hawkJumpscare.destroy();
					}
				});
			}
		});
		// Reset counter
		hawkPressCount = 0;
		// Show notification
		var notification = game.addChild(new Notification("🦅 HAWK ATTACK! 🦅"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 100;
	}
};
var towerTypes = ['Tunnan', 'Lansen', 'Draken', 'Viggen', 'Gripen', 'Super Viggen'];
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;
// Play background music
LK.playMusic('JollyTug');
game.update = function () {
	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 = grid.height - 200;
			}
			// 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);
				}
				// Scale difficulty with wave number but don't apply to boss
				// as bosses already have their health multiplier
				// Use exponential scaling for health
				var healthMultiplier = Math.pow(1.12, currentWave); // ~20% increase per wave
				enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
				enemy.health = enemy.maxHealth;
				// Increment speed slightly with wave number
				//enemy.speed = enemy.speed + currentWave * 0.002;
				// 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;
		}
	}
	// Batch enemy processing for better performance
	var deadEnemies = [];
	var escapedEnemies = [];
	var uiNeedsUpdate = false;
	for (var a = 0; a < enemies.length; a++) {
		var enemy = enemies[a];
		if (enemy.health <= 0) {
			deadEnemies.push({
				enemy: enemy,
				index: a
			});
		} else if (grid.updateEnemy(enemy)) {
			escapedEnemies.push({
				enemy: enemy,
				index: a
			});
		}
	}
	// Process dead enemies in batch
	for (var i = 0; i < deadEnemies.length; i++) {
		var deadData = deadEnemies[i];
		var enemy = deadData.enemy;
		for (var j = 0; j < enemy.bulletsTargetingThis.length; j++) {
			var bullet = enemy.bulletsTargetingThis[j];
			bullet.targetEnemy = null;
		}
		// Boss enemies give more gold and score
		var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
		var goldIndicator = new GoldIndicator(goldEarned, enemy.x, enemy.y);
		game.addChild(goldIndicator);
		setGold(gold + goldEarned);
		// Give more score for defeating a boss
		var scoreValue = enemy.isBoss ? 100 : 5;
		score += scoreValue;
		uiNeedsUpdate = true;
		// Add a notification for boss defeat
		if (enemy.isBoss) {
			var notification = game.addChild(new Notification("Boss defeated! +" + goldEarned + " gold!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 150;
		}
		// 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);
		}
	}
	// Process escaped enemies in batch
	for (var i = 0; i < escapedEnemies.length; i++) {
		var escapedData = escapedEnemies[i];
		var enemy = escapedData.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);
		}
		lives = Math.max(0, lives - 1);
		uiNeedsUpdate = true;
	}
	// Remove enemies from array in reverse order (highest index first)
	var allRemovals = deadEnemies.concat(escapedEnemies);
	allRemovals.sort(function (a, b) {
		return b.index - a.index;
	});
	for (var i = 0; i < allRemovals.length; i++) {
		enemies.splice(allRemovals[i].index, 1);
	}
	// Update UI only once if needed
	if (uiNeedsUpdate) {
		updateUI();
	}
	// Check game over only once
	if (lives <= 0) {
		LK.showGameOver();
	}
	// Optimize bullet cleanup - batch removals
	var bulletsToRemove = [];
	for (var i = 0; i < bullets.length; i++) {
		if (!bullets[i].parent) {
			bulletsToRemove.push(i);
			if (bullets[i].targetEnemy) {
				var targetEnemy = bullets[i].targetEnemy;
				var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
				if (bulletIndex !== -1) {
					targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
				}
			}
		}
	}
	// Remove bullets in reverse order to maintain indices
	for (var i = bulletsToRemove.length - 1; i >= 0; i--) {
		bullets.splice(bulletsToRemove[i], 1);
	}
	// Optimize missile cleanup - batch removals
	var missilesToRemove = [];
	for (var i = 0; i < missiles.length; i++) {
		if (!missiles[i].parent) {
			missilesToRemove.push(i);
		}
	}
	// Remove missiles in reverse order to maintain indices
	for (var i = missilesToRemove.length - 1; i >= 0; i--) {
		missiles.splice(missilesToRemove[i], 1);
	}
	if (towerPreview.visible) {
		towerPreview.checkPlacement();
	}
	if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) {
		LK.showYouWin();
	}
};
 
 White circle with black outline. Blue background.. In-Game asset. 2d. High contrast. No shadows
 A Soviet tank.. In-Game asset. 2d. High contrast. No shadows. Top down view
 A Saab 37 Viggen fighter jet.. In-Game asset. 2d. High contrast. No shadows. Top down view
 A FIERCE HAWK WITH RED EYES, SPREAD WINGS AND A THIRST FOR BLOOD!. In-Game asset. 2d. High contrast. No shadows
 A normal Canada goose. Nothing special.. In-Game asset. 2d. High contrast. No shadows. Top down view