/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.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;
	// Use default bullet asset initially, will be updated based on type
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.update = function () {
		// Mortar projectile logic
		if (self.type === 'mortar') {
			var dx = self.targetX - self.x;
			var dy = self.targetY - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < self.speed) {
				// Create explosion effect
				var mortarEffect = new EffectIndicator(self.targetX, self.targetY, 'mortar');
				game.addChild(mortarEffect);
				// Area damage
				var explosionRadius = CELL_SIZE * 1.5;
				for (var i = 0; i < enemies.length; i++) {
					var enemy = enemies[i];
					var enemyDx = enemy.x - self.targetX;
					var enemyDy = enemy.y - self.targetY;
					var enemyDist = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy);
					if (enemyDist <= explosionRadius) {
						// Damage falls off with distance
						var damageFactor = 1 - enemyDist / explosionRadius * 0.5;
						enemy.health -= oneHitKillCheat ? 999999 : self.damage * damageFactor;
						if (enemy.health <= 0) {
							enemy.health = 0;
						} else {
							enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
						}
					}
				}
				self.destroy();
			} else {
				var angle = Math.atan2(dy, dx);
				self.x += Math.cos(angle) * self.speed;
				self.y += Math.sin(angle) * self.speed;
			}
			return;
		}
		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;
			LK.getSound('enemy_hit').play();
			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 -= oneHitKillCheat ? 999999 : 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 === 'sniper') {
				// Create visual critical hit effect for sniper
				var sniperEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'sniper');
				game.addChild(sniperEffect);
			} else if (self.type === 'wizard') {
				// Check if tower has charm ability
				if (self.hasCharmAbility) {
					// Charm effect instead of confusion
					if (!self.targetEnemy.isCharmed && !self.targetEnemy.isImmune) {
						self.targetEnemy.isCharmed = true;
						self.targetEnemy.charmDuration = 300; // 5 seconds at 60 FPS
						self.targetEnemy.originalTeam = 'enemy';
						// Visual effect for charm
						var charmEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'charm');
						game.addChild(charmEffect);
					}
				} else {
					// Regular confusion effect
					if (Math.random() < 0.5 && !self.targetEnemy.isConfused && !self.targetEnemy.isImmune) {
						self.targetEnemy.isConfused = true;
						self.targetEnemy.confusionDuration = 180; // 3 seconds at 60 FPS
						// Visual effect for confusion
						var confuseEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'confuse');
						game.addChild(confuseEffect);
					}
				}
			} else if (self.type === 'rapid' && self.hasBleedAbility) {
				// 10% chance to apply bleed
				if (Math.random() < 0.1 && !self.targetEnemy.isBleeding && !self.targetEnemy.isImmune) {
					self.targetEnemy.isBleeding = true;
					self.targetEnemy.bleedDuration = 300; // 5 seconds at 60 FPS
					self.targetEnemy.bleedDamage = 5; // 5 damage per second
					// Visual effect for bleed
					var bleedEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'bleed');
					game.addChild(bleedEffect);
				}
			} else if (self.type === 'slow' && self.hasPermafrostAbility) {
				// Permanent slow effect
				if (!self.targetEnemy.isImmune) {
					// Create visual slow effect
					var slowEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'slow');
					game.addChild(slowEffect);
					// Apply permanent slow
					if (!self.targetEnemy.slowed) {
						self.targetEnemy.originalSpeed = self.targetEnemy.speed;
						self.targetEnemy.speed *= 0.2; // 80% slow
						self.targetEnemy.slowed = true;
						self.targetEnemy.slowDuration = 999999; // Permanent
						self.targetEnemy.permanentSlow = true;
					}
				}
			}
			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 CheatMenu = Container.expand(function () {
	var self = Container.call(this);
	// Background
	var background = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.width = 800;
	background.height = 600;
	background.tint = 0x222222;
	background.alpha = 0.95;
	// Title
	var titleText = new Text2('CHEATS', {
		size: 80,
		fill: 0xFF0000,
		weight: 800
	});
	titleText.anchor.set(0.5, 0);
	titleText.x = 0;
	titleText.y = -250;
	self.addChild(titleText);
	// Unlimited Money Toggle
	var moneyToggle = new Container();
	var moneyBg = moneyToggle.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	moneyBg.width = 700;
	moneyBg.height = 120;
	moneyBg.tint = unlimitedMoneyCheat ? 0x00FF00 : 0x888888;
	var moneyText = new Text2('Unlimited Money: ' + (unlimitedMoneyCheat ? 'ON' : 'OFF'), {
		size: 50,
		fill: 0xFFFFFF,
		weight: 800
	});
	moneyText.anchor.set(0.5, 0.5);
	moneyToggle.addChild(moneyText);
	moneyToggle.y = -80;
	self.addChild(moneyToggle);
	moneyToggle.down = function () {
		unlimitedMoneyCheat = !unlimitedMoneyCheat;
		moneyBg.tint = unlimitedMoneyCheat ? 0x00FF00 : 0x888888;
		moneyText.setText('Unlimited Money: ' + (unlimitedMoneyCheat ? 'ON' : 'OFF'));
		if (unlimitedMoneyCheat) {
			setGold(999999);
		}
	};
	// One Hit Kill Toggle
	var oneHitToggle = new Container();
	var oneHitBg = oneHitToggle.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	oneHitBg.width = 700;
	oneHitBg.height = 120;
	oneHitBg.tint = oneHitKillCheat ? 0x00FF00 : 0x888888;
	var oneHitText = new Text2('One Hit Kills: ' + (oneHitKillCheat ? 'ON' : 'OFF'), {
		size: 50,
		fill: 0xFFFFFF,
		weight: 800
	});
	oneHitText.anchor.set(0.5, 0.5);
	oneHitToggle.addChild(oneHitText);
	oneHitToggle.y = 80;
	self.addChild(oneHitToggle);
	oneHitToggle.down = function () {
		oneHitKillCheat = !oneHitKillCheat;
		oneHitBg.tint = oneHitKillCheat ? 0x00FF00 : 0x888888;
		oneHitText.setText('One Hit Kills: ' + (oneHitKillCheat ? 'ON' : 'OFF'));
	};
	// Close button
	var closeButton = new Container();
	var closeBg = closeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBg.width = 90;
	closeBg.height = 90;
	closeBg.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 = background.width / 2 - 57;
	closeButton.y = -background.height / 2 + 57;
	self.addChild(closeButton);
	closeButton.down = function () {
		self.destroy();
	};
	// Initial position (centered)
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	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('', {
		size: 30,
		fill: 0xFFFFFF,
		weight: 800
	});
	numberLabel.anchor.set(.5, .5);
	numberLabel.visible = false;
	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.visible = false;
						cellGraphics.tint = 0x880000;
						return;
					}
					numberLabel.visible = false;
					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;
					}
					self.removeArrows();
					break;
				}
			case 1:
				{
					self.removeArrows();
					cellGraphics.tint = 0xaaaaaa;
					numberLabel.visible = false;
					break;
				}
			case 3:
				{
					self.removeArrows();
					cellGraphics.tint = 0x008800;
					numberLabel.visible = false;
					break;
				}
		}
	};
});
// This update method was incorrectly placed here and should be removed
var EffectIndicator = Container.expand(function (x, y, type) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	var effectGraphics = self.attachAsset('rangeCircle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	effectGraphics.blendMode = 1;
	switch (type) {
		case 'splash':
			effectGraphics.tint = 0x33CC00;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5;
			break;
		case 'slow':
			effectGraphics.tint = 0x9900FF;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'sniper':
			effectGraphics.tint = 0xFF5500;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'confuse':
			effectGraphics.tint = 0xFF1493;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.2;
			break;
		case 'mortar':
			effectGraphics.tint = 0x8B4513;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 3;
			break;
		case 'charm':
			effectGraphics.tint = 0xFFB6C1;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5;
			break;
		case 'bleed':
			effectGraphics.tint = 0x8B0000;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 0.8;
			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;
	self.isHidden = false;
	self.hideDuration = 0;
	self.hideTimer = 0;
	self.hasSpawned = 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; // Twice as fast
			self.maxHealth = 100;
			break;
		case 'immune':
			self.isImmune = true;
			self.maxHealth = 80;
			break;
		case 'flying':
			self.isFlying = true;
			self.maxHealth = 80;
			break;
		case 'swarm':
			self.maxHealth = 50; // Weaker enemies
			break;
		case 'flying_horde':
			self.isFlying = true;
			self.maxHealth = 25; // Very weak
			self.speed *= 1.5; // Fast
			break;
		case 'mole':
			self.maxHealth = 120; // Slightly tankier
			self.speed *= 0.8; // Slower when visible
			self.hideTimer = 300; // 5 seconds until first hide
			break;
		case 'mixed':
			// Mixed will be handled as a special spawner type
			self.maxHealth = 1; // Placeholder, should not be attacked
			self.isSpawner = true;
			break;
		case 'normal':
		default:
			// Normal enemy uses default values
			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;
		}
		// Handle mole digging mechanics
		if (self.type === 'mole') {
			self.hideTimer--;
			if (self.hideTimer <= 0) {
				if (!self.isHidden) {
					// Start hiding (go underground)
					self.isHidden = true;
					self.hideDuration = 90; // 1.5 seconds at 60 FPS
					self.hideTimer = 300; // 5 seconds until next hide
					// Double speed while hidden
					if (self.originalSpeed === undefined) {
						self.originalSpeed = self.speed;
					}
					self.speed = self.originalSpeed * 2;
					// Visual effect - make semi-transparent and darker
					enemyGraphics.alpha = 0.3;
					enemyGraphics.tint = 0x444444;
					// Hide health bar while underground
					healthBarOutline.visible = false;
					healthBarBG.visible = false;
					healthBar.visible = false;
				} else {
					// Come back up (surface)
					self.isHidden = false;
					self.hideTimer = 300; // 5 seconds until next hide
					// Reset speed
					if (self.originalSpeed !== undefined) {
						self.speed = self.originalSpeed;
					}
					// Restore visibility
					enemyGraphics.alpha = 1;
					enemyGraphics.tint = 0xFFFFFF;
					// Show health bar again
					healthBarOutline.visible = true;
					healthBarBG.visible = true;
					healthBar.visible = true;
				}
			} else if (self.isHidden) {
				self.hideDuration--;
				if (self.hideDuration <= 0) {
					// Force surface if duration is over
					self.isHidden = false;
					self.hideTimer = 300; // Reset timer
					// Reset speed
					if (self.originalSpeed !== undefined) {
						self.speed = self.originalSpeed;
					}
					// Restore visibility
					enemyGraphics.alpha = 1;
					enemyGraphics.tint = 0xFFFFFF;
					// Show health bar again
					healthBarOutline.visible = true;
					healthBarBG.visible = true;
					healthBar.visible = true;
				}
			}
		}
		// Handle flying horde spawning
		if (self.type === 'flying_horde' && !self.hasSpawned && self.currentCellY >= 2) {
			self.hasSpawned = true;
			// Spawn 4-6 additional weak flying enemies
			var spawnCount = 4 + Math.floor(Math.random() * 3);
			for (var i = 0; i < spawnCount; i++) {
				var newEnemy = new Enemy('flying');
				newEnemy.maxHealth = 15; // Very weak
				newEnemy.health = newEnemy.maxHealth;
				newEnemy.speed = self.speed * (0.8 + Math.random() * 0.4); // Varied speed
				// Position around the spawner
				var angle = Math.PI * 2 / spawnCount * i + Math.random() * 0.5;
				var distance = 50 + Math.random() * 30;
				newEnemy.cellX = self.cellX;
				newEnemy.cellY = self.cellY;
				newEnemy.currentCellX = self.currentCellX + Math.cos(angle) * distance / CELL_SIZE;
				newEnemy.currentCellY = self.currentCellY + Math.sin(angle) * distance / CELL_SIZE;
				newEnemy.x = grid.x + newEnemy.currentCellX * CELL_SIZE;
				newEnemy.y = grid.y + newEnemy.currentCellY * CELL_SIZE;
				newEnemy.waveNumber = self.waveNumber;
				// Add to flying layer
				enemyLayerTop.addChild(newEnemy);
				if (newEnemy.shadow) {
					enemyLayerMiddle.addChild(newEnemy.shadow);
				}
				enemies.push(newEnemy);
			}
		}
		// Handle confusion effect
		if (self.isConfused && !self.isImmune) {
			self.confusionDuration--;
			if (self.confusionDuration <= 0) {
				self.isConfused = false;
				// Reset pathfinding when confusion ends
				self.currentTarget = undefined;
			}
		}
		// Handle charm effect
		if (self.isCharmed && !self.isImmune) {
			self.charmDuration--;
			if (self.charmDuration <= 0) {
				self.isCharmed = false;
				self.originalTeam = 'enemy';
				// Reset pathfinding when charm ends
				self.currentTarget = undefined;
			}
		}
		// Handle bleed effect
		if (self.isBleeding && !self.isImmune) {
			self.bleedDuration--;
			// Take 5 damage every second (60 ticks)
			if (self.bleedDuration % 60 === 0) {
				self.health -= oneHitKillCheat ? 999999 : self.bleedDamage;
				if (self.health <= 0) {
					self.health = 0;
				} else {
					self.healthBar.width = self.health / self.maxHealth * 70;
				}
				// Visual feedback
				LK.effects.flashObject(self, 0x8B0000, 100);
			}
			if (self.bleedDuration <= 0) {
				self.isBleeding = false;
			}
		}
		// Handle slow effect
		if (self.isImmune) {
			// Immune enemies cannot be slowed, clear any such effects
			self.slowed = false;
			self.slowEffect = false;
			// Reset speed to original if needed
			if (self.originalSpeed !== undefined) {
				self.speed = self.originalSpeed;
			}
		} else {
			// Handle slow effect
			if (self.slowed) {
				// Visual indication of slowed status
				if (!self.slowEffect) {
					self.slowEffect = true;
				}
				self.slowDuration--;
				if (self.slowDuration <= 0) {
					self.speed = self.originalSpeed;
					self.slowed = false;
					self.slowEffect = false;
					// Only reset tint if not poisoned
					if (!self.poisoned) {
						enemyGraphics.tint = 0xFFFFFF; // Reset tint
					}
				}
			}
		}
		// Set tint based on effect status
		if (self.isImmune) {
			enemyGraphics.tint = 0xFFFFFF;
		} else if (self.isCharmed) {
			enemyGraphics.tint = 0xFFB6C1; // Light pink for charmed
		} else if (self.isConfused) {
			enemyGraphics.tint = 0xFF1493; // Pink for confused
		} else if (self.isBleeding) {
			enemyGraphics.tint = 0x8B0000; // Dark red for bleeding
		} else if (self.slowed) {
			enemyGraphics.tint = 0x9900FF;
		} else {
			enemyGraphics.tint = 0xFFFFFF;
		}
		if (self.currentTarget) {
			var ox = self.currentTarget.x - self.currentCellX;
			var oy = self.currentTarget.y - self.currentCellY;
			if (ox !== 0 || oy !== 0) {
				var angle = Math.atan2(oy, ox);
				if (enemyGraphics.targetRotation === undefined) {
					enemyGraphics.targetRotation = angle;
					enemyGraphics.rotation = angle;
				} else {
					if (Math.abs(angle - enemyGraphics.targetRotation) > 0.05) {
						tween.stop(enemyGraphics, {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = enemyGraphics.rotation;
						var angleDiff = angle - currentRotation;
						// Normalize angle difference to -PI to PI range for shortest path
						while (angleDiff > Math.PI) {
							angleDiff -= Math.PI * 2;
						}
						while (angleDiff < -Math.PI) {
							angleDiff += Math.PI * 2;
						}
						enemyGraphics.targetRotation = angle;
						tween(enemyGraphics, {
							rotation: currentRotation + angleDiff
						}, {
							duration: 250,
							easing: tween.easeOut
						});
					}
				}
			}
		}
		healthBarOutline.y = healthBarBG.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	};
	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;
			}
		}
		for (var a = 0; a < enemies.length; a++) {
			var enemy = enemies[a];
			// Skip enemies that haven't entered the viewable area yet
			if (enemy.currentCellY < 4) {
				continue;
			}
			// Skip flying enemies from path check as they can fly over obstacles
			if (enemy.isFlying) {
				continue;
			}
			var target = self.getCell(enemy.cellX, enemy.cellY);
			if (enemy.currentTarget) {
				if (enemy.currentTarget.pathId != pathId) {
					if (!target || target.pathId != pathId) {
						console.warn("Enemy blocked 1 ");
						return true;
					}
				}
			} else if (!target || target.pathId != pathId) {
				console.warn("Enemy blocked 2");
				return true;
			}
		}
		console.log("Speed", new Date().getTime() - before);
	};
	self.renderDebug = function () {
		for (var i = 0; i < gridWidth; i++) {
			for (var j = 0; j < gridHeight; j++) {
				var debugCell = self.cells[i][j].debugCell;
				if (debugCell) {
					debugCell.render(self.cells[i][j]);
				}
			}
		}
	};
	self.updateEnemy = function (enemy) {
		var cell = grid.getCell(enemy.cellX, enemy.cellY);
		if (cell.type == 3) {
			return true;
		}
		if (enemy.isFlying && enemy.shadow) {
			enemy.shadow.x = enemy.x + 20; // Match enemy x-position + offset
			enemy.shadow.y = enemy.y + 20; // Match enemy y-position + offset
			// Match shadow rotation with enemy rotation
			if (enemy.children[0] && enemy.shadow.children[0]) {
				enemy.shadow.children[0].rotation = enemy.children[0].rotation;
			}
		}
		// Check if the enemy has reached the entry area (y position is at least 5)
		var hasReachedEntryArea = enemy.currentCellY >= 4;
		// If enemy hasn't reached the entry area yet, just move down vertically
		if (!hasReachedEntryArea) {
			// Move directly downward
			enemy.currentCellY += enemy.speed;
			// Rotate enemy graphic to face downward (PI/2 radians = 90 degrees)
			var angle = Math.PI / 2;
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update enemy's position
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// If enemy has now reached the entry area, update cell coordinates
			if (enemy.currentCellY >= 4) {
				enemy.cellX = Math.round(enemy.currentCellX);
				enemy.cellY = Math.round(enemy.currentCellY);
			}
			return false;
		}
		// After reaching entry area, handle flying enemies differently
		if (enemy.isFlying) {
			// Flying enemies head straight to the closest goal
			if (!enemy.flyingTarget) {
				// Set flying target to the closest goal
				enemy.flyingTarget = self.goals[0];
				// Find closest goal if there are multiple
				if (self.goals.length > 1) {
					var closestDist = Infinity;
					for (var i = 0; i < self.goals.length; i++) {
						var goal = self.goals[i];
						var dx = goal.x - enemy.cellX;
						var dy = goal.y - enemy.cellY;
						var dist = dx * dx + dy * dy;
						if (dist < closestDist) {
							closestDist = dist;
							enemy.flyingTarget = goal;
						}
					}
				}
			}
			// Move directly toward the goal
			var ox = enemy.flyingTarget.x - enemy.currentCellX;
			var oy = enemy.flyingTarget.y - enemy.currentCellY;
			var dist = Math.sqrt(ox * ox + oy * oy);
			if (dist < enemy.speed) {
				// Reached the goal
				return true;
			}
			var angle = Math.atan2(oy, ox);
			// Rotate enemy graphic to match movement direction
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update the cell position to track where the flying enemy is
			enemy.cellX = Math.round(enemy.currentCellX);
			enemy.cellY = Math.round(enemy.currentCellY);
			enemy.currentCellX += Math.cos(angle) * enemy.speed;
			enemy.currentCellY += Math.sin(angle) * enemy.speed;
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// Update shadow position if this is a flying enemy
			return false;
		}
		// Handle normal pathfinding enemies
		if (enemy.isCharmed) {
			// Charmed enemies attack other enemies
			var nearestEnemy = null;
			var nearestDist = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var otherEnemy = enemies[i];
				if (otherEnemy !== enemy && !otherEnemy.isCharmed) {
					var dx = otherEnemy.cellX - enemy.cellX;
					var dy = otherEnemy.cellY - enemy.cellY;
					var dist = dx * dx + dy * dy;
					if (dist < nearestDist) {
						nearestDist = dist;
						nearestEnemy = otherEnemy;
					}
				}
			}
			if (nearestEnemy) {
				// Move towards the nearest enemy
				enemy.currentTarget = {
					x: nearestEnemy.cellX,
					y: nearestEnemy.cellY
				};
				// Deal damage if close enough
				if (nearestDist < 2) {
					if (LK.ticks % 60 === 0) {
						// Attack once per second
						nearestEnemy.health -= oneHitKillCheat ? 999999 : 10;
						if (nearestEnemy.health <= 0) {
							nearestEnemy.health = 0;
						} else {
							nearestEnemy.healthBar.width = nearestEnemy.health / nearestEnemy.maxHealth * 70;
						}
						LK.effects.flashObject(nearestEnemy, 0xFFB6C1, 100);
					}
				}
			}
		} else if (enemy.isConfused) {
			// Confused enemies move towards the nearest tower
			var nearestTower = null;
			var nearestDist = Infinity;
			for (var i = 0; i < towers.length; i++) {
				var tower = towers[i];
				var dx = tower.gridX - enemy.cellX;
				var dy = tower.gridY - enemy.cellY;
				var dist = dx * dx + dy * dy;
				if (dist < nearestDist) {
					nearestDist = dist;
					nearestTower = tower;
				}
			}
			if (nearestTower) {
				// Set target to move towards the tower
				enemy.currentTarget = {
					x: nearestTower.gridX,
					y: nearestTower.gridY
				};
			}
		} else if (!enemy.currentTarget) {
			enemy.currentTarget = cell.targets[0];
		}
		if (enemy.currentTarget) {
			if (!enemy.isConfused && 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 LaserWall = Container.expand(function (tower1, tower2) {
	var self = Container.call(this);
	self.tower1 = tower1;
	self.tower2 = tower2;
	self.damage = 18; // Base damage per tick (increased by 2)
	self.level = 1;
	self.maxLevel = 6;
	// Create laser visual
	var laserGraphics = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	laserGraphics.tint = 0xFF0088;
	laserGraphics.alpha = 0.8;
	// Position between the two towers
	self.updatePosition = function () {
		self.x = Math.min(self.tower1.x, self.tower2.x);
		self.y = self.tower1.y;
		var distance = Math.abs(self.tower2.x - self.tower1.x);
		laserGraphics.width = distance;
		laserGraphics.height = CELL_SIZE * 0.5;
	};
	self.updatePosition();
	// Level indicators
	var levelIndicators = [];
	var maxDots = self.maxLevel;
	var dotSize = CELL_SIZE / 8;
	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 + 2;
		outlineCircle.height = dotSize + 2;
		outlineCircle.tint = 0x000000;
		var levelIndicator = dot.attachAsset('towerLevelIndicator', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		levelIndicator.width = dotSize;
		levelIndicator.height = dotSize;
		levelIndicator.tint = 0xCCCCCC;
		dot.y = -CELL_SIZE * 0.4;
		self.addChild(dot);
		levelIndicators.push(dot);
	}
	self.updateLevelIndicators = function () {
		var centerX = laserGraphics.width / 2;
		var spacing = laserGraphics.width / (maxDots + 1);
		for (var i = 0; i < maxDots; i++) {
			var dot = levelIndicators[i];
			dot.x = spacing * (i + 1);
			var levelIndicator = dot.children[1];
			if (i < self.level) {
				levelIndicator.tint = 0xFFFFFF;
			} else {
				levelIndicator.tint = 0xFF0088;
			}
		}
	};
	self.updateLevelIndicators();
	self.upgrade = function () {
		if (self.level < self.maxLevel) {
			var upgradeCost = Math.floor(40 * Math.pow(2, self.level - 1));
			if (self.level === self.maxLevel - 1) {
				upgradeCost = Math.floor(upgradeCost * 3.5 / 2);
			}
			if (gold >= upgradeCost) {
				setGold(gold - upgradeCost);
				self.level++;
				self.damage = 18 + self.level * 24; // Increased base by 2 and maintain scaling
				// Unlock special ability at level 3
				if (self.level === 3) {
					self.hasSpecialAbility = true;
					var notification = game.addChild(new Notification("Laser Wall: Sky Piercer unlocked!"));
					notification.x = 2048 / 2;
					notification.y = grid.height - 100;
				}
				self.updateLevelIndicators();
				// Visual feedback
				tween(laserGraphics, {
					scaleY: 1.5,
					alpha: 1
				}, {
					duration: 200,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						tween(laserGraphics, {
							scaleY: 1,
							alpha: 0.8
						}, {
							duration: 200,
							easing: tween.easeIn
						});
					}
				});
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough gold to upgrade laser wall!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.getTotalValue = function () {
		var totalInvestment = 0;
		for (var i = 1; i < self.level; i++) {
			totalInvestment += Math.floor(40 * Math.pow(2, i - 1));
		}
		return totalInvestment;
	};
	self.update = function () {
		// Check for enemies passing through the laser
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			// Skip flying enemies unless laser wall has special ability
			if (enemy.isFlying && !self.hasSpecialAbility) {
				continue;
			}
			// Skip hidden moles unless laser wall has special ability
			if (enemy.isHidden && !self.hasSpecialAbility) {
				continue;
			}
			// Check if enemy is in the same row as the laser
			if (Math.abs(enemy.y - self.y) < CELL_SIZE / 2) {
				// Check if enemy is within the laser's horizontal range
				if (enemy.x >= self.x && enemy.x <= self.x + laserGraphics.width) {
					// Deal damage every 30 ticks (0.5 seconds)
					if (LK.ticks % 30 === 0) {
						enemy.health -= oneHitKillCheat ? 999999 : self.damage;
						if (enemy.health <= 0) {
							enemy.health = 0;
						} else {
							enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
						}
						// Visual effect
						LK.effects.flashObject(enemy, 0xFF0088, 100);
						// Play laser sound occasionally
						if (LK.ticks % 120 === 0) {
							LK.getSound('laser_beam').play();
						}
					}
				}
			}
		}
		// Pulse effect
		laserGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.1) * 0.2;
	};
	self.down = function (x, y, obj) {
		// Show upgrade menu for laser wall
		var existingMenus = game.children.filter(function (child) {
			return child instanceof UpgradeMenu;
		});
		for (var i = 0; i < existingMenus.length; i++) {
			existingMenus[i].destroy();
		}
		selectedTower = self;
		var upgradeMenu = new LaserWallUpgradeMenu(self);
		game.addChild(upgradeMenu);
		upgradeMenu.x = 2048 / 2;
		tween(upgradeMenu, {
			y: 2732 - 275
		}, {
			duration: 200,
			easing: tween.backOut
		});
	};
	return self;
});
var LaserWallUpgradeMenu = Container.expand(function (laserWall) {
	var self = Container.call(this);
	self.laserWall = laserWall;
	self.y = 2732 + 275;
	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 titleText = new Text2('Laser Wall', {
		size: 80,
		fill: 0xFFFFFF,
		weight: 800
	});
	titleText.anchor.set(0, 0);
	titleText.x = -840;
	titleText.y = -160;
	self.addChild(titleText);
	var statsText = new Text2('Level: ' + self.laserWall.level + '/' + self.laserWall.maxLevel + '\nDamage: ' + self.laserWall.damage + '/0.5s', {
		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);
	// Upgrade button
	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.laserWall.level >= self.laserWall.maxLevel;
	var upgradeCost = 0;
	if (!isMaxLevel) {
		upgradeCost = Math.floor(40 * Math.pow(2, self.laserWall.level - 1));
		if (self.laserWall.level === self.laserWall.maxLevel - 1) {
			upgradeCost = Math.floor(upgradeCost * 3.5 / 2);
		}
	}
	buttonBackground.tint = isMaxLevel ? 0x888888 : gold >= upgradeCost ? 0x00AA00 : 0x888888;
	var buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	// Sell button
	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 sellValue = getTowerSellValue(self.laserWall.getTotalValue());
	var sellButtonText = new Text2('Remove Wall: +' + sellValue + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	sellButtonText.anchor.set(0.5, 0.5);
	sellButton.addChild(sellButtonText);
	upgradeButton.y = -85;
	sellButton.y = 85;
	// Close button
	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 () {
		if (self.laserWall.level >= self.laserWall.maxLevel) {
			var notification = game.addChild(new Notification("Laser wall is already at max level!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
			return;
		}
		if (self.laserWall.upgrade()) {
			statsText.setText('Level: ' + self.laserWall.level + '/' + self.laserWall.maxLevel + '\nDamage: ' + self.laserWall.damage + '/0.5s');
			if (self.laserWall.level >= self.laserWall.maxLevel) {
				buttonBackground.tint = 0x888888;
				buttonText.setText('Max Level');
			} else {
				var newCost = Math.floor(40 * Math.pow(2, self.laserWall.level - 1));
				if (self.laserWall.level === self.laserWall.maxLevel - 1) {
					newCost = Math.floor(newCost * 3.5 / 2);
				}
				buttonText.setText('Upgrade: ' + newCost + ' gold');
			}
			var newSellValue = getTowerSellValue(self.laserWall.getTotalValue());
			sellButtonText.setText('Remove Wall: +' + newSellValue + ' gold');
		}
	};
	sellButton.down = function () {
		var sellValue = getTowerSellValue(self.laserWall.getTotalValue());
		setGold(gold + sellValue);
		var notification = game.addChild(new Notification("Laser wall removed for " + sellValue + " gold!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		// Remove laser wall from game
		var wallIndex = laserWalls.indexOf(self.laserWall);
		if (wallIndex !== -1) {
			laserWalls.splice(wallIndex, 1);
		}
		game.removeChild(self.laserWall);
		self.destroy();
		selectedTower = null;
	};
	closeButton.down = function () {
		hideUpgradeMenu(self);
		selectedTower = null;
	};
	self.update = function () {
		if (self.laserWall.level >= self.laserWall.maxLevel) {
			return;
		}
		var currentUpgradeCost = Math.floor(40 * Math.pow(2, self.laserWall.level - 1));
		if (self.laserWall.level === self.laserWall.maxLevel - 1) {
			currentUpgradeCost = Math.floor(currentUpgradeCost * 3.5 / 2);
		}
		var canAfford = gold >= currentUpgradeCost;
		buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888;
	};
	return self;
});
var Manual = Container.expand(function () {
	var self = Container.call(this);
	// Manual background
	var background = self.attachAsset('manualBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.alpha = 0.95;
	// Title
	var titleText = new Text2('TOWER DEFENSE MANUAL', {
		size: 80,
		fill: 0xFFFFFF,
		weight: 800
	});
	titleText.anchor.set(0.5, 0);
	titleText.x = 0;
	titleText.y = -1150;
	self.addChild(titleText);
	// Create scrollable content container
	var contentContainer = new Container();
	self.addChild(contentContainer);
	var yPos = -1000;
	var sectionSpacing = 350;
	// Scrolling variables
	var isDragging = false;
	var startY = 0;
	var startContentY = 0;
	var velocity = 0;
	var minY = -1000; // Top limit
	var maxY = 0; // Will be calculated based on content height
	var contentHeight = 0; // Will be calculated after adding all content
	// Tower Classes Section
	self.createSection = function (title, items, startY) {
		var sectionY = startY;
		// Section title
		var sectionTitle = new Text2(title, {
			size: 60,
			fill: 0xFFD700,
			weight: 800
		});
		sectionTitle.anchor.set(0.5, 0);
		sectionTitle.x = 0;
		sectionTitle.y = sectionY;
		contentContainer.addChild(sectionTitle);
		sectionY += 80;
		// Items
		for (var i = 0; i < items.length; i++) {
			var item = items[i];
			// Item background
			var itemBg = contentContainer.attachAsset('manualSection', {
				anchorX: 0.5,
				anchorY: 0
			});
			itemBg.x = 0;
			itemBg.y = sectionY;
			itemBg.height = 200;
			itemBg.alpha = 0.3;
			// Item name
			var itemName = new Text2(item.name, {
				size: 50,
				fill: 0xFFFFFF,
				weight: 800
			});
			itemName.anchor.set(0, 0);
			itemName.x = -800;
			itemName.y = sectionY + 20;
			contentContainer.addChild(itemName);
			// Item stats
			var itemStats = new Text2(item.stats, {
				size: 40,
				fill: 0xCCCCCC,
				weight: 400
			});
			itemStats.anchor.set(0, 0);
			itemStats.x = -800;
			itemStats.y = sectionY + 80;
			contentContainer.addChild(itemStats);
			sectionY += 220;
		}
		return sectionY + 50;
	};
	// Tower data
	var towerData = [{
		name: 'BOW (Default)',
		stats: 'Cost: 5 gold • Damage: 10 • Range: 3 tiles • Rate: 1/s\nBalanced tower good for early game'
	}, {
		name: 'CROSSBOW (Rapid)',
		stats: 'Cost: 15 gold • Damage: 5 • Range: 2.5 tiles • Rate: 2/s\nFast firing tower, good against swarms'
	}, {
		name: 'SNIPER',
		stats: 'Cost: 25 gold • Damage: 25 • Range: 5 tiles • Rate: 0.67/s\nLong range, high damage, slow firing'
	}, {
		name: 'CANNON (Splash)',
		stats: 'Cost: 35 gold • Damage: 15 • Range: 2 tiles • Rate: 0.8/s\nArea damage affects nearby enemies'
	}, {
		name: 'ICE WIZARD (Slow)',
		stats: 'Cost: 45 gold • Damage: 8 • Range: 3.5 tiles • Rate: 1.2/s\nSlows enemies, ineffective vs immune'
	}, {
		name: 'FARM',
		stats: 'Cost: 30 gold • Income: 10 gold/wave (+15 per level)\nGenerates passive income, no combat'
	}, {
		name: 'LASER BASE ALPHA',
		stats: 'Cost: 40 gold • Requires 2+ in same row\nCreates laser wall, blocks ground enemies'
	}, {
		name: 'INFERNO (Single)',
		stats: 'Cost: 50 gold • Damage: 5 DPS • Range: 4 tiles\nContinuous beam that drains health'
	}, {
		name: 'TRICKY WIZARD (Weakening)',
		stats: 'Cost: 40 gold • Damage: 10 • Range: 3 tiles\n50% chance to confuse enemies'
	}, {
		name: 'CHURCH (Income)',
		stats: 'Cost: 60 gold • Gives 1 life per wave\nNo combat ability, provides lives'
	}, {
		name: 'MORTAR (Area)',
		stats: 'Cost: 55 gold • Damage: 30 • Range: 7 tiles\nHigh range area damage, min range 2 tiles'
	}];
	// Enemy data
	var enemyData = [{
		name: 'NORMAL',
		stats: 'Health: 100 • Speed: Normal • Ground unit\nBasic enemy type'
	}, {
		name: 'FAST',
		stats: 'Health: 100 • Speed: 2x Normal • Ground unit\nQuick moving enemy'
	}, {
		name: 'IMMUNE',
		stats: 'Health: 80 • Speed: Normal • Ground unit\nImmune to slow effects'
	}, {
		name: 'FLYING',
		stats: 'Health: 80 • Speed: Normal • Flying unit\nFlies over obstacles, immune to laser walls'
	}, {
		name: 'SWARM',
		stats: 'Health: 50 • Speed: Normal • Ground unit\nWeaker but comes in large numbers'
	}, {
		name: 'FLYING HORDE',
		stats: 'Health: 25 • Speed: 1.5x Normal • Flying unit\nSpawner creates multiple weak flying enemies'
	}, {
		name: 'MOLE DIGGER',
		stats: 'Health: 120 • Speed: 0.8x/2x Normal • Ground unit\nHides underground periodically, untargetable while hidden'
	}, {
		name: 'BOSS',
		stats: 'Health: 20x Normal • Speed: 0.7x Normal\nAppears every 10th wave, massive health'
	}, {
		name: 'MIXED',
		stats: 'Spawns various random enemy types\nUnpredictable wave composition'
	}];
	// Create sections
	yPos = self.createSection('TOWER TYPES', towerData, yPos);
	yPos = self.createSection('ENEMY TYPES', enemyData, yPos);
	// Game mechanics section
	var mechanicsData = [{
		name: 'TOWER TARGETING',
		stats: 'First: Closest to exit • Last: Farthest from exit\nStrong: Highest HP • Crowd: Most nearby enemies'
	}, {
		name: 'WAVE PROGRESSION',
		stats: 'Waves 1-10: Fixed types to introduce mechanics\nAfter wave 10: Random types except boss waves'
	}, {
		name: 'DIFFICULTY SCALING',
		stats: 'Enemy health increases 12% per wave\nBoss waves every 10th wave'
	}, {
		name: 'TOWER UPGRADES',
		stats: 'Level 1-5: Exponential cost increase\nLevel 6: Extra powerful, costs 3.5x previous'
	}, {
		name: 'SELLING TOWERS',
		stats: 'Returns 60% of total investment\nStrategic for repositioning'
	}];
	yPos = self.createSection('GAME MECHANICS', mechanicsData, yPos);
	// Calculate content height and set scroll limits
	contentHeight = yPos + 1000; // yPos is negative, so we add back the initial offset
	maxY = Math.min(0, -contentHeight + 1800); // 1800 is approximate visible height
	// Close button
	var closeButton = new Container();
	self.addChild(closeButton);
	var closeBg = closeButton.attachAsset('manualButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBg.width = 100;
	closeBg.height = 100;
	closeBg.tint = 0xFF4444;
	var closeText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	closeButton.x = 850;
	closeButton.y = -1150;
	closeButton.down = function () {
		self.destroy();
	};
	// Touch event handlers for scrolling
	self.down = function (x, y, obj) {
		// Don't start scrolling if clicking on the close button
		// Check if click is on close button using passed x,y coordinates
		var dx = x - closeButton.x;
		var dy = y - closeButton.y;
		if (Math.abs(dx) < 50 && Math.abs(dy) < 50) {
			return;
		}
		isDragging = true;
		startY = y;
		startContentY = contentContainer.y;
		velocity = 0;
	};
	self.move = function (x, y, obj) {
		if (isDragging) {
			var deltaY = y - startY;
			var newY = startContentY + deltaY;
			// Apply bounds
			newY = Math.max(maxY, Math.min(minY, newY));
			contentContainer.y = newY;
			// Calculate velocity for momentum
			velocity = deltaY * 0.5;
		}
	};
	self.up = function (x, y, obj) {
		isDragging = false;
	};
	// Update function for momentum scrolling
	self.update = function () {
		if (!isDragging && Math.abs(velocity) > 0.1) {
			// Apply momentum
			contentContainer.y += velocity;
			// Apply bounds
			contentContainer.y = Math.max(maxY, Math.min(minY, contentContainer.y));
			// Apply friction
			velocity *= 0.92;
			// Stop if velocity is too small
			if (Math.abs(velocity) < 0.1) {
				velocity = 0;
			}
		}
	};
	// Initial position (hidden)
	self.x = 2048 / 2; // Center horizontally
	self.y = 2732 + 1200;
	// Animate in
	tween(self, {
		y: 2732 / 2
	}, {
		duration: 300,
		easing: tween.backOut
	});
	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';
	// Use specific tower asset based on type
	var towerAssetId = 'tower_' + self.towerType;
	if (self.towerType === 'default') {
		towerAssetId = 'tower_default';
	}
	// Increase size of base for easier touch
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.3,
		scaleY: 1.3
	});
	// No need to tint anymore as we have specific assets
	var towerCost = getTowerCost(self.towerType);
	// Get display name for tower type
	var displayName = self.towerType;
	switch (self.towerType) {
		case 'default':
			displayName = 'Bow';
			break;
		case 'rapid':
			displayName = 'Crossbow';
			break;
		case 'splash':
			displayName = 'Cannon';
			break;
		case 'slow':
			displayName = 'Ice Wizard';
			break;
		case 'farm':
			displayName = 'Farm';
			break;
		case 'laser':
			displayName = 'Laser Base';
			break;
		case 'inferno':
			displayName = 'Inferno';
			break;
		case 'wizard':
			displayName = 'Tricky Wizard';
			break;
		case 'church':
			displayName = 'Church';
			break;
		case 'mortar':
			displayName = 'Mortar';
			break;
	}
	// Add shadow for tower type label
	var typeLabelShadow = new Text2(displayName, {
		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(displayName, {
		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;
	self.targetingMode = 'first'; // Options: 'first', 'last', 'strong', 'crowd'
	self.hasSpecialAbility = false; // Unlocked at max level
	self.specialAbilityActive = false;
	self.specialAbilityTimer = 0;
	self.rapidBurstCount = 0; // For archer rapid fire
	self.infernoTargets = []; // For inferno multi-target
	// 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 'sniper':
				// Sniper: base 5, +0.8 per level, infinite range with special ability
				if (self.hasSpecialAbility) {
					return 999 * CELL_SIZE; // Effectively infinite range
				}
				return (5 + (self.level - 1) * 0.8) * CELL_SIZE;
			case 'splash':
				// Splash: base 2, +0.2 per level (max ~4 blocks at max level)
				return (2 + (self.level - 1) * 0.2) * CELL_SIZE;
			case 'rapid':
				// Rapid: base 2.5, +0.5 per level
				return (2.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'slow':
				// Slow: base 3.5, +0.5 per level
				return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'farm':
				// Farm has no range
				return 0;
			case 'laser':
				// Laser has no shooting range
				return 0;
			case 'inferno':
				// Inferno: base 4, +0.3 per level
				return (4 + (self.level - 1) * 0.3) * CELL_SIZE;
			case 'wizard':
				// Wizard: base 3, +0.4 per level
				return (3 + (self.level - 1) * 0.4) * CELL_SIZE;
			case 'church':
				// Church has no range
				return 0;
			case 'mortar':
				// Mortar: base 7, +0.5 per level (high range)
				return (7 + (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 'rapid':
			self.fireRate = 30;
			self.damage = 5;
			self.range = 2.5 * CELL_SIZE;
			self.bulletSpeed = 7;
			break;
		case 'sniper':
			self.fireRate = 90;
			self.damage = 25;
			self.range = 5 * CELL_SIZE;
			self.bulletSpeed = 25;
			break;
		case 'splash':
			self.fireRate = 75;
			self.damage = 15;
			self.range = 2 * CELL_SIZE;
			self.bulletSpeed = 4;
			break;
		case 'slow':
			self.fireRate = 50;
			self.damage = 8;
			self.range = 3.5 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
		case 'farm':
			self.fireRate = 999999; // Farm doesn't shoot
			self.damage = 0;
			self.range = 0;
			self.bulletSpeed = 0;
			break;
		case 'laser':
			self.fireRate = 999999; // Laser doesn't shoot normally
			self.damage = 0;
			self.range = 0;
			self.bulletSpeed = 0;
			break;
		case 'inferno':
			self.fireRate = 999999; // Inferno uses continuous beam
			self.damage = 5; // Base DPS
			self.range = 4 * CELL_SIZE;
			self.bulletSpeed = 0;
			break;
		case 'wizard':
			self.fireRate = 120; // Slower fire rate
			self.damage = 10;
			self.range = 3 * CELL_SIZE;
			self.bulletSpeed = 6;
			break;
		case 'church':
			self.fireRate = 999999; // Church doesn't shoot
			self.damage = 0;
			self.range = 0;
			self.bulletSpeed = 0;
			break;
		case 'mortar':
			self.fireRate = 180; // Very slow fire rate
			self.damage = 30;
			self.range = 7 * CELL_SIZE;
			self.minRange = 2 * CELL_SIZE; // Can't hit close enemies
			self.bulletSpeed = 3;
			break;
	}
	// Use specific tower asset based on type
	var towerAssetId = 'tower_' + self.id;
	if (self.id === 'default') {
		towerAssetId = 'tower_default';
	}
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No need to tint anymore as we have specific assets
	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);
	// Use specific defense asset based on type
	var defenseAssetId = 'defense_' + self.id;
	if (self.id === 'default') {
		defenseAssetId = 'defense_default';
	}
	var gunGraphics = gunContainer.attachAsset(defenseAssetId, {
		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 'rapid':
						towerLevelIndicator.tint = 0x00AAFF;
						break;
					case 'sniper':
						towerLevelIndicator.tint = 0xFF5500;
						break;
					case 'splash':
						towerLevelIndicator.tint = 0x33CC00;
						break;
					case 'slow':
						towerLevelIndicator.tint = 0x9900FF;
						break;
					case 'farm':
						towerLevelIndicator.tint = 0xFFD700; // Gold color
						break;
					case 'laser':
						towerLevelIndicator.tint = 0xFF0088; // Pink color
						break;
					case 'inferno':
						towerLevelIndicator.tint = 0xFF4500; // Orange-red
						break;
					case 'wizard':
						towerLevelIndicator.tint = 0xFF1493; // Deep pink
						break;
					case 'church':
						towerLevelIndicator.tint = 0xFFD700; // Gold
						break;
					case 'mortar':
						towerLevelIndicator.tint = 0x8B4513; // Saddle brown
						break;
					default:
						towerLevelIndicator.tint = 0xAAAAAA;
				}
			}
		}
	};
	self.updateLevelIndicators();
	// Create inferno beam visual if this is an inferno tower
	if (self.id === 'inferno') {
		self.infernoBeam = self.attachAsset('infernoBeam', {
			anchorX: 0,
			anchorY: 0.5
		});
		self.infernoBeam.visible = false;
		self.infernoBeam.alpha = 0.8;
		self.infernoDamageTimer = 0;
	}
	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.getSpecialAbilityName = function () {
		switch (self.id) {
			case 'default':
				return 'Rapid Fire';
			case 'rapid':
				return 'Bleeding Shots';
			case 'sniper':
				return 'Infinite Range';
			case 'inferno':
				return 'Triple Beam';
			case 'splash':
				return 'Mega Blast';
			case 'laser':
				return 'Sky Piercer';
			case 'mortar':
				return 'Quad Shot';
			case 'slow':
				return 'Permafrost';
			case 'wizard':
				return 'Charm';
			case 'farm':
				return 'Gold Boost';
			case 'church':
				return 'Divine Intervention';
			default:
				return null;
		}
	};
	self.getSpecialAbilityCost = function () {
		// Special ability costs 3x the base tower cost
		return getTowerCost(self.id) * 3;
	};
	self.unlockSpecialAbility = function () {
		if (self.level >= 3 && !self.hasSpecialAbility) {
			var cost = self.getSpecialAbilityCost();
			if (gold >= cost) {
				setGold(gold - cost);
				self.hasSpecialAbility = true;
				// Show special ability unlocked notification
				var abilityName = self.getSpecialAbilityName();
				if (abilityName) {
					var notification = game.addChild(new Notification("Special Ability Unlocked: " + abilityName));
					notification.x = 2048 / 2;
					notification.y = grid.height - 100;
				}
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough gold for special ability!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	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++;
				LK.getSound('tower_upgrade').play();
				// Special ability is unlocked separately at level 3 (no longer automatic)
				// Special ability unlocking is now handled by separate purchase button
				// No need to update self.range here; getRange() is now the source of truth
				// Apply tower-specific upgrades based on type
				if (self.id === 'rapid') {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade (double the effect)
						self.fireRate = Math.max(4, 30 - self.level * 9); // double the effect
						self.damage = 5 + self.level * 10; // double the effect
						self.bulletSpeed = 7 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(15, 30 - self.level * 3); // Fast tower gets faster with upgrades
						self.damage = 5 + self.level * 3;
						self.bulletSpeed = 7 + self.level * 0.7;
					}
				} else if (self.id === 'inferno') {
					// Inferno tower damage scales differently (DPS)
					self.damage = 5 + self.level * 3;
				} else if (self.id === 'wizard') {
					if (self.level === self.maxLevel) {
						self.fireRate = Math.max(30, 120 - self.level * 30);
						self.damage = 10 + self.level * 15;
						self.bulletSpeed = 6 + self.level * 1.5;
					} else {
						self.fireRate = Math.max(60, 120 - self.level * 10);
						self.damage = 10 + self.level * 5;
						self.bulletSpeed = 6 + self.level * 0.5;
					}
				} else if (self.id === 'mortar') {
					if (self.level === self.maxLevel) {
						self.fireRate = Math.max(60, 180 - self.level * 40);
						self.damage = 30 + self.level * 25;
						self.bulletSpeed = 3 + self.level * 1.0;
					} else {
						self.fireRate = Math.max(120, 180 - self.level * 10);
						self.damage = 30 + self.level * 8;
						self.bulletSpeed = 3 + self.level * 0.3;
					}
				} else {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade for all other towers (double the effect)
						self.fireRate = Math.max(5, 60 - self.level * 24); // double the effect
						self.damage = 10 + self.level * 20; // double the effect
						self.bulletSpeed = 5 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(20, 60 - self.level * 8);
						self.damage = 10 + self.level * 5;
						self.bulletSpeed = 5 + self.level * 0.5;
					}
				}
				self.refreshCellsInRange();
				self.updateLevelIndicators();
				if (self.level > 1) {
					var levelDot = levelIndicators[self.level - 1].children[1];
					tween(levelDot, {
						scaleX: 1.5,
						scaleY: 1.5
					}, {
						duration: 300,
						easing: tween.elasticOut,
						onFinish: function onFinish() {
							tween(levelDot, {
								scaleX: 1,
								scaleY: 1
							}, {
								duration: 200,
								easing: tween.easeOut
							});
						}
					});
				}
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough gold to upgrade!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.findTarget = function () {
		var enemiesInRange = [];
		// First, collect all enemies in range
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			// Check if enemy is in range and not hidden underground
			if (distance <= self.getRange() && !enemy.isHidden) {
				// Mortar can't hit enemies that are too close
				if (self.id === 'mortar' && distance < self.minRange) {
					continue;
				}
				enemiesInRange.push({
					enemy: enemy,
					distance: distance,
					dx: dx,
					dy: dy
				});
			}
		}
		if (enemiesInRange.length === 0) {
			self.targetEnemy = null;
			return null;
		}
		var targetEnemy = null;
		switch (self.targetingMode) {
			case 'first':
				// Target enemy closest to the base (lowest path score or closest to goal for flying)
				var lowestScore = Infinity;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemyData = enemiesInRange[i];
					var enemy = enemyData.enemy;
					if (enemy.isFlying) {
						// For flying enemies, prioritize by distance to the goal
						if (enemy.flyingTarget) {
							var goalX = enemy.flyingTarget.x;
							var goalY = enemy.flyingTarget.y;
							var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY));
							// Use distance to goal as score
							if (distToGoal < lowestScore) {
								lowestScore = distToGoal;
								targetEnemy = enemy;
							}
						} else {
							// If no flying target yet (shouldn't happen), prioritize by distance to tower
							if (enemyData.distance < lowestScore) {
								lowestScore = enemyData.distance;
								targetEnemy = 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 < lowestScore) {
								lowestScore = cell.score;
								targetEnemy = enemy;
							}
						}
					}
				}
				break;
			case 'last':
				// Target enemy farthest from the base (highest path score)
				var highestScore = -Infinity;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemyData = enemiesInRange[i];
					var enemy = enemyData.enemy;
					if (enemy.isFlying) {
						// For flying enemies, prioritize by distance to the goal (inverse)
						if (enemy.flyingTarget) {
							var goalX = enemy.flyingTarget.x;
							var goalY = enemy.flyingTarget.y;
							var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY));
							// Use inverse distance to goal as score
							if (distToGoal > highestScore) {
								highestScore = distToGoal;
								targetEnemy = enemy;
							}
						}
					} else {
						// For ground enemies
						var cell = grid.getCell(enemy.cellX, enemy.cellY);
						if (cell && cell.pathId === pathId) {
							// Higher score means farther from exit
							if (cell.score > highestScore) {
								highestScore = cell.score;
								targetEnemy = enemy;
							}
						}
					}
				}
				break;
			case 'strong':
				// Target enemy with the most HP
				var mostHP = -1;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemy = enemiesInRange[i].enemy;
					if (enemy.health > mostHP) {
						mostHP = enemy.health;
						targetEnemy = enemy;
					}
				}
				break;
			case 'crowd':
				// Target enemy with the most other enemies nearby
				var maxCrowdScore = -1;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemyData = enemiesInRange[i];
					var enemy = enemyData.enemy;
					var crowdScore = 0;
					// Count enemies within 2 cells of this enemy
					for (var j = 0; j < enemies.length; j++) {
						if (enemies[j] !== enemy) {
							var edx = enemies[j].x - enemy.x;
							var edy = enemies[j].y - enemy.y;
							var edist = Math.sqrt(edx * edx + edy * edy);
							if (edist <= CELL_SIZE * 2) {
								crowdScore++;
							}
						}
					}
					if (crowdScore > maxCrowdScore) {
						maxCrowdScore = crowdScore;
						targetEnemy = enemy;
					}
				}
				break;
		}
		// For inferno tower with special ability, find up to 3 targets
		if (self.id === 'inferno' && self.hasSpecialAbility && enemiesInRange.length > 0) {
			self.infernoTargets = [];
			// Sort enemies by distance
			enemiesInRange.sort(function (a, b) {
				return a.distance - b.distance;
			});
			// Get up to 3 targets
			for (var i = 0; i < Math.min(3, enemiesInRange.length); i++) {
				self.infernoTargets.push(enemiesInRange[i].enemy);
			}
			return self.infernoTargets[0]; // Return primary target
		}
		return targetEnemy;
	};
	self.update = function () {
		// Farm towers don't target or shoot
		if (self.id === 'farm') {
			return;
		}
		// Laser towers are handled separately
		if (self.id === 'laser') {
			return;
		}
		// Church towers don't shoot
		if (self.id === 'church') {
			return;
		}
		// Inferno tower uses continuous beam
		if (self.id === 'inferno') {
			self.targetEnemy = self.findTarget();
			if (self.targetEnemy) {
				// Show and position beam
				self.infernoBeam.visible = true;
				var dx = self.targetEnemy.x - self.x;
				var dy = self.targetEnemy.y - self.y;
				var angle = Math.atan2(dy, dx);
				var distance = Math.sqrt(dx * dx + dy * dy);
				self.infernoBeam.rotation = angle;
				self.infernoBeam.width = distance;
				gunContainer.rotation = angle;
				// Deal damage every 10 ticks
				self.infernoDamageTimer++;
				if (self.infernoDamageTimer >= 10) {
					self.infernoDamageTimer = 0;
					// Calculate damage based on level
					var damagePerTick = oneHitKillCheat ? 999999 : self.damage + self.level * 3;
					self.targetEnemy.health -= damagePerTick;
					if (self.targetEnemy.health <= 0) {
						self.targetEnemy.health = 0;
					} else {
						self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70;
					}
					// Visual effect
					LK.effects.flashObject(self.targetEnemy, 0xFF4500, 100);
					// Handle multi-target ability
					if (self.hasSpecialAbility && self.infernoTargets.length > 1) {
						// Damage additional targets (50% damage)
						for (var i = 1; i < self.infernoTargets.length; i++) {
							var additionalTarget = self.infernoTargets[i];
							if (additionalTarget && additionalTarget.parent && !additionalTarget.isHidden) {
								additionalTarget.health -= oneHitKillCheat ? 999999 : damagePerTick * 0.5;
								if (additionalTarget.health <= 0) {
									additionalTarget.health = 0;
								} else {
									additionalTarget.healthBar.width = additionalTarget.health / additionalTarget.maxHealth * 70;
								}
								LK.effects.flashObject(additionalTarget, 0xFF4500, 100);
							}
						}
					}
				}
			} else {
				self.infernoBeam.visible = false;
				self.infernoDamageTimer = 0;
				self.infernoTargets = [];
			}
			return;
		}
		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;
			// Handle rapid burst fire for archer
			if (self.rapidBurstCount > 0) {
				if (LK.ticks - self.lastFired >= 6) {
					// Very fast fire rate during burst
					self.fire();
					self.lastFired = LK.ticks;
					self.rapidBurstCount--;
					if (self.rapidBurstCount === 0) {
						self.specialAbilityActive = false;
					}
				}
			} else if (LK.ticks - self.lastFired >= self.fireRate) {
				self.fire();
				self.lastFired = LK.ticks;
			}
		}
	};
	self.down = function (x, y, obj) {
		var existingMenus = game.children.filter(function (child) {
			return child instanceof UpgradeMenu;
		});
		var hasOwnMenu = false;
		var rangeCircle = null;
		for (var i = 0; i < game.children.length; i++) {
			if (game.children[i].isTowerRange && game.children[i].tower === self) {
				rangeCircle = game.children[i];
				break;
			}
		}
		for (var i = 0; i < existingMenus.length; i++) {
			if (existingMenus[i].tower === self) {
				hasOwnMenu = true;
				break;
			}
		}
		if (hasOwnMenu) {
			for (var i = 0; i < existingMenus.length; i++) {
				if (existingMenus[i].tower === self) {
					hideUpgradeMenu(existingMenus[i]);
				}
			}
			if (rangeCircle) {
				game.removeChild(rangeCircle);
			}
			selectedTower = null;
			grid.renderDebug();
			return;
		}
		for (var i = 0; i < existingMenus.length; i++) {
			existingMenus[i].destroy();
		}
		for (var i = game.children.length - 1; i >= 0; i--) {
			if (game.children[i].isTowerRange) {
				game.removeChild(game.children[i]);
			}
		}
		selectedTower = self;
		var rangeIndicator = new Container();
		rangeIndicator.isTowerRange = true;
		rangeIndicator.tower = self;
		game.addChild(rangeIndicator);
		rangeIndicator.x = self.x;
		rangeIndicator.y = self.y;
		var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		rangeGraphics.width = rangeGraphics.height = self.getRange() * 2;
		rangeGraphics.alpha = 0.3;
		var upgradeMenu = new UpgradeMenu(self);
		game.addChild(upgradeMenu);
		upgradeMenu.x = 2048 / 2;
		tween(upgradeMenu, {
			y: 2732 - 325
		}, {
			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 () {
		// Handle archer rapid fire ability
		if (self.id === 'default' && self.hasSpecialAbility && Math.random() < 0.25) {
			self.rapidBurstCount = 5;
			self.specialAbilityActive = true;
		}
		// Handle mortar quad shot ability
		if (self.id === 'mortar' && self.hasSpecialAbility) {
			// Fire 4 projectiles at once
			if (self.targetEnemy) {
				for (var i = 0; i < 4; i++) {
					var offsetAngle = (i - 1.5) * 0.3; // Spread the shots
					var targetX = self.targetEnemy.x + Math.cos(offsetAngle) * 50;
					var targetY = self.targetEnemy.y + Math.sin(offsetAngle) * 50;
					var bulletX = self.x + Math.cos(gunContainer.rotation + offsetAngle) * 40;
					var bulletY = self.y + Math.sin(gunContainer.rotation + offsetAngle) * 40;
					var bullet = new Bullet(bulletX, bulletY, null, self.damage, self.bulletSpeed);
					bullet.type = 'mortar';
					bullet.targetX = targetX;
					bullet.targetY = targetY;
					// Replace bullet graphics
					bullet.removeChild(bullet.children[0]);
					var mortarGraphics = bullet.attachAsset('bullet_mortar', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					game.addChild(bullet);
					bullets.push(bullet);
				}
			}
			return;
		}
		// Handle cannon mega blast ability
		if (self.id === 'splash' && self.hasSpecialAbility && self.specialAbilityTimer <= 0) {
			self.fireRate = 25; // Triple fire rate
			self.specialAbilityTimer = 180; // 3 second duration
		}
		if (self.id === 'splash' && self.specialAbilityTimer > 0) {
			self.specialAbilityTimer--;
			if (self.specialAbilityTimer === 0) {
				self.fireRate = 75; // Reset to normal
			}
		}
		if (self.targetEnemy) {
			var potentialDamage = 0;
			for (var i = 0; i < self.targetEnemy.bulletsTargetingThis.length; i++) {
				potentialDamage += self.targetEnemy.bulletsTargetingThis[i].damage;
			}
			if (self.targetEnemy.health > potentialDamage) {
				var bulletX = self.x + Math.cos(gunContainer.rotation) * 40;
				var bulletY = self.y + Math.sin(gunContainer.rotation) * 40;
				var bulletDamage = oneHitKillCheat ? 999999 : self.damage;
				var bullet = new Bullet(bulletX, bulletY, self.targetEnemy, bulletDamage, self.bulletSpeed);
				// Set bullet type based on tower type
				bullet.type = self.id;
				// For slow tower, pass level for scaling slow effect
				if (self.id === 'slow') {
					bullet.sourceTowerLevel = self.level;
					bullet.hasPermafrostAbility = self.hasSpecialAbility;
				} else if (self.id === 'rapid') {
					bullet.hasBleedAbility = self.hasSpecialAbility;
				} else if (self.id === 'wizard') {
					bullet.hasCharmAbility = self.hasSpecialAbility;
				}
				// For mortar, store target position instead of enemy
				if (self.id === 'mortar') {
					bullet.targetX = self.targetEnemy.x;
					bullet.targetY = self.targetEnemy.y;
					bullet.targetEnemy = null; // Mortar targets location, not enemy
				}
				// Replace bullet graphics with tower-specific asset
				var bulletAssetId = 'bullet';
				if (self.id !== 'default') {
					bulletAssetId = 'bullet_' + self.id;
				}
				// Remove the old generic bullet graphic
				bullet.removeChild(bullet.children[0]);
				// Attach the specific bullet asset
				var specificBulletGraphics = bullet.attachAsset(bulletAssetId, {
					anchorX: 0.5,
					anchorY: 0.5
				});
				game.addChild(bullet);
				bullets.push(bullet);
				self.targetEnemy.bulletsTargetingThis.push(bullet);
				// Play shooting sound based on tower type
				if (self.id === 'sniper') {
					LK.getSound('tower_shoot').play();
				} else if (self.id === 'splash' || self.id === 'mortar') {
					LK.getSound('explosion').play();
				} else if (self.id === 'slow') {
					LK.getSound('freeze').play();
				} else if (self.id === 'wizard') {
					LK.getSound('charm').play();
				} else {
					LK.getSound('tower_shoot').play();
				}
				// --- 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 'rapid':
				previewGraphics.tint = 0x00AAFF;
				break;
			case 'sniper':
				previewGraphics.tint = 0xFF5500;
				break;
			case 'splash':
				previewGraphics.tint = 0x33CC00;
				break;
			case 'slow':
				previewGraphics.tint = 0x9900FF;
				break;
			case 'farm':
				previewGraphics.tint = 0xFFD700; // Gold color
				break;
			case 'laser':
				previewGraphics.tint = 0xFF0088; // Pink color
				break;
			case 'inferno':
				previewGraphics.tint = 0xFF4500; // Orange-red
				break;
			case 'wizard':
				previewGraphics.tint = 0xFF1493; // Deep pink
				break;
			case 'church':
				previewGraphics.tint = 0xFFD700; // Gold
				break;
			case 'mortar':
				previewGraphics.tint = 0x8B4513; // Saddle brown
				break;
			default:
				previewGraphics.tint = 0xAAAAAA;
		}
		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 + 325;
	var menuBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	menuBackground.width = 2048;
	menuBackground.height = 700;
	menuBackground.tint = 0x444444;
	menuBackground.alpha = 0.9;
	// Get display name for tower type
	var displayName = self.tower.id;
	switch (self.tower.id) {
		case 'default':
			displayName = 'Bow';
			break;
		case 'rapid':
			displayName = 'Crossbow';
			break;
		case 'splash':
			displayName = 'Cannon';
			break;
		case 'slow':
			displayName = 'Ice Wizard';
			break;
		case 'farm':
			displayName = 'Farm';
			break;
		case 'laser':
			displayName = 'Laser Base Alpha';
			break;
		case 'inferno':
			displayName = 'Inferno';
			break;
		case 'wizard':
			displayName = 'Tricky Wizard';
			break;
		case 'church':
			displayName = 'Church';
			break;
		case 'mortar':
			displayName = 'Mortar';
			break;
	}
	var towerTypeText = new Text2(displayName + ' 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(self.tower.id === 'inferno' ? 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + (self.tower.damage + self.tower.level * 3) + ' DPS\nRange: ' + (self.tower.getRange() / CELL_SIZE).toFixed(1) + ' tiles' : self.tower.id === 'church' ? 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nLives per wave: ' + self.tower.level + '\nNo combat ability' : '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 buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	// Special ability button
	var specialButton = new Container();
	buttonsContainer.addChild(specialButton);
	var specialBackground = specialButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	specialBackground.width = 500;
	specialBackground.height = 150;
	var hasAbility = self.tower.hasSpecialAbility;
	var abilityName = self.tower.getSpecialAbilityName();
	var canUnlock = self.tower.level >= 3 && !hasAbility;
	var abilityCost = canUnlock ? self.tower.getSpecialAbilityCost() : 0;
	var lockText = self.tower.level < 3 ? 'Locked (Lv 3)' : canUnlock ? 'Buy: ' + abilityCost + ' gold' : 'Locked';
	specialBackground.tint = hasAbility ? 0x9400D3 : canUnlock ? gold >= abilityCost ? 0x00AA00 : 0x888888 : 0x444444;
	var specialText = new Text2(hasAbility ? abilityName : lockText, {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	specialText.anchor.set(0.5, 0.5);
	specialButton.addChild(specialText);
	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);
	// Targeting mode button
	var targetingButton = new Container();
	buttonsContainer.addChild(targetingButton);
	var targetingBackground = targetingButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	targetingBackground.width = 500;
	targetingBackground.height = 150;
	targetingBackground.tint = 0x0088FF;
	var targetingModeNames = {
		'first': 'First',
		'last': 'Last',
		'strong': 'Strong',
		'crowd': 'Crowd'
	};
	var targetingText = new Text2('Target: ' + targetingModeNames[self.tower.targetingMode], {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	targetingText.anchor.set(0.5, 0.5);
	targetingButton.addChild(targetingText);
	upgradeButton.y = -210;
	specialButton.y = -70;
	targetingButton.y = 70;
	sellButton.y = 210;
	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) {
		LK.getSound('button_click').play();
		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));
			}
			if (self.tower.id === 'inferno') {
				statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + (self.tower.damage + self.tower.level * 3) + ' DPS\nRange: ' + (self.tower.getRange() / CELL_SIZE).toFixed(1) + ' tiles');
			} else if (self.tower.id === 'church') {
				statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nLives per wave: ' + self.tower.level + '\nNo combat ability');
			} else {
				statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s');
			}
			// Update special ability button when upgrading
			if (self.tower.hasSpecialAbility && !hasAbility) {
				specialBackground.tint = 0x9400D3;
				specialText.setText(self.tower.getSpecialAbilityName());
			}
			buttonText.setText('Upgrade: ' + 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
					});
				}
			});
		}
	};
	specialButton.down = function () {
		if (self.tower.hasSpecialAbility) {
			var notification = game.addChild(new Notification("Special Ability: " + self.tower.getSpecialAbilityName()));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
		} else if (self.tower.level >= 3) {
			// Try to purchase special ability
			if (self.tower.unlockSpecialAbility()) {
				// Update button appearance after successful purchase
				specialBackground.tint = 0x9400D3;
				specialText.setText(self.tower.getSpecialAbilityName());
			}
		} else {
			var notification = game.addChild(new Notification("Reach level 3 to unlock special ability!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
		}
	};
	targetingButton.down = function () {
		// Cycle through targeting modes
		var modes = ['first', 'last', 'strong', 'crowd'];
		var currentIndex = modes.indexOf(self.tower.targetingMode);
		var nextIndex = (currentIndex + 1) % modes.length;
		self.tower.targetingMode = modes[nextIndex];
		var targetingModeNames = {
			'first': 'First',
			'last': 'Last',
			'strong': 'Strong',
			'crowd': 'Crowd'
		};
		targetingText.setText('Target: ' + targetingModeNames[self.tower.targetingMode]);
		// Visual feedback
		tween(targetingButton, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(targetingButton, {
					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();
		// Update laser walls if we removed a laser tower
		if (self.tower.id === 'laser') {
			updateLaserWalls();
		}
		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;
			}
		} else {
			// 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 newText = 'Upgrade: ' + currentUpgradeCost + ' gold';
			if (buttonText.text !== newText) {
				buttonText.setText(newText);
			}
		}
		// Update special ability button
		if (!self.tower.hasSpecialAbility && self.tower.level >= 3) {
			var abilityCost = self.tower.getSpecialAbilityCost();
			var canAffordAbility = gold >= abilityCost;
			specialBackground.tint = canAffordAbility ? 0x00AA00 : 0x888888;
			var newSpecialText = 'Buy: ' + abilityCost + ' gold';
			if (specialText.text !== newSpecialText) {
				specialText.setText(newSpecialText);
			}
		}
	};
	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;
			LK.getSound('wave_start').play();
		}
	};
	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 = "Normal";
			enemyType = "normal";
			enemyCount = 10;
		} else if (i === 1) {
			block.tint = 0x00AAFF;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if (i === 2) {
			block.tint = 0xAA0000;
			waveType = "Immune";
			enemyType = "immune";
			enemyCount = 10;
		} else if (i === 3) {
			block.tint = 0xFFFF00;
			waveType = "Flying";
			enemyType = "flying";
			enemyCount = 10;
		} else if (i === 4) {
			block.tint = 0xFF00FF;
			waveType = "Swarm";
			enemyType = "swarm";
			enemyCount = 30;
		} else if (i === 5) {
			block.tint = 0x00FFFF;
			waveType = "Flying Horde";
			enemyType = "flying_horde";
			enemyCount = 3; // Few spawners that create many
		} else if (i === 6) {
			block.tint = 0x8B4513;
			waveType = "Mole Digger";
			enemyType = "mole";
			enemyCount = 8;
		} else if (i === 7) {
			block.tint = 0xFFFFFF;
			waveType = "Mixed";
			enemyType = "mixed";
			enemyCount = 12;
		} else if (isBossWave) {
			// Boss waves: cycle through all boss types, last boss is always flying
			var bossTypes = ['normal', 'fast', 'immune', 'flying'];
			var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
			if (i === totalWaves - 1) {
				// Last boss is always flying
				enemyType = 'flying';
				waveType = "Boss Flying";
				block.tint = 0xFFFF00;
			} else {
				enemyType = bossTypes[bossTypeIndex % bossTypes.length];
				switch (enemyType) {
					case 'normal':
						block.tint = 0xAAAAAA;
						waveType = "Boss Normal";
						break;
					case 'fast':
						block.tint = 0x00AAFF;
						waveType = "Boss Fast";
						break;
					case 'immune':
						block.tint = 0xAA0000;
						waveType = "Boss Immune";
						break;
					case 'flying':
						block.tint = 0xFFFF00;
						waveType = "Boss Flying";
						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;
				default:
					block.tint = 0xFF0000;
					break;
			}
		} else if (i + 1 > 10) {
			// After wave 10, all non-boss waves are completely random
			var randomWaveTypes = [{
				type: 'normal',
				name: 'Normal',
				tint: 0xAAAAAA,
				count: 10
			}, {
				type: 'fast',
				name: 'Fast',
				tint: 0x00AAFF,
				count: 10
			}, {
				type: 'immune',
				name: 'Immune',
				tint: 0xAA0000,
				count: 10
			}, {
				type: 'flying',
				name: 'Flying',
				tint: 0xFFFF00,
				count: 10
			}, {
				type: 'swarm',
				name: 'Swarm',
				tint: 0xFF00FF,
				count: 30
			}, {
				type: 'flying_horde',
				name: 'Flying Horde',
				tint: 0x00FFFF,
				count: 3
			}, {
				type: 'mole',
				name: 'Mole Digger',
				tint: 0x8B4513,
				count: 8
			}, {
				type: 'mixed',
				name: 'Mixed',
				tint: 0xFFFFFF,
				count: 12
			}];
			var randomChoice = randomWaveTypes[Math.floor(Math.random() * randomWaveTypes.length)];
			enemyType = randomChoice.type;
			waveType = randomChoice.name;
			block.tint = randomChoice.tint;
			enemyCount = randomChoice.count;
		} else if ((i + 1) % 5 === 0) {
			// Every 5th non-boss wave is fast
			block.tint = 0x00AAFF;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if ((i + 1) % 4 === 0) {
			// Every 4th non-boss wave is immune
			block.tint = 0xAA0000;
			waveType = "Immune";
			enemyType = "immune";
			enemyCount = 10;
		} else if ((i + 1) % 7 === 0) {
			// Every 7th non-boss wave is flying
			block.tint = 0xFFFF00;
			waveType = "Flying";
			enemyType = "flying";
			enemyCount = 10;
		} else if ((i + 1) % 3 === 0) {
			// Every 3rd non-boss wave is swarm
			block.tint = 0xFF00FF;
			waveType = "Swarm";
			enemyType = "swarm";
			enemyCount = 30;
		} else if ((i + 1) % 8 === 0) {
			// Every 8th non-boss wave is flying horde
			block.tint = 0x00FFFF;
			waveType = "Flying Horde";
			enemyType = "flying_horde";
			enemyCount = 3;
		} else if ((i + 1) % 9 === 0) {
			// Every 9th non-boss wave is mole digger
			block.tint = 0x8B4513;
			waveType = "Mole Digger";
			enemyType = "mole";
			enemyCount = 8;
		} else if ((i + 1) % 6 === 0) {
			// Every 6th non-boss wave is mixed
			block.tint = 0xFFFFFF;
			waveType = "Mixed";
			enemyType = "mixed";
			enemyCount = 12;
		} else {
			block.tint = 0xAAAAAA;
			waveType = "Normal";
			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 () {
		var progress = waveTimer / nextWaveTime;
		var moveAmount = (progress + currentWave) * blockWidth;
		for (var i = 0; i < self.waveMarkers.length; i++) {
			var marker = self.waveMarkers[i];
			marker.x = -moveAmount + i * blockWidth;
		}
		self.positionIndicator.x = 0;
		for (var i = 0; i < totalWaves + 1; i++) {
			var marker = self.waveMarkers[i];
			if (i === 0) {
				continue;
			}
			var block = marker.children[0];
			if (i - 1 < currentWave) {
				block.alpha = .5;
			}
		}
		self.handleWaveProgression = function () {
			if (!self.gameStarted) {
				return;
			}
			if (currentWave < totalWaves) {
				waveTimer++;
				if (waveTimer >= nextWaveTime) {
					waveTimer = 0;
					currentWave++;
					waveInProgress = true;
					waveSpawned = false;
					if (currentWave != 1) {
						var waveType = self.getWaveTypeName(currentWave);
						var enemyCount = self.getEnemyCount(currentWave);
						var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) incoming!"));
						notification.x = 2048 / 2;
						notification.y = grid.height - 150;
					}
				}
			}
		};
		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 + 325
	}, {
		duration: 150,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			menu.destroy();
			isHidingUpgradeMenu = false;
		}
	});
}
var CELL_SIZE = 76;
var pathId = 1;
var maxScore = 0;
var enemies = [];
var towers = [];
var bullets = [];
var defenses = [];
var laserWalls = [];
var selectedTower = null;
var gold = 100;
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
// Cheat variables
var unlimitedMoneyCheat = false;
var oneHitKillCheat = false;
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;
function updateUI() {
	goldText.setText('Gold: ' + gold);
	livesText.setText('Lives: ' + lives);
	scoreText.setText('Score: ' + score);
}
function setGold(value) {
	if (unlimitedMoneyCheat) {
		gold = 999999;
	} else {
		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 'rapid':
			cost = 15;
			break;
		case 'sniper':
			cost = 25;
			break;
		case 'splash':
			cost = 35;
			break;
		case 'slow':
			cost = 45;
			break;
		case 'farm':
			cost = 30;
			break;
		case 'laser':
			cost = 40;
			break;
		case 'inferno':
			cost = 50;
			break;
		case 'wizard':
			cost = 40;
			break;
		case 'church':
			cost = 60;
			break;
		case 'mortar':
			cost = 55;
			break;
	}
	return cost;
}
function getTowerSellValue(totalValue) {
	return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
}
function updateLaserWalls() {
	// Remove all existing laser walls
	for (var i = laserWalls.length - 1; i >= 0; i--) {
		game.removeChild(laserWalls[i]);
	}
	laserWalls = [];
	// Group laser towers by row
	var laserTowersByRow = {};
	for (var i = 0; i < towers.length; i++) {
		if (towers[i].id === 'laser') {
			var row = towers[i].gridY;
			if (!laserTowersByRow[row]) {
				laserTowersByRow[row] = [];
			}
			laserTowersByRow[row].push(towers[i]);
		}
	}
	// Create laser walls for rows with 2 or more laser towers
	for (var row in laserTowersByRow) {
		var rowTowers = laserTowersByRow[row];
		if (rowTowers.length >= 2) {
			// Sort towers by x position
			rowTowers.sort(function (a, b) {
				return a.x - b.x;
			});
			// Create walls between adjacent towers
			for (var i = 0; i < rowTowers.length - 1; i++) {
				var wall = new LaserWall(rowTowers[i], rowTowers[i + 1]);
				game.addChild(wall);
				laserWalls.push(wall);
			}
		}
	}
}
function placeTower(gridX, gridY, towerType) {
	var towerCost = getTowerCost(towerType);
	if (gold >= towerCost) {
		var tower = new Tower(towerType || 'default');
		tower.placeOnGrid(gridX, gridY);
		towerLayer.addChild(tower);
		towers.push(tower);
		setGold(gold - towerCost);
		LK.getSound('place_tower').play();
		grid.pathFind();
		grid.renderDebug();
		// Update laser walls if we placed a laser tower
		if (towerType === 'laser') {
			updateLaserWalls();
		}
		return true;
	} else {
		var notification = game.addChild(new Notification("Not enough gold!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		LK.getSound('error').play();
		return false;
	}
}
game.down = function (x, y, obj) {
	var upgradeMenuVisible = game.children.some(function (child) {
		return child instanceof UpgradeMenu;
	});
	if (upgradeMenuVisible) {
		return;
	}
	// Check if clicking on a class button
	for (var i = 0; i < classButtons.length; i++) {
		var button = classButtons[i];
		if (x >= button.x - button.width / 2 && x <= button.x + button.width / 2 && y >= button.y - button.height / 2 && y <= button.y + button.height / 2) {
			// Class button was clicked, let it handle the event
			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);
// Tower classes configuration
var towerClasses = {
	'Single Damage': {
		towers: ['default', 'rapid', 'sniper', 'inferno'],
		color: 0x4488FF
	},
	'Area Damage': {
		towers: ['splash', 'laser', 'mortar'],
		color: 0xFF8844
	},
	'Weakening': {
		towers: ['slow', 'wizard'],
		color: 0x8844FF
	},
	'Income/Lives': {
		towers: ['farm', 'church'],
		color: 0x44FF88
	}
};
var sourceTowers = [];
var classButtons = [];
var currentClass = null;
var towerSelectionContainer = new Container();
game.addChild(towerSelectionContainer);
// Create class buttons
var classButtonWidth = 400;
var classButtonHeight = 80;
var classButtonSpacing = 20;
var classNames = Object.keys(towerClasses);
var totalClassWidth = classNames.length * classButtonWidth + (classNames.length - 1) * classButtonSpacing;
var classStartX = 2048 / 2 - totalClassWidth / 2 + classButtonWidth / 2;
var classButtonY = 2732 - CELL_SIZE * 3 - 180;
for (var i = 0; i < classNames.length; i++) {
	var className = classNames[i];
	var classData = towerClasses[className];
	var classButton = new Container();
	classButton.className = className;
	classButton.classData = classData;
	var buttonBg = classButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBg.width = classButtonWidth;
	buttonBg.height = classButtonHeight;
	buttonBg.tint = classData.color;
	buttonBg.alpha = 0.7;
	var buttonText = new Text2(className, {
		size: 40,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	classButton.addChild(buttonText);
	classButton.x = classStartX + i * (classButtonWidth + classButtonSpacing);
	classButton.y = classButtonY;
	classButton.down = function () {
		selectTowerClass(this.className);
	};
	towerSelectionContainer.addChild(classButton);
	classButtons.push(classButton);
}
// Function to select a tower class
function selectTowerClass(className) {
	// Update class button appearances
	for (var i = 0; i < classButtons.length; i++) {
		var button = classButtons[i];
		var bg = button.children[0];
		if (button.className === className) {
			bg.alpha = 1.0;
			bg.tint = button.classData.color;
		} else {
			bg.alpha = 0.3;
			bg.tint = 0x666666;
		}
	}
	// Clear existing source towers
	for (var i = 0; i < sourceTowers.length; i++) {
		towerLayer.removeChild(sourceTowers[i]);
	}
	sourceTowers = [];
	// Create towers for selected class
	currentClass = className;
	var classData = towerClasses[className];
	var towerTypes = classData.towers;
	var towerSpacing = 300;
	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);
	}
}
// Select first class by default
selectTowerClass(classNames[0]);
// Play theme music
LK.playMusic('game_theme');
// Create manual button
var manualButton = new Container();
var manualBg = manualButton.attachAsset('manualButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
manualBg.tint = 0x4CAF50;
var manualText = new Text2('?', {
	size: 70,
	fill: 0xFFFFFF,
	weight: 800
});
manualText.anchor.set(0.5, 0.5);
manualButton.addChild(manualText);
manualButton.x = 2048 - 80;
manualButton.y = 150;
manualButton.down = function () {
	var manual = new Manual();
	game.addChild(manual);
};
game.addChild(manualButton);
// Create cheat button
var cheatButton = new Container();
var cheatBg = cheatButton.attachAsset('manualButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
cheatBg.tint = 0xFF0000;
var cheatText = new Text2('C', {
	size: 70,
	fill: 0xFFFFFF,
	weight: 800
});
cheatText.anchor.set(0.5, 0.5);
cheatButton.addChild(cheatText);
cheatButton.x = 2048 - 200;
cheatButton.y = 150;
cheatButton.down = function () {
	var cheatMenu = new CheatMenu();
	game.addChild(cheatMenu);
};
game.addChild(cheatButton);
sourceTower = null;
enemiesToSpawn = 10;
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;
				LK.getSound('boss_spawn').play();
			}
			// Spawn the appropriate number of enemies
			for (var i = 0; i < enemyCount; i++) {
				var enemy;
				if (waveType === 'mixed') {
					// Mixed wave spawns random enemy types
					var mixedTypes = ['normal', 'fast', 'immune', 'flying', 'swarm', 'mole'];
					var randomType = mixedTypes[Math.floor(Math.random() * mixedTypes.length)];
					enemy = new Enemy(randomType);
				} else {
					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;
			// Give income from all farm towers
			var totalFarmIncome = 0;
			for (var i = 0; i < towers.length; i++) {
				if (towers[i].id === 'farm') {
					// Base income 10, +15 per level
					var farmIncome = 10 + (towers[i].level - 1) * 15;
					totalFarmIncome += farmIncome;
				}
			}
			if (totalFarmIncome > 0) {
				setGold(gold + totalFarmIncome);
				var notification = game.addChild(new Notification("Farm income: +" + totalFarmIncome + " gold!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 250;
			}
			// Give lives from all church towers
			var totalChurchLives = 0;
			var hasDivineIntervention = false;
			for (var i = 0; i < towers.length; i++) {
				if (towers[i].id === 'church') {
					// Church gives 1 life per wave at level 1, +1 per level upgrade
					totalChurchLives += towers[i].level; // Level 1 = 1 life, Level 2 = 2 lives, etc.
					// Check for divine intervention ability
					if (towers[i].hasSpecialAbility && Math.random() < 0.1) {
						// 10% chance
						hasDivineIntervention = true;
					}
				}
			}
			if (totalChurchLives > 0) {
				lives += totalChurchLives;
				updateUI();
				var notification = game.addChild(new Notification("Church blessing: +" + totalChurchLives + " lives!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 300;
			}
			// Handle divine intervention
			if (hasDivineIntervention && currentWave < totalWaves) {
				// Skip the next wave and give 350 gold
				currentWave++;
				waveTimer = 0;
				setGold(gold + 350);
				var notification = game.addChild(new Notification("Divine Intervention! Wave skipped +350 gold!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 350;
				LK.getSound('divine_intervention').play();
			}
			// Check for laser tower pairs and create/update laser walls
			updateLaserWalls();
		}
	}
	for (var a = enemies.length - 1; a >= 0; a--) {
		var enemy = enemies[a];
		if (enemy.health <= 0) {
			for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
				var bullet = enemy.bulletsTargetingThis[i];
				bullet.targetEnemy = null;
			}
			// Boss enemies give more gold and score
			var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
			// Check if killed by a tower in range of a farm with special ability
			var farmBonus = 0;
			for (var i = 0; i < towers.length; i++) {
				if (towers[i].id === 'farm' && towers[i].hasSpecialAbility) {
					// Check if any tower that could have killed this enemy is in range of the farm
					var farmX = towers[i].x;
					var farmY = towers[i].y;
					var farmRange = 3 * CELL_SIZE; // Farm boost range
					for (var j = 0; j < towers.length; j++) {
						if (towers[j].id !== 'farm') {
							var dx = towers[j].x - farmX;
							var dy = towers[j].y - farmY;
							var distance = Math.sqrt(dx * dx + dy * dy);
							if (distance <= farmRange) {
								// Check if this tower could have killed the enemy
								var towerToEnemyDx = enemy.x - towers[j].x;
								var towerToEnemyDy = enemy.y - towers[j].y;
								var towerToEnemyDist = Math.sqrt(towerToEnemyDx * towerToEnemyDx + towerToEnemyDy * towerToEnemyDy);
								if (towerToEnemyDist <= towers[j].getRange()) {
									farmBonus = Math.ceil(goldEarned * 0.25); // 25% bonus
									break;
								}
							}
						}
					}
					if (farmBonus > 0) break;
				}
			}
			var totalGold = goldEarned + farmBonus;
			var goldIndicator = new GoldIndicator(totalGold, enemy.x, enemy.y);
			game.addChild(goldIndicator);
			setGold(gold + totalGold);
			LK.getSound('enemy_death').play();
			LK.getSound('gold_collect').play();
			// Give more score for defeating a boss
			var scoreValue = enemy.isBoss ? 100 : 5;
			score += scoreValue;
			// Add a notification for boss defeat
			if (enemy.isBoss) {
				var notification = game.addChild(new Notification("Boss defeated! +" + goldEarned + " gold!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 150;
			}
			updateUI();
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			continue;
		}
		if (grid.updateEnemy(enemy)) {
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			lives = Math.max(0, lives - 1);
			updateUI();
			if (lives <= 0) {
				LK.getSound('game_over').play();
				LK.stopMusic();
				LK.showGameOver();
			}
		}
	}
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (!bullets[i].parent) {
			if (bullets[i].targetEnemy) {
				var targetEnemy = bullets[i].targetEnemy;
				var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
				if (bulletIndex !== -1) {
					targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
				}
			}
			bullets.splice(i, 1);
		}
	}
	if (towerPreview.visible) {
		towerPreview.checkPlacement();
	}
	// Update all laser walls
	for (var i = 0; i < laserWalls.length; i++) {
		laserWalls[i].update();
	}
	if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) {
		LK.getSound('victory').play();
		LK.stopMusic();
		LK.showYouWin();
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.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;
	// Use default bullet asset initially, will be updated based on type
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.update = function () {
		// Mortar projectile logic
		if (self.type === 'mortar') {
			var dx = self.targetX - self.x;
			var dy = self.targetY - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < self.speed) {
				// Create explosion effect
				var mortarEffect = new EffectIndicator(self.targetX, self.targetY, 'mortar');
				game.addChild(mortarEffect);
				// Area damage
				var explosionRadius = CELL_SIZE * 1.5;
				for (var i = 0; i < enemies.length; i++) {
					var enemy = enemies[i];
					var enemyDx = enemy.x - self.targetX;
					var enemyDy = enemy.y - self.targetY;
					var enemyDist = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy);
					if (enemyDist <= explosionRadius) {
						// Damage falls off with distance
						var damageFactor = 1 - enemyDist / explosionRadius * 0.5;
						enemy.health -= oneHitKillCheat ? 999999 : self.damage * damageFactor;
						if (enemy.health <= 0) {
							enemy.health = 0;
						} else {
							enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
						}
					}
				}
				self.destroy();
			} else {
				var angle = Math.atan2(dy, dx);
				self.x += Math.cos(angle) * self.speed;
				self.y += Math.sin(angle) * self.speed;
			}
			return;
		}
		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;
			LK.getSound('enemy_hit').play();
			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 -= oneHitKillCheat ? 999999 : 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 === 'sniper') {
				// Create visual critical hit effect for sniper
				var sniperEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'sniper');
				game.addChild(sniperEffect);
			} else if (self.type === 'wizard') {
				// Check if tower has charm ability
				if (self.hasCharmAbility) {
					// Charm effect instead of confusion
					if (!self.targetEnemy.isCharmed && !self.targetEnemy.isImmune) {
						self.targetEnemy.isCharmed = true;
						self.targetEnemy.charmDuration = 300; // 5 seconds at 60 FPS
						self.targetEnemy.originalTeam = 'enemy';
						// Visual effect for charm
						var charmEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'charm');
						game.addChild(charmEffect);
					}
				} else {
					// Regular confusion effect
					if (Math.random() < 0.5 && !self.targetEnemy.isConfused && !self.targetEnemy.isImmune) {
						self.targetEnemy.isConfused = true;
						self.targetEnemy.confusionDuration = 180; // 3 seconds at 60 FPS
						// Visual effect for confusion
						var confuseEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'confuse');
						game.addChild(confuseEffect);
					}
				}
			} else if (self.type === 'rapid' && self.hasBleedAbility) {
				// 10% chance to apply bleed
				if (Math.random() < 0.1 && !self.targetEnemy.isBleeding && !self.targetEnemy.isImmune) {
					self.targetEnemy.isBleeding = true;
					self.targetEnemy.bleedDuration = 300; // 5 seconds at 60 FPS
					self.targetEnemy.bleedDamage = 5; // 5 damage per second
					// Visual effect for bleed
					var bleedEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'bleed');
					game.addChild(bleedEffect);
				}
			} else if (self.type === 'slow' && self.hasPermafrostAbility) {
				// Permanent slow effect
				if (!self.targetEnemy.isImmune) {
					// Create visual slow effect
					var slowEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'slow');
					game.addChild(slowEffect);
					// Apply permanent slow
					if (!self.targetEnemy.slowed) {
						self.targetEnemy.originalSpeed = self.targetEnemy.speed;
						self.targetEnemy.speed *= 0.2; // 80% slow
						self.targetEnemy.slowed = true;
						self.targetEnemy.slowDuration = 999999; // Permanent
						self.targetEnemy.permanentSlow = true;
					}
				}
			}
			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 CheatMenu = Container.expand(function () {
	var self = Container.call(this);
	// Background
	var background = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.width = 800;
	background.height = 600;
	background.tint = 0x222222;
	background.alpha = 0.95;
	// Title
	var titleText = new Text2('CHEATS', {
		size: 80,
		fill: 0xFF0000,
		weight: 800
	});
	titleText.anchor.set(0.5, 0);
	titleText.x = 0;
	titleText.y = -250;
	self.addChild(titleText);
	// Unlimited Money Toggle
	var moneyToggle = new Container();
	var moneyBg = moneyToggle.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	moneyBg.width = 700;
	moneyBg.height = 120;
	moneyBg.tint = unlimitedMoneyCheat ? 0x00FF00 : 0x888888;
	var moneyText = new Text2('Unlimited Money: ' + (unlimitedMoneyCheat ? 'ON' : 'OFF'), {
		size: 50,
		fill: 0xFFFFFF,
		weight: 800
	});
	moneyText.anchor.set(0.5, 0.5);
	moneyToggle.addChild(moneyText);
	moneyToggle.y = -80;
	self.addChild(moneyToggle);
	moneyToggle.down = function () {
		unlimitedMoneyCheat = !unlimitedMoneyCheat;
		moneyBg.tint = unlimitedMoneyCheat ? 0x00FF00 : 0x888888;
		moneyText.setText('Unlimited Money: ' + (unlimitedMoneyCheat ? 'ON' : 'OFF'));
		if (unlimitedMoneyCheat) {
			setGold(999999);
		}
	};
	// One Hit Kill Toggle
	var oneHitToggle = new Container();
	var oneHitBg = oneHitToggle.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	oneHitBg.width = 700;
	oneHitBg.height = 120;
	oneHitBg.tint = oneHitKillCheat ? 0x00FF00 : 0x888888;
	var oneHitText = new Text2('One Hit Kills: ' + (oneHitKillCheat ? 'ON' : 'OFF'), {
		size: 50,
		fill: 0xFFFFFF,
		weight: 800
	});
	oneHitText.anchor.set(0.5, 0.5);
	oneHitToggle.addChild(oneHitText);
	oneHitToggle.y = 80;
	self.addChild(oneHitToggle);
	oneHitToggle.down = function () {
		oneHitKillCheat = !oneHitKillCheat;
		oneHitBg.tint = oneHitKillCheat ? 0x00FF00 : 0x888888;
		oneHitText.setText('One Hit Kills: ' + (oneHitKillCheat ? 'ON' : 'OFF'));
	};
	// Close button
	var closeButton = new Container();
	var closeBg = closeButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBg.width = 90;
	closeBg.height = 90;
	closeBg.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 = background.width / 2 - 57;
	closeButton.y = -background.height / 2 + 57;
	self.addChild(closeButton);
	closeButton.down = function () {
		self.destroy();
	};
	// Initial position (centered)
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	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('', {
		size: 30,
		fill: 0xFFFFFF,
		weight: 800
	});
	numberLabel.anchor.set(.5, .5);
	numberLabel.visible = false;
	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.visible = false;
						cellGraphics.tint = 0x880000;
						return;
					}
					numberLabel.visible = false;
					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;
					}
					self.removeArrows();
					break;
				}
			case 1:
				{
					self.removeArrows();
					cellGraphics.tint = 0xaaaaaa;
					numberLabel.visible = false;
					break;
				}
			case 3:
				{
					self.removeArrows();
					cellGraphics.tint = 0x008800;
					numberLabel.visible = false;
					break;
				}
		}
	};
});
// This update method was incorrectly placed here and should be removed
var EffectIndicator = Container.expand(function (x, y, type) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	var effectGraphics = self.attachAsset('rangeCircle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	effectGraphics.blendMode = 1;
	switch (type) {
		case 'splash':
			effectGraphics.tint = 0x33CC00;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5;
			break;
		case 'slow':
			effectGraphics.tint = 0x9900FF;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'sniper':
			effectGraphics.tint = 0xFF5500;
			effectGraphics.width = effectGraphics.height = CELL_SIZE;
			break;
		case 'confuse':
			effectGraphics.tint = 0xFF1493;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.2;
			break;
		case 'mortar':
			effectGraphics.tint = 0x8B4513;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 3;
			break;
		case 'charm':
			effectGraphics.tint = 0xFFB6C1;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5;
			break;
		case 'bleed':
			effectGraphics.tint = 0x8B0000;
			effectGraphics.width = effectGraphics.height = CELL_SIZE * 0.8;
			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;
	self.isHidden = false;
	self.hideDuration = 0;
	self.hideTimer = 0;
	self.hasSpawned = 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; // Twice as fast
			self.maxHealth = 100;
			break;
		case 'immune':
			self.isImmune = true;
			self.maxHealth = 80;
			break;
		case 'flying':
			self.isFlying = true;
			self.maxHealth = 80;
			break;
		case 'swarm':
			self.maxHealth = 50; // Weaker enemies
			break;
		case 'flying_horde':
			self.isFlying = true;
			self.maxHealth = 25; // Very weak
			self.speed *= 1.5; // Fast
			break;
		case 'mole':
			self.maxHealth = 120; // Slightly tankier
			self.speed *= 0.8; // Slower when visible
			self.hideTimer = 300; // 5 seconds until first hide
			break;
		case 'mixed':
			// Mixed will be handled as a special spawner type
			self.maxHealth = 1; // Placeholder, should not be attacked
			self.isSpawner = true;
			break;
		case 'normal':
		default:
			// Normal enemy uses default values
			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;
		}
		// Handle mole digging mechanics
		if (self.type === 'mole') {
			self.hideTimer--;
			if (self.hideTimer <= 0) {
				if (!self.isHidden) {
					// Start hiding (go underground)
					self.isHidden = true;
					self.hideDuration = 90; // 1.5 seconds at 60 FPS
					self.hideTimer = 300; // 5 seconds until next hide
					// Double speed while hidden
					if (self.originalSpeed === undefined) {
						self.originalSpeed = self.speed;
					}
					self.speed = self.originalSpeed * 2;
					// Visual effect - make semi-transparent and darker
					enemyGraphics.alpha = 0.3;
					enemyGraphics.tint = 0x444444;
					// Hide health bar while underground
					healthBarOutline.visible = false;
					healthBarBG.visible = false;
					healthBar.visible = false;
				} else {
					// Come back up (surface)
					self.isHidden = false;
					self.hideTimer = 300; // 5 seconds until next hide
					// Reset speed
					if (self.originalSpeed !== undefined) {
						self.speed = self.originalSpeed;
					}
					// Restore visibility
					enemyGraphics.alpha = 1;
					enemyGraphics.tint = 0xFFFFFF;
					// Show health bar again
					healthBarOutline.visible = true;
					healthBarBG.visible = true;
					healthBar.visible = true;
				}
			} else if (self.isHidden) {
				self.hideDuration--;
				if (self.hideDuration <= 0) {
					// Force surface if duration is over
					self.isHidden = false;
					self.hideTimer = 300; // Reset timer
					// Reset speed
					if (self.originalSpeed !== undefined) {
						self.speed = self.originalSpeed;
					}
					// Restore visibility
					enemyGraphics.alpha = 1;
					enemyGraphics.tint = 0xFFFFFF;
					// Show health bar again
					healthBarOutline.visible = true;
					healthBarBG.visible = true;
					healthBar.visible = true;
				}
			}
		}
		// Handle flying horde spawning
		if (self.type === 'flying_horde' && !self.hasSpawned && self.currentCellY >= 2) {
			self.hasSpawned = true;
			// Spawn 4-6 additional weak flying enemies
			var spawnCount = 4 + Math.floor(Math.random() * 3);
			for (var i = 0; i < spawnCount; i++) {
				var newEnemy = new Enemy('flying');
				newEnemy.maxHealth = 15; // Very weak
				newEnemy.health = newEnemy.maxHealth;
				newEnemy.speed = self.speed * (0.8 + Math.random() * 0.4); // Varied speed
				// Position around the spawner
				var angle = Math.PI * 2 / spawnCount * i + Math.random() * 0.5;
				var distance = 50 + Math.random() * 30;
				newEnemy.cellX = self.cellX;
				newEnemy.cellY = self.cellY;
				newEnemy.currentCellX = self.currentCellX + Math.cos(angle) * distance / CELL_SIZE;
				newEnemy.currentCellY = self.currentCellY + Math.sin(angle) * distance / CELL_SIZE;
				newEnemy.x = grid.x + newEnemy.currentCellX * CELL_SIZE;
				newEnemy.y = grid.y + newEnemy.currentCellY * CELL_SIZE;
				newEnemy.waveNumber = self.waveNumber;
				// Add to flying layer
				enemyLayerTop.addChild(newEnemy);
				if (newEnemy.shadow) {
					enemyLayerMiddle.addChild(newEnemy.shadow);
				}
				enemies.push(newEnemy);
			}
		}
		// Handle confusion effect
		if (self.isConfused && !self.isImmune) {
			self.confusionDuration--;
			if (self.confusionDuration <= 0) {
				self.isConfused = false;
				// Reset pathfinding when confusion ends
				self.currentTarget = undefined;
			}
		}
		// Handle charm effect
		if (self.isCharmed && !self.isImmune) {
			self.charmDuration--;
			if (self.charmDuration <= 0) {
				self.isCharmed = false;
				self.originalTeam = 'enemy';
				// Reset pathfinding when charm ends
				self.currentTarget = undefined;
			}
		}
		// Handle bleed effect
		if (self.isBleeding && !self.isImmune) {
			self.bleedDuration--;
			// Take 5 damage every second (60 ticks)
			if (self.bleedDuration % 60 === 0) {
				self.health -= oneHitKillCheat ? 999999 : self.bleedDamage;
				if (self.health <= 0) {
					self.health = 0;
				} else {
					self.healthBar.width = self.health / self.maxHealth * 70;
				}
				// Visual feedback
				LK.effects.flashObject(self, 0x8B0000, 100);
			}
			if (self.bleedDuration <= 0) {
				self.isBleeding = false;
			}
		}
		// Handle slow effect
		if (self.isImmune) {
			// Immune enemies cannot be slowed, clear any such effects
			self.slowed = false;
			self.slowEffect = false;
			// Reset speed to original if needed
			if (self.originalSpeed !== undefined) {
				self.speed = self.originalSpeed;
			}
		} else {
			// Handle slow effect
			if (self.slowed) {
				// Visual indication of slowed status
				if (!self.slowEffect) {
					self.slowEffect = true;
				}
				self.slowDuration--;
				if (self.slowDuration <= 0) {
					self.speed = self.originalSpeed;
					self.slowed = false;
					self.slowEffect = false;
					// Only reset tint if not poisoned
					if (!self.poisoned) {
						enemyGraphics.tint = 0xFFFFFF; // Reset tint
					}
				}
			}
		}
		// Set tint based on effect status
		if (self.isImmune) {
			enemyGraphics.tint = 0xFFFFFF;
		} else if (self.isCharmed) {
			enemyGraphics.tint = 0xFFB6C1; // Light pink for charmed
		} else if (self.isConfused) {
			enemyGraphics.tint = 0xFF1493; // Pink for confused
		} else if (self.isBleeding) {
			enemyGraphics.tint = 0x8B0000; // Dark red for bleeding
		} else if (self.slowed) {
			enemyGraphics.tint = 0x9900FF;
		} else {
			enemyGraphics.tint = 0xFFFFFF;
		}
		if (self.currentTarget) {
			var ox = self.currentTarget.x - self.currentCellX;
			var oy = self.currentTarget.y - self.currentCellY;
			if (ox !== 0 || oy !== 0) {
				var angle = Math.atan2(oy, ox);
				if (enemyGraphics.targetRotation === undefined) {
					enemyGraphics.targetRotation = angle;
					enemyGraphics.rotation = angle;
				} else {
					if (Math.abs(angle - enemyGraphics.targetRotation) > 0.05) {
						tween.stop(enemyGraphics, {
							rotation: true
						});
						// Calculate the shortest angle to rotate
						var currentRotation = enemyGraphics.rotation;
						var angleDiff = angle - currentRotation;
						// Normalize angle difference to -PI to PI range for shortest path
						while (angleDiff > Math.PI) {
							angleDiff -= Math.PI * 2;
						}
						while (angleDiff < -Math.PI) {
							angleDiff += Math.PI * 2;
						}
						enemyGraphics.targetRotation = angle;
						tween(enemyGraphics, {
							rotation: currentRotation + angleDiff
						}, {
							duration: 250,
							easing: tween.easeOut
						});
					}
				}
			}
		}
		healthBarOutline.y = healthBarBG.y = healthBar.y = -enemyGraphics.height / 2 - 10;
	};
	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;
			}
		}
		for (var a = 0; a < enemies.length; a++) {
			var enemy = enemies[a];
			// Skip enemies that haven't entered the viewable area yet
			if (enemy.currentCellY < 4) {
				continue;
			}
			// Skip flying enemies from path check as they can fly over obstacles
			if (enemy.isFlying) {
				continue;
			}
			var target = self.getCell(enemy.cellX, enemy.cellY);
			if (enemy.currentTarget) {
				if (enemy.currentTarget.pathId != pathId) {
					if (!target || target.pathId != pathId) {
						console.warn("Enemy blocked 1 ");
						return true;
					}
				}
			} else if (!target || target.pathId != pathId) {
				console.warn("Enemy blocked 2");
				return true;
			}
		}
		console.log("Speed", new Date().getTime() - before);
	};
	self.renderDebug = function () {
		for (var i = 0; i < gridWidth; i++) {
			for (var j = 0; j < gridHeight; j++) {
				var debugCell = self.cells[i][j].debugCell;
				if (debugCell) {
					debugCell.render(self.cells[i][j]);
				}
			}
		}
	};
	self.updateEnemy = function (enemy) {
		var cell = grid.getCell(enemy.cellX, enemy.cellY);
		if (cell.type == 3) {
			return true;
		}
		if (enemy.isFlying && enemy.shadow) {
			enemy.shadow.x = enemy.x + 20; // Match enemy x-position + offset
			enemy.shadow.y = enemy.y + 20; // Match enemy y-position + offset
			// Match shadow rotation with enemy rotation
			if (enemy.children[0] && enemy.shadow.children[0]) {
				enemy.shadow.children[0].rotation = enemy.children[0].rotation;
			}
		}
		// Check if the enemy has reached the entry area (y position is at least 5)
		var hasReachedEntryArea = enemy.currentCellY >= 4;
		// If enemy hasn't reached the entry area yet, just move down vertically
		if (!hasReachedEntryArea) {
			// Move directly downward
			enemy.currentCellY += enemy.speed;
			// Rotate enemy graphic to face downward (PI/2 radians = 90 degrees)
			var angle = Math.PI / 2;
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update enemy's position
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// If enemy has now reached the entry area, update cell coordinates
			if (enemy.currentCellY >= 4) {
				enemy.cellX = Math.round(enemy.currentCellX);
				enemy.cellY = Math.round(enemy.currentCellY);
			}
			return false;
		}
		// After reaching entry area, handle flying enemies differently
		if (enemy.isFlying) {
			// Flying enemies head straight to the closest goal
			if (!enemy.flyingTarget) {
				// Set flying target to the closest goal
				enemy.flyingTarget = self.goals[0];
				// Find closest goal if there are multiple
				if (self.goals.length > 1) {
					var closestDist = Infinity;
					for (var i = 0; i < self.goals.length; i++) {
						var goal = self.goals[i];
						var dx = goal.x - enemy.cellX;
						var dy = goal.y - enemy.cellY;
						var dist = dx * dx + dy * dy;
						if (dist < closestDist) {
							closestDist = dist;
							enemy.flyingTarget = goal;
						}
					}
				}
			}
			// Move directly toward the goal
			var ox = enemy.flyingTarget.x - enemy.currentCellX;
			var oy = enemy.flyingTarget.y - enemy.currentCellY;
			var dist = Math.sqrt(ox * ox + oy * oy);
			if (dist < enemy.speed) {
				// Reached the goal
				return true;
			}
			var angle = Math.atan2(oy, ox);
			// Rotate enemy graphic to match movement direction
			if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
				enemy.children[0].targetRotation = angle;
				enemy.children[0].rotation = angle;
			} else if (enemy.children[0]) {
				if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
					tween.stop(enemy.children[0], {
						rotation: true
					});
					// Calculate the shortest angle to rotate
					var currentRotation = enemy.children[0].rotation;
					var angleDiff = angle - currentRotation;
					// Normalize angle difference to -PI to PI range for shortest path
					while (angleDiff > Math.PI) {
						angleDiff -= Math.PI * 2;
					}
					while (angleDiff < -Math.PI) {
						angleDiff += Math.PI * 2;
					}
					// Set target rotation and animate to it
					enemy.children[0].targetRotation = angle;
					tween(enemy.children[0], {
						rotation: currentRotation + angleDiff
					}, {
						duration: 250,
						easing: tween.easeOut
					});
				}
			}
			// Update the cell position to track where the flying enemy is
			enemy.cellX = Math.round(enemy.currentCellX);
			enemy.cellY = Math.round(enemy.currentCellY);
			enemy.currentCellX += Math.cos(angle) * enemy.speed;
			enemy.currentCellY += Math.sin(angle) * enemy.speed;
			enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
			enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
			// Update shadow position if this is a flying enemy
			return false;
		}
		// Handle normal pathfinding enemies
		if (enemy.isCharmed) {
			// Charmed enemies attack other enemies
			var nearestEnemy = null;
			var nearestDist = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var otherEnemy = enemies[i];
				if (otherEnemy !== enemy && !otherEnemy.isCharmed) {
					var dx = otherEnemy.cellX - enemy.cellX;
					var dy = otherEnemy.cellY - enemy.cellY;
					var dist = dx * dx + dy * dy;
					if (dist < nearestDist) {
						nearestDist = dist;
						nearestEnemy = otherEnemy;
					}
				}
			}
			if (nearestEnemy) {
				// Move towards the nearest enemy
				enemy.currentTarget = {
					x: nearestEnemy.cellX,
					y: nearestEnemy.cellY
				};
				// Deal damage if close enough
				if (nearestDist < 2) {
					if (LK.ticks % 60 === 0) {
						// Attack once per second
						nearestEnemy.health -= oneHitKillCheat ? 999999 : 10;
						if (nearestEnemy.health <= 0) {
							nearestEnemy.health = 0;
						} else {
							nearestEnemy.healthBar.width = nearestEnemy.health / nearestEnemy.maxHealth * 70;
						}
						LK.effects.flashObject(nearestEnemy, 0xFFB6C1, 100);
					}
				}
			}
		} else if (enemy.isConfused) {
			// Confused enemies move towards the nearest tower
			var nearestTower = null;
			var nearestDist = Infinity;
			for (var i = 0; i < towers.length; i++) {
				var tower = towers[i];
				var dx = tower.gridX - enemy.cellX;
				var dy = tower.gridY - enemy.cellY;
				var dist = dx * dx + dy * dy;
				if (dist < nearestDist) {
					nearestDist = dist;
					nearestTower = tower;
				}
			}
			if (nearestTower) {
				// Set target to move towards the tower
				enemy.currentTarget = {
					x: nearestTower.gridX,
					y: nearestTower.gridY
				};
			}
		} else if (!enemy.currentTarget) {
			enemy.currentTarget = cell.targets[0];
		}
		if (enemy.currentTarget) {
			if (!enemy.isConfused && 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 LaserWall = Container.expand(function (tower1, tower2) {
	var self = Container.call(this);
	self.tower1 = tower1;
	self.tower2 = tower2;
	self.damage = 18; // Base damage per tick (increased by 2)
	self.level = 1;
	self.maxLevel = 6;
	// Create laser visual
	var laserGraphics = self.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	laserGraphics.tint = 0xFF0088;
	laserGraphics.alpha = 0.8;
	// Position between the two towers
	self.updatePosition = function () {
		self.x = Math.min(self.tower1.x, self.tower2.x);
		self.y = self.tower1.y;
		var distance = Math.abs(self.tower2.x - self.tower1.x);
		laserGraphics.width = distance;
		laserGraphics.height = CELL_SIZE * 0.5;
	};
	self.updatePosition();
	// Level indicators
	var levelIndicators = [];
	var maxDots = self.maxLevel;
	var dotSize = CELL_SIZE / 8;
	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 + 2;
		outlineCircle.height = dotSize + 2;
		outlineCircle.tint = 0x000000;
		var levelIndicator = dot.attachAsset('towerLevelIndicator', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		levelIndicator.width = dotSize;
		levelIndicator.height = dotSize;
		levelIndicator.tint = 0xCCCCCC;
		dot.y = -CELL_SIZE * 0.4;
		self.addChild(dot);
		levelIndicators.push(dot);
	}
	self.updateLevelIndicators = function () {
		var centerX = laserGraphics.width / 2;
		var spacing = laserGraphics.width / (maxDots + 1);
		for (var i = 0; i < maxDots; i++) {
			var dot = levelIndicators[i];
			dot.x = spacing * (i + 1);
			var levelIndicator = dot.children[1];
			if (i < self.level) {
				levelIndicator.tint = 0xFFFFFF;
			} else {
				levelIndicator.tint = 0xFF0088;
			}
		}
	};
	self.updateLevelIndicators();
	self.upgrade = function () {
		if (self.level < self.maxLevel) {
			var upgradeCost = Math.floor(40 * Math.pow(2, self.level - 1));
			if (self.level === self.maxLevel - 1) {
				upgradeCost = Math.floor(upgradeCost * 3.5 / 2);
			}
			if (gold >= upgradeCost) {
				setGold(gold - upgradeCost);
				self.level++;
				self.damage = 18 + self.level * 24; // Increased base by 2 and maintain scaling
				// Unlock special ability at level 3
				if (self.level === 3) {
					self.hasSpecialAbility = true;
					var notification = game.addChild(new Notification("Laser Wall: Sky Piercer unlocked!"));
					notification.x = 2048 / 2;
					notification.y = grid.height - 100;
				}
				self.updateLevelIndicators();
				// Visual feedback
				tween(laserGraphics, {
					scaleY: 1.5,
					alpha: 1
				}, {
					duration: 200,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						tween(laserGraphics, {
							scaleY: 1,
							alpha: 0.8
						}, {
							duration: 200,
							easing: tween.easeIn
						});
					}
				});
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough gold to upgrade laser wall!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.getTotalValue = function () {
		var totalInvestment = 0;
		for (var i = 1; i < self.level; i++) {
			totalInvestment += Math.floor(40 * Math.pow(2, i - 1));
		}
		return totalInvestment;
	};
	self.update = function () {
		// Check for enemies passing through the laser
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			// Skip flying enemies unless laser wall has special ability
			if (enemy.isFlying && !self.hasSpecialAbility) {
				continue;
			}
			// Skip hidden moles unless laser wall has special ability
			if (enemy.isHidden && !self.hasSpecialAbility) {
				continue;
			}
			// Check if enemy is in the same row as the laser
			if (Math.abs(enemy.y - self.y) < CELL_SIZE / 2) {
				// Check if enemy is within the laser's horizontal range
				if (enemy.x >= self.x && enemy.x <= self.x + laserGraphics.width) {
					// Deal damage every 30 ticks (0.5 seconds)
					if (LK.ticks % 30 === 0) {
						enemy.health -= oneHitKillCheat ? 999999 : self.damage;
						if (enemy.health <= 0) {
							enemy.health = 0;
						} else {
							enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
						}
						// Visual effect
						LK.effects.flashObject(enemy, 0xFF0088, 100);
						// Play laser sound occasionally
						if (LK.ticks % 120 === 0) {
							LK.getSound('laser_beam').play();
						}
					}
				}
			}
		}
		// Pulse effect
		laserGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.1) * 0.2;
	};
	self.down = function (x, y, obj) {
		// Show upgrade menu for laser wall
		var existingMenus = game.children.filter(function (child) {
			return child instanceof UpgradeMenu;
		});
		for (var i = 0; i < existingMenus.length; i++) {
			existingMenus[i].destroy();
		}
		selectedTower = self;
		var upgradeMenu = new LaserWallUpgradeMenu(self);
		game.addChild(upgradeMenu);
		upgradeMenu.x = 2048 / 2;
		tween(upgradeMenu, {
			y: 2732 - 275
		}, {
			duration: 200,
			easing: tween.backOut
		});
	};
	return self;
});
var LaserWallUpgradeMenu = Container.expand(function (laserWall) {
	var self = Container.call(this);
	self.laserWall = laserWall;
	self.y = 2732 + 275;
	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 titleText = new Text2('Laser Wall', {
		size: 80,
		fill: 0xFFFFFF,
		weight: 800
	});
	titleText.anchor.set(0, 0);
	titleText.x = -840;
	titleText.y = -160;
	self.addChild(titleText);
	var statsText = new Text2('Level: ' + self.laserWall.level + '/' + self.laserWall.maxLevel + '\nDamage: ' + self.laserWall.damage + '/0.5s', {
		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);
	// Upgrade button
	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.laserWall.level >= self.laserWall.maxLevel;
	var upgradeCost = 0;
	if (!isMaxLevel) {
		upgradeCost = Math.floor(40 * Math.pow(2, self.laserWall.level - 1));
		if (self.laserWall.level === self.laserWall.maxLevel - 1) {
			upgradeCost = Math.floor(upgradeCost * 3.5 / 2);
		}
	}
	buttonBackground.tint = isMaxLevel ? 0x888888 : gold >= upgradeCost ? 0x00AA00 : 0x888888;
	var buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	// Sell button
	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 sellValue = getTowerSellValue(self.laserWall.getTotalValue());
	var sellButtonText = new Text2('Remove Wall: +' + sellValue + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	sellButtonText.anchor.set(0.5, 0.5);
	sellButton.addChild(sellButtonText);
	upgradeButton.y = -85;
	sellButton.y = 85;
	// Close button
	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 () {
		if (self.laserWall.level >= self.laserWall.maxLevel) {
			var notification = game.addChild(new Notification("Laser wall is already at max level!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
			return;
		}
		if (self.laserWall.upgrade()) {
			statsText.setText('Level: ' + self.laserWall.level + '/' + self.laserWall.maxLevel + '\nDamage: ' + self.laserWall.damage + '/0.5s');
			if (self.laserWall.level >= self.laserWall.maxLevel) {
				buttonBackground.tint = 0x888888;
				buttonText.setText('Max Level');
			} else {
				var newCost = Math.floor(40 * Math.pow(2, self.laserWall.level - 1));
				if (self.laserWall.level === self.laserWall.maxLevel - 1) {
					newCost = Math.floor(newCost * 3.5 / 2);
				}
				buttonText.setText('Upgrade: ' + newCost + ' gold');
			}
			var newSellValue = getTowerSellValue(self.laserWall.getTotalValue());
			sellButtonText.setText('Remove Wall: +' + newSellValue + ' gold');
		}
	};
	sellButton.down = function () {
		var sellValue = getTowerSellValue(self.laserWall.getTotalValue());
		setGold(gold + sellValue);
		var notification = game.addChild(new Notification("Laser wall removed for " + sellValue + " gold!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		// Remove laser wall from game
		var wallIndex = laserWalls.indexOf(self.laserWall);
		if (wallIndex !== -1) {
			laserWalls.splice(wallIndex, 1);
		}
		game.removeChild(self.laserWall);
		self.destroy();
		selectedTower = null;
	};
	closeButton.down = function () {
		hideUpgradeMenu(self);
		selectedTower = null;
	};
	self.update = function () {
		if (self.laserWall.level >= self.laserWall.maxLevel) {
			return;
		}
		var currentUpgradeCost = Math.floor(40 * Math.pow(2, self.laserWall.level - 1));
		if (self.laserWall.level === self.laserWall.maxLevel - 1) {
			currentUpgradeCost = Math.floor(currentUpgradeCost * 3.5 / 2);
		}
		var canAfford = gold >= currentUpgradeCost;
		buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888;
	};
	return self;
});
var Manual = Container.expand(function () {
	var self = Container.call(this);
	// Manual background
	var background = self.attachAsset('manualBackground', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.alpha = 0.95;
	// Title
	var titleText = new Text2('TOWER DEFENSE MANUAL', {
		size: 80,
		fill: 0xFFFFFF,
		weight: 800
	});
	titleText.anchor.set(0.5, 0);
	titleText.x = 0;
	titleText.y = -1150;
	self.addChild(titleText);
	// Create scrollable content container
	var contentContainer = new Container();
	self.addChild(contentContainer);
	var yPos = -1000;
	var sectionSpacing = 350;
	// Scrolling variables
	var isDragging = false;
	var startY = 0;
	var startContentY = 0;
	var velocity = 0;
	var minY = -1000; // Top limit
	var maxY = 0; // Will be calculated based on content height
	var contentHeight = 0; // Will be calculated after adding all content
	// Tower Classes Section
	self.createSection = function (title, items, startY) {
		var sectionY = startY;
		// Section title
		var sectionTitle = new Text2(title, {
			size: 60,
			fill: 0xFFD700,
			weight: 800
		});
		sectionTitle.anchor.set(0.5, 0);
		sectionTitle.x = 0;
		sectionTitle.y = sectionY;
		contentContainer.addChild(sectionTitle);
		sectionY += 80;
		// Items
		for (var i = 0; i < items.length; i++) {
			var item = items[i];
			// Item background
			var itemBg = contentContainer.attachAsset('manualSection', {
				anchorX: 0.5,
				anchorY: 0
			});
			itemBg.x = 0;
			itemBg.y = sectionY;
			itemBg.height = 200;
			itemBg.alpha = 0.3;
			// Item name
			var itemName = new Text2(item.name, {
				size: 50,
				fill: 0xFFFFFF,
				weight: 800
			});
			itemName.anchor.set(0, 0);
			itemName.x = -800;
			itemName.y = sectionY + 20;
			contentContainer.addChild(itemName);
			// Item stats
			var itemStats = new Text2(item.stats, {
				size: 40,
				fill: 0xCCCCCC,
				weight: 400
			});
			itemStats.anchor.set(0, 0);
			itemStats.x = -800;
			itemStats.y = sectionY + 80;
			contentContainer.addChild(itemStats);
			sectionY += 220;
		}
		return sectionY + 50;
	};
	// Tower data
	var towerData = [{
		name: 'BOW (Default)',
		stats: 'Cost: 5 gold • Damage: 10 • Range: 3 tiles • Rate: 1/s\nBalanced tower good for early game'
	}, {
		name: 'CROSSBOW (Rapid)',
		stats: 'Cost: 15 gold • Damage: 5 • Range: 2.5 tiles • Rate: 2/s\nFast firing tower, good against swarms'
	}, {
		name: 'SNIPER',
		stats: 'Cost: 25 gold • Damage: 25 • Range: 5 tiles • Rate: 0.67/s\nLong range, high damage, slow firing'
	}, {
		name: 'CANNON (Splash)',
		stats: 'Cost: 35 gold • Damage: 15 • Range: 2 tiles • Rate: 0.8/s\nArea damage affects nearby enemies'
	}, {
		name: 'ICE WIZARD (Slow)',
		stats: 'Cost: 45 gold • Damage: 8 • Range: 3.5 tiles • Rate: 1.2/s\nSlows enemies, ineffective vs immune'
	}, {
		name: 'FARM',
		stats: 'Cost: 30 gold • Income: 10 gold/wave (+15 per level)\nGenerates passive income, no combat'
	}, {
		name: 'LASER BASE ALPHA',
		stats: 'Cost: 40 gold • Requires 2+ in same row\nCreates laser wall, blocks ground enemies'
	}, {
		name: 'INFERNO (Single)',
		stats: 'Cost: 50 gold • Damage: 5 DPS • Range: 4 tiles\nContinuous beam that drains health'
	}, {
		name: 'TRICKY WIZARD (Weakening)',
		stats: 'Cost: 40 gold • Damage: 10 • Range: 3 tiles\n50% chance to confuse enemies'
	}, {
		name: 'CHURCH (Income)',
		stats: 'Cost: 60 gold • Gives 1 life per wave\nNo combat ability, provides lives'
	}, {
		name: 'MORTAR (Area)',
		stats: 'Cost: 55 gold • Damage: 30 • Range: 7 tiles\nHigh range area damage, min range 2 tiles'
	}];
	// Enemy data
	var enemyData = [{
		name: 'NORMAL',
		stats: 'Health: 100 • Speed: Normal • Ground unit\nBasic enemy type'
	}, {
		name: 'FAST',
		stats: 'Health: 100 • Speed: 2x Normal • Ground unit\nQuick moving enemy'
	}, {
		name: 'IMMUNE',
		stats: 'Health: 80 • Speed: Normal • Ground unit\nImmune to slow effects'
	}, {
		name: 'FLYING',
		stats: 'Health: 80 • Speed: Normal • Flying unit\nFlies over obstacles, immune to laser walls'
	}, {
		name: 'SWARM',
		stats: 'Health: 50 • Speed: Normal • Ground unit\nWeaker but comes in large numbers'
	}, {
		name: 'FLYING HORDE',
		stats: 'Health: 25 • Speed: 1.5x Normal • Flying unit\nSpawner creates multiple weak flying enemies'
	}, {
		name: 'MOLE DIGGER',
		stats: 'Health: 120 • Speed: 0.8x/2x Normal • Ground unit\nHides underground periodically, untargetable while hidden'
	}, {
		name: 'BOSS',
		stats: 'Health: 20x Normal • Speed: 0.7x Normal\nAppears every 10th wave, massive health'
	}, {
		name: 'MIXED',
		stats: 'Spawns various random enemy types\nUnpredictable wave composition'
	}];
	// Create sections
	yPos = self.createSection('TOWER TYPES', towerData, yPos);
	yPos = self.createSection('ENEMY TYPES', enemyData, yPos);
	// Game mechanics section
	var mechanicsData = [{
		name: 'TOWER TARGETING',
		stats: 'First: Closest to exit • Last: Farthest from exit\nStrong: Highest HP • Crowd: Most nearby enemies'
	}, {
		name: 'WAVE PROGRESSION',
		stats: 'Waves 1-10: Fixed types to introduce mechanics\nAfter wave 10: Random types except boss waves'
	}, {
		name: 'DIFFICULTY SCALING',
		stats: 'Enemy health increases 12% per wave\nBoss waves every 10th wave'
	}, {
		name: 'TOWER UPGRADES',
		stats: 'Level 1-5: Exponential cost increase\nLevel 6: Extra powerful, costs 3.5x previous'
	}, {
		name: 'SELLING TOWERS',
		stats: 'Returns 60% of total investment\nStrategic for repositioning'
	}];
	yPos = self.createSection('GAME MECHANICS', mechanicsData, yPos);
	// Calculate content height and set scroll limits
	contentHeight = yPos + 1000; // yPos is negative, so we add back the initial offset
	maxY = Math.min(0, -contentHeight + 1800); // 1800 is approximate visible height
	// Close button
	var closeButton = new Container();
	self.addChild(closeButton);
	var closeBg = closeButton.attachAsset('manualButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	closeBg.width = 100;
	closeBg.height = 100;
	closeBg.tint = 0xFF4444;
	var closeText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	closeText.anchor.set(0.5, 0.5);
	closeButton.addChild(closeText);
	closeButton.x = 850;
	closeButton.y = -1150;
	closeButton.down = function () {
		self.destroy();
	};
	// Touch event handlers for scrolling
	self.down = function (x, y, obj) {
		// Don't start scrolling if clicking on the close button
		// Check if click is on close button using passed x,y coordinates
		var dx = x - closeButton.x;
		var dy = y - closeButton.y;
		if (Math.abs(dx) < 50 && Math.abs(dy) < 50) {
			return;
		}
		isDragging = true;
		startY = y;
		startContentY = contentContainer.y;
		velocity = 0;
	};
	self.move = function (x, y, obj) {
		if (isDragging) {
			var deltaY = y - startY;
			var newY = startContentY + deltaY;
			// Apply bounds
			newY = Math.max(maxY, Math.min(minY, newY));
			contentContainer.y = newY;
			// Calculate velocity for momentum
			velocity = deltaY * 0.5;
		}
	};
	self.up = function (x, y, obj) {
		isDragging = false;
	};
	// Update function for momentum scrolling
	self.update = function () {
		if (!isDragging && Math.abs(velocity) > 0.1) {
			// Apply momentum
			contentContainer.y += velocity;
			// Apply bounds
			contentContainer.y = Math.max(maxY, Math.min(minY, contentContainer.y));
			// Apply friction
			velocity *= 0.92;
			// Stop if velocity is too small
			if (Math.abs(velocity) < 0.1) {
				velocity = 0;
			}
		}
	};
	// Initial position (hidden)
	self.x = 2048 / 2; // Center horizontally
	self.y = 2732 + 1200;
	// Animate in
	tween(self, {
		y: 2732 / 2
	}, {
		duration: 300,
		easing: tween.backOut
	});
	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';
	// Use specific tower asset based on type
	var towerAssetId = 'tower_' + self.towerType;
	if (self.towerType === 'default') {
		towerAssetId = 'tower_default';
	}
	// Increase size of base for easier touch
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.3,
		scaleY: 1.3
	});
	// No need to tint anymore as we have specific assets
	var towerCost = getTowerCost(self.towerType);
	// Get display name for tower type
	var displayName = self.towerType;
	switch (self.towerType) {
		case 'default':
			displayName = 'Bow';
			break;
		case 'rapid':
			displayName = 'Crossbow';
			break;
		case 'splash':
			displayName = 'Cannon';
			break;
		case 'slow':
			displayName = 'Ice Wizard';
			break;
		case 'farm':
			displayName = 'Farm';
			break;
		case 'laser':
			displayName = 'Laser Base';
			break;
		case 'inferno':
			displayName = 'Inferno';
			break;
		case 'wizard':
			displayName = 'Tricky Wizard';
			break;
		case 'church':
			displayName = 'Church';
			break;
		case 'mortar':
			displayName = 'Mortar';
			break;
	}
	// Add shadow for tower type label
	var typeLabelShadow = new Text2(displayName, {
		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(displayName, {
		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;
	self.targetingMode = 'first'; // Options: 'first', 'last', 'strong', 'crowd'
	self.hasSpecialAbility = false; // Unlocked at max level
	self.specialAbilityActive = false;
	self.specialAbilityTimer = 0;
	self.rapidBurstCount = 0; // For archer rapid fire
	self.infernoTargets = []; // For inferno multi-target
	// 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 'sniper':
				// Sniper: base 5, +0.8 per level, infinite range with special ability
				if (self.hasSpecialAbility) {
					return 999 * CELL_SIZE; // Effectively infinite range
				}
				return (5 + (self.level - 1) * 0.8) * CELL_SIZE;
			case 'splash':
				// Splash: base 2, +0.2 per level (max ~4 blocks at max level)
				return (2 + (self.level - 1) * 0.2) * CELL_SIZE;
			case 'rapid':
				// Rapid: base 2.5, +0.5 per level
				return (2.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'slow':
				// Slow: base 3.5, +0.5 per level
				return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE;
			case 'farm':
				// Farm has no range
				return 0;
			case 'laser':
				// Laser has no shooting range
				return 0;
			case 'inferno':
				// Inferno: base 4, +0.3 per level
				return (4 + (self.level - 1) * 0.3) * CELL_SIZE;
			case 'wizard':
				// Wizard: base 3, +0.4 per level
				return (3 + (self.level - 1) * 0.4) * CELL_SIZE;
			case 'church':
				// Church has no range
				return 0;
			case 'mortar':
				// Mortar: base 7, +0.5 per level (high range)
				return (7 + (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 'rapid':
			self.fireRate = 30;
			self.damage = 5;
			self.range = 2.5 * CELL_SIZE;
			self.bulletSpeed = 7;
			break;
		case 'sniper':
			self.fireRate = 90;
			self.damage = 25;
			self.range = 5 * CELL_SIZE;
			self.bulletSpeed = 25;
			break;
		case 'splash':
			self.fireRate = 75;
			self.damage = 15;
			self.range = 2 * CELL_SIZE;
			self.bulletSpeed = 4;
			break;
		case 'slow':
			self.fireRate = 50;
			self.damage = 8;
			self.range = 3.5 * CELL_SIZE;
			self.bulletSpeed = 5;
			break;
		case 'farm':
			self.fireRate = 999999; // Farm doesn't shoot
			self.damage = 0;
			self.range = 0;
			self.bulletSpeed = 0;
			break;
		case 'laser':
			self.fireRate = 999999; // Laser doesn't shoot normally
			self.damage = 0;
			self.range = 0;
			self.bulletSpeed = 0;
			break;
		case 'inferno':
			self.fireRate = 999999; // Inferno uses continuous beam
			self.damage = 5; // Base DPS
			self.range = 4 * CELL_SIZE;
			self.bulletSpeed = 0;
			break;
		case 'wizard':
			self.fireRate = 120; // Slower fire rate
			self.damage = 10;
			self.range = 3 * CELL_SIZE;
			self.bulletSpeed = 6;
			break;
		case 'church':
			self.fireRate = 999999; // Church doesn't shoot
			self.damage = 0;
			self.range = 0;
			self.bulletSpeed = 0;
			break;
		case 'mortar':
			self.fireRate = 180; // Very slow fire rate
			self.damage = 30;
			self.range = 7 * CELL_SIZE;
			self.minRange = 2 * CELL_SIZE; // Can't hit close enemies
			self.bulletSpeed = 3;
			break;
	}
	// Use specific tower asset based on type
	var towerAssetId = 'tower_' + self.id;
	if (self.id === 'default') {
		towerAssetId = 'tower_default';
	}
	var baseGraphics = self.attachAsset(towerAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No need to tint anymore as we have specific assets
	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);
	// Use specific defense asset based on type
	var defenseAssetId = 'defense_' + self.id;
	if (self.id === 'default') {
		defenseAssetId = 'defense_default';
	}
	var gunGraphics = gunContainer.attachAsset(defenseAssetId, {
		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 'rapid':
						towerLevelIndicator.tint = 0x00AAFF;
						break;
					case 'sniper':
						towerLevelIndicator.tint = 0xFF5500;
						break;
					case 'splash':
						towerLevelIndicator.tint = 0x33CC00;
						break;
					case 'slow':
						towerLevelIndicator.tint = 0x9900FF;
						break;
					case 'farm':
						towerLevelIndicator.tint = 0xFFD700; // Gold color
						break;
					case 'laser':
						towerLevelIndicator.tint = 0xFF0088; // Pink color
						break;
					case 'inferno':
						towerLevelIndicator.tint = 0xFF4500; // Orange-red
						break;
					case 'wizard':
						towerLevelIndicator.tint = 0xFF1493; // Deep pink
						break;
					case 'church':
						towerLevelIndicator.tint = 0xFFD700; // Gold
						break;
					case 'mortar':
						towerLevelIndicator.tint = 0x8B4513; // Saddle brown
						break;
					default:
						towerLevelIndicator.tint = 0xAAAAAA;
				}
			}
		}
	};
	self.updateLevelIndicators();
	// Create inferno beam visual if this is an inferno tower
	if (self.id === 'inferno') {
		self.infernoBeam = self.attachAsset('infernoBeam', {
			anchorX: 0,
			anchorY: 0.5
		});
		self.infernoBeam.visible = false;
		self.infernoBeam.alpha = 0.8;
		self.infernoDamageTimer = 0;
	}
	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.getSpecialAbilityName = function () {
		switch (self.id) {
			case 'default':
				return 'Rapid Fire';
			case 'rapid':
				return 'Bleeding Shots';
			case 'sniper':
				return 'Infinite Range';
			case 'inferno':
				return 'Triple Beam';
			case 'splash':
				return 'Mega Blast';
			case 'laser':
				return 'Sky Piercer';
			case 'mortar':
				return 'Quad Shot';
			case 'slow':
				return 'Permafrost';
			case 'wizard':
				return 'Charm';
			case 'farm':
				return 'Gold Boost';
			case 'church':
				return 'Divine Intervention';
			default:
				return null;
		}
	};
	self.getSpecialAbilityCost = function () {
		// Special ability costs 3x the base tower cost
		return getTowerCost(self.id) * 3;
	};
	self.unlockSpecialAbility = function () {
		if (self.level >= 3 && !self.hasSpecialAbility) {
			var cost = self.getSpecialAbilityCost();
			if (gold >= cost) {
				setGold(gold - cost);
				self.hasSpecialAbility = true;
				// Show special ability unlocked notification
				var abilityName = self.getSpecialAbilityName();
				if (abilityName) {
					var notification = game.addChild(new Notification("Special Ability Unlocked: " + abilityName));
					notification.x = 2048 / 2;
					notification.y = grid.height - 100;
				}
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough gold for special ability!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	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++;
				LK.getSound('tower_upgrade').play();
				// Special ability is unlocked separately at level 3 (no longer automatic)
				// Special ability unlocking is now handled by separate purchase button
				// No need to update self.range here; getRange() is now the source of truth
				// Apply tower-specific upgrades based on type
				if (self.id === 'rapid') {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade (double the effect)
						self.fireRate = Math.max(4, 30 - self.level * 9); // double the effect
						self.damage = 5 + self.level * 10; // double the effect
						self.bulletSpeed = 7 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(15, 30 - self.level * 3); // Fast tower gets faster with upgrades
						self.damage = 5 + self.level * 3;
						self.bulletSpeed = 7 + self.level * 0.7;
					}
				} else if (self.id === 'inferno') {
					// Inferno tower damage scales differently (DPS)
					self.damage = 5 + self.level * 3;
				} else if (self.id === 'wizard') {
					if (self.level === self.maxLevel) {
						self.fireRate = Math.max(30, 120 - self.level * 30);
						self.damage = 10 + self.level * 15;
						self.bulletSpeed = 6 + self.level * 1.5;
					} else {
						self.fireRate = Math.max(60, 120 - self.level * 10);
						self.damage = 10 + self.level * 5;
						self.bulletSpeed = 6 + self.level * 0.5;
					}
				} else if (self.id === 'mortar') {
					if (self.level === self.maxLevel) {
						self.fireRate = Math.max(60, 180 - self.level * 40);
						self.damage = 30 + self.level * 25;
						self.bulletSpeed = 3 + self.level * 1.0;
					} else {
						self.fireRate = Math.max(120, 180 - self.level * 10);
						self.damage = 30 + self.level * 8;
						self.bulletSpeed = 3 + self.level * 0.3;
					}
				} else {
					if (self.level === self.maxLevel) {
						// Extra powerful last upgrade for all other towers (double the effect)
						self.fireRate = Math.max(5, 60 - self.level * 24); // double the effect
						self.damage = 10 + self.level * 20; // double the effect
						self.bulletSpeed = 5 + self.level * 2.4; // double the effect
					} else {
						self.fireRate = Math.max(20, 60 - self.level * 8);
						self.damage = 10 + self.level * 5;
						self.bulletSpeed = 5 + self.level * 0.5;
					}
				}
				self.refreshCellsInRange();
				self.updateLevelIndicators();
				if (self.level > 1) {
					var levelDot = levelIndicators[self.level - 1].children[1];
					tween(levelDot, {
						scaleX: 1.5,
						scaleY: 1.5
					}, {
						duration: 300,
						easing: tween.elasticOut,
						onFinish: function onFinish() {
							tween(levelDot, {
								scaleX: 1,
								scaleY: 1
							}, {
								duration: 200,
								easing: tween.easeOut
							});
						}
					});
				}
				return true;
			} else {
				var notification = game.addChild(new Notification("Not enough gold to upgrade!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 50;
				return false;
			}
		}
		return false;
	};
	self.findTarget = function () {
		var enemiesInRange = [];
		// First, collect all enemies in range
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			// Check if enemy is in range and not hidden underground
			if (distance <= self.getRange() && !enemy.isHidden) {
				// Mortar can't hit enemies that are too close
				if (self.id === 'mortar' && distance < self.minRange) {
					continue;
				}
				enemiesInRange.push({
					enemy: enemy,
					distance: distance,
					dx: dx,
					dy: dy
				});
			}
		}
		if (enemiesInRange.length === 0) {
			self.targetEnemy = null;
			return null;
		}
		var targetEnemy = null;
		switch (self.targetingMode) {
			case 'first':
				// Target enemy closest to the base (lowest path score or closest to goal for flying)
				var lowestScore = Infinity;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemyData = enemiesInRange[i];
					var enemy = enemyData.enemy;
					if (enemy.isFlying) {
						// For flying enemies, prioritize by distance to the goal
						if (enemy.flyingTarget) {
							var goalX = enemy.flyingTarget.x;
							var goalY = enemy.flyingTarget.y;
							var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY));
							// Use distance to goal as score
							if (distToGoal < lowestScore) {
								lowestScore = distToGoal;
								targetEnemy = enemy;
							}
						} else {
							// If no flying target yet (shouldn't happen), prioritize by distance to tower
							if (enemyData.distance < lowestScore) {
								lowestScore = enemyData.distance;
								targetEnemy = 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 < lowestScore) {
								lowestScore = cell.score;
								targetEnemy = enemy;
							}
						}
					}
				}
				break;
			case 'last':
				// Target enemy farthest from the base (highest path score)
				var highestScore = -Infinity;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemyData = enemiesInRange[i];
					var enemy = enemyData.enemy;
					if (enemy.isFlying) {
						// For flying enemies, prioritize by distance to the goal (inverse)
						if (enemy.flyingTarget) {
							var goalX = enemy.flyingTarget.x;
							var goalY = enemy.flyingTarget.y;
							var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY));
							// Use inverse distance to goal as score
							if (distToGoal > highestScore) {
								highestScore = distToGoal;
								targetEnemy = enemy;
							}
						}
					} else {
						// For ground enemies
						var cell = grid.getCell(enemy.cellX, enemy.cellY);
						if (cell && cell.pathId === pathId) {
							// Higher score means farther from exit
							if (cell.score > highestScore) {
								highestScore = cell.score;
								targetEnemy = enemy;
							}
						}
					}
				}
				break;
			case 'strong':
				// Target enemy with the most HP
				var mostHP = -1;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemy = enemiesInRange[i].enemy;
					if (enemy.health > mostHP) {
						mostHP = enemy.health;
						targetEnemy = enemy;
					}
				}
				break;
			case 'crowd':
				// Target enemy with the most other enemies nearby
				var maxCrowdScore = -1;
				for (var i = 0; i < enemiesInRange.length; i++) {
					var enemyData = enemiesInRange[i];
					var enemy = enemyData.enemy;
					var crowdScore = 0;
					// Count enemies within 2 cells of this enemy
					for (var j = 0; j < enemies.length; j++) {
						if (enemies[j] !== enemy) {
							var edx = enemies[j].x - enemy.x;
							var edy = enemies[j].y - enemy.y;
							var edist = Math.sqrt(edx * edx + edy * edy);
							if (edist <= CELL_SIZE * 2) {
								crowdScore++;
							}
						}
					}
					if (crowdScore > maxCrowdScore) {
						maxCrowdScore = crowdScore;
						targetEnemy = enemy;
					}
				}
				break;
		}
		// For inferno tower with special ability, find up to 3 targets
		if (self.id === 'inferno' && self.hasSpecialAbility && enemiesInRange.length > 0) {
			self.infernoTargets = [];
			// Sort enemies by distance
			enemiesInRange.sort(function (a, b) {
				return a.distance - b.distance;
			});
			// Get up to 3 targets
			for (var i = 0; i < Math.min(3, enemiesInRange.length); i++) {
				self.infernoTargets.push(enemiesInRange[i].enemy);
			}
			return self.infernoTargets[0]; // Return primary target
		}
		return targetEnemy;
	};
	self.update = function () {
		// Farm towers don't target or shoot
		if (self.id === 'farm') {
			return;
		}
		// Laser towers are handled separately
		if (self.id === 'laser') {
			return;
		}
		// Church towers don't shoot
		if (self.id === 'church') {
			return;
		}
		// Inferno tower uses continuous beam
		if (self.id === 'inferno') {
			self.targetEnemy = self.findTarget();
			if (self.targetEnemy) {
				// Show and position beam
				self.infernoBeam.visible = true;
				var dx = self.targetEnemy.x - self.x;
				var dy = self.targetEnemy.y - self.y;
				var angle = Math.atan2(dy, dx);
				var distance = Math.sqrt(dx * dx + dy * dy);
				self.infernoBeam.rotation = angle;
				self.infernoBeam.width = distance;
				gunContainer.rotation = angle;
				// Deal damage every 10 ticks
				self.infernoDamageTimer++;
				if (self.infernoDamageTimer >= 10) {
					self.infernoDamageTimer = 0;
					// Calculate damage based on level
					var damagePerTick = oneHitKillCheat ? 999999 : self.damage + self.level * 3;
					self.targetEnemy.health -= damagePerTick;
					if (self.targetEnemy.health <= 0) {
						self.targetEnemy.health = 0;
					} else {
						self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70;
					}
					// Visual effect
					LK.effects.flashObject(self.targetEnemy, 0xFF4500, 100);
					// Handle multi-target ability
					if (self.hasSpecialAbility && self.infernoTargets.length > 1) {
						// Damage additional targets (50% damage)
						for (var i = 1; i < self.infernoTargets.length; i++) {
							var additionalTarget = self.infernoTargets[i];
							if (additionalTarget && additionalTarget.parent && !additionalTarget.isHidden) {
								additionalTarget.health -= oneHitKillCheat ? 999999 : damagePerTick * 0.5;
								if (additionalTarget.health <= 0) {
									additionalTarget.health = 0;
								} else {
									additionalTarget.healthBar.width = additionalTarget.health / additionalTarget.maxHealth * 70;
								}
								LK.effects.flashObject(additionalTarget, 0xFF4500, 100);
							}
						}
					}
				}
			} else {
				self.infernoBeam.visible = false;
				self.infernoDamageTimer = 0;
				self.infernoTargets = [];
			}
			return;
		}
		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;
			// Handle rapid burst fire for archer
			if (self.rapidBurstCount > 0) {
				if (LK.ticks - self.lastFired >= 6) {
					// Very fast fire rate during burst
					self.fire();
					self.lastFired = LK.ticks;
					self.rapidBurstCount--;
					if (self.rapidBurstCount === 0) {
						self.specialAbilityActive = false;
					}
				}
			} else if (LK.ticks - self.lastFired >= self.fireRate) {
				self.fire();
				self.lastFired = LK.ticks;
			}
		}
	};
	self.down = function (x, y, obj) {
		var existingMenus = game.children.filter(function (child) {
			return child instanceof UpgradeMenu;
		});
		var hasOwnMenu = false;
		var rangeCircle = null;
		for (var i = 0; i < game.children.length; i++) {
			if (game.children[i].isTowerRange && game.children[i].tower === self) {
				rangeCircle = game.children[i];
				break;
			}
		}
		for (var i = 0; i < existingMenus.length; i++) {
			if (existingMenus[i].tower === self) {
				hasOwnMenu = true;
				break;
			}
		}
		if (hasOwnMenu) {
			for (var i = 0; i < existingMenus.length; i++) {
				if (existingMenus[i].tower === self) {
					hideUpgradeMenu(existingMenus[i]);
				}
			}
			if (rangeCircle) {
				game.removeChild(rangeCircle);
			}
			selectedTower = null;
			grid.renderDebug();
			return;
		}
		for (var i = 0; i < existingMenus.length; i++) {
			existingMenus[i].destroy();
		}
		for (var i = game.children.length - 1; i >= 0; i--) {
			if (game.children[i].isTowerRange) {
				game.removeChild(game.children[i]);
			}
		}
		selectedTower = self;
		var rangeIndicator = new Container();
		rangeIndicator.isTowerRange = true;
		rangeIndicator.tower = self;
		game.addChild(rangeIndicator);
		rangeIndicator.x = self.x;
		rangeIndicator.y = self.y;
		var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		rangeGraphics.width = rangeGraphics.height = self.getRange() * 2;
		rangeGraphics.alpha = 0.3;
		var upgradeMenu = new UpgradeMenu(self);
		game.addChild(upgradeMenu);
		upgradeMenu.x = 2048 / 2;
		tween(upgradeMenu, {
			y: 2732 - 325
		}, {
			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 () {
		// Handle archer rapid fire ability
		if (self.id === 'default' && self.hasSpecialAbility && Math.random() < 0.25) {
			self.rapidBurstCount = 5;
			self.specialAbilityActive = true;
		}
		// Handle mortar quad shot ability
		if (self.id === 'mortar' && self.hasSpecialAbility) {
			// Fire 4 projectiles at once
			if (self.targetEnemy) {
				for (var i = 0; i < 4; i++) {
					var offsetAngle = (i - 1.5) * 0.3; // Spread the shots
					var targetX = self.targetEnemy.x + Math.cos(offsetAngle) * 50;
					var targetY = self.targetEnemy.y + Math.sin(offsetAngle) * 50;
					var bulletX = self.x + Math.cos(gunContainer.rotation + offsetAngle) * 40;
					var bulletY = self.y + Math.sin(gunContainer.rotation + offsetAngle) * 40;
					var bullet = new Bullet(bulletX, bulletY, null, self.damage, self.bulletSpeed);
					bullet.type = 'mortar';
					bullet.targetX = targetX;
					bullet.targetY = targetY;
					// Replace bullet graphics
					bullet.removeChild(bullet.children[0]);
					var mortarGraphics = bullet.attachAsset('bullet_mortar', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					game.addChild(bullet);
					bullets.push(bullet);
				}
			}
			return;
		}
		// Handle cannon mega blast ability
		if (self.id === 'splash' && self.hasSpecialAbility && self.specialAbilityTimer <= 0) {
			self.fireRate = 25; // Triple fire rate
			self.specialAbilityTimer = 180; // 3 second duration
		}
		if (self.id === 'splash' && self.specialAbilityTimer > 0) {
			self.specialAbilityTimer--;
			if (self.specialAbilityTimer === 0) {
				self.fireRate = 75; // Reset to normal
			}
		}
		if (self.targetEnemy) {
			var potentialDamage = 0;
			for (var i = 0; i < self.targetEnemy.bulletsTargetingThis.length; i++) {
				potentialDamage += self.targetEnemy.bulletsTargetingThis[i].damage;
			}
			if (self.targetEnemy.health > potentialDamage) {
				var bulletX = self.x + Math.cos(gunContainer.rotation) * 40;
				var bulletY = self.y + Math.sin(gunContainer.rotation) * 40;
				var bulletDamage = oneHitKillCheat ? 999999 : self.damage;
				var bullet = new Bullet(bulletX, bulletY, self.targetEnemy, bulletDamage, self.bulletSpeed);
				// Set bullet type based on tower type
				bullet.type = self.id;
				// For slow tower, pass level for scaling slow effect
				if (self.id === 'slow') {
					bullet.sourceTowerLevel = self.level;
					bullet.hasPermafrostAbility = self.hasSpecialAbility;
				} else if (self.id === 'rapid') {
					bullet.hasBleedAbility = self.hasSpecialAbility;
				} else if (self.id === 'wizard') {
					bullet.hasCharmAbility = self.hasSpecialAbility;
				}
				// For mortar, store target position instead of enemy
				if (self.id === 'mortar') {
					bullet.targetX = self.targetEnemy.x;
					bullet.targetY = self.targetEnemy.y;
					bullet.targetEnemy = null; // Mortar targets location, not enemy
				}
				// Replace bullet graphics with tower-specific asset
				var bulletAssetId = 'bullet';
				if (self.id !== 'default') {
					bulletAssetId = 'bullet_' + self.id;
				}
				// Remove the old generic bullet graphic
				bullet.removeChild(bullet.children[0]);
				// Attach the specific bullet asset
				var specificBulletGraphics = bullet.attachAsset(bulletAssetId, {
					anchorX: 0.5,
					anchorY: 0.5
				});
				game.addChild(bullet);
				bullets.push(bullet);
				self.targetEnemy.bulletsTargetingThis.push(bullet);
				// Play shooting sound based on tower type
				if (self.id === 'sniper') {
					LK.getSound('tower_shoot').play();
				} else if (self.id === 'splash' || self.id === 'mortar') {
					LK.getSound('explosion').play();
				} else if (self.id === 'slow') {
					LK.getSound('freeze').play();
				} else if (self.id === 'wizard') {
					LK.getSound('charm').play();
				} else {
					LK.getSound('tower_shoot').play();
				}
				// --- 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 'rapid':
				previewGraphics.tint = 0x00AAFF;
				break;
			case 'sniper':
				previewGraphics.tint = 0xFF5500;
				break;
			case 'splash':
				previewGraphics.tint = 0x33CC00;
				break;
			case 'slow':
				previewGraphics.tint = 0x9900FF;
				break;
			case 'farm':
				previewGraphics.tint = 0xFFD700; // Gold color
				break;
			case 'laser':
				previewGraphics.tint = 0xFF0088; // Pink color
				break;
			case 'inferno':
				previewGraphics.tint = 0xFF4500; // Orange-red
				break;
			case 'wizard':
				previewGraphics.tint = 0xFF1493; // Deep pink
				break;
			case 'church':
				previewGraphics.tint = 0xFFD700; // Gold
				break;
			case 'mortar':
				previewGraphics.tint = 0x8B4513; // Saddle brown
				break;
			default:
				previewGraphics.tint = 0xAAAAAA;
		}
		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 + 325;
	var menuBackground = self.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	menuBackground.width = 2048;
	menuBackground.height = 700;
	menuBackground.tint = 0x444444;
	menuBackground.alpha = 0.9;
	// Get display name for tower type
	var displayName = self.tower.id;
	switch (self.tower.id) {
		case 'default':
			displayName = 'Bow';
			break;
		case 'rapid':
			displayName = 'Crossbow';
			break;
		case 'splash':
			displayName = 'Cannon';
			break;
		case 'slow':
			displayName = 'Ice Wizard';
			break;
		case 'farm':
			displayName = 'Farm';
			break;
		case 'laser':
			displayName = 'Laser Base Alpha';
			break;
		case 'inferno':
			displayName = 'Inferno';
			break;
		case 'wizard':
			displayName = 'Tricky Wizard';
			break;
		case 'church':
			displayName = 'Church';
			break;
		case 'mortar':
			displayName = 'Mortar';
			break;
	}
	var towerTypeText = new Text2(displayName + ' 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(self.tower.id === 'inferno' ? 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + (self.tower.damage + self.tower.level * 3) + ' DPS\nRange: ' + (self.tower.getRange() / CELL_SIZE).toFixed(1) + ' tiles' : self.tower.id === 'church' ? 'Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nLives per wave: ' + self.tower.level + '\nNo combat ability' : '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 buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' gold', {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	upgradeButton.addChild(buttonText);
	// Special ability button
	var specialButton = new Container();
	buttonsContainer.addChild(specialButton);
	var specialBackground = specialButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	specialBackground.width = 500;
	specialBackground.height = 150;
	var hasAbility = self.tower.hasSpecialAbility;
	var abilityName = self.tower.getSpecialAbilityName();
	var canUnlock = self.tower.level >= 3 && !hasAbility;
	var abilityCost = canUnlock ? self.tower.getSpecialAbilityCost() : 0;
	var lockText = self.tower.level < 3 ? 'Locked (Lv 3)' : canUnlock ? 'Buy: ' + abilityCost + ' gold' : 'Locked';
	specialBackground.tint = hasAbility ? 0x9400D3 : canUnlock ? gold >= abilityCost ? 0x00AA00 : 0x888888 : 0x444444;
	var specialText = new Text2(hasAbility ? abilityName : lockText, {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	specialText.anchor.set(0.5, 0.5);
	specialButton.addChild(specialText);
	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);
	// Targeting mode button
	var targetingButton = new Container();
	buttonsContainer.addChild(targetingButton);
	var targetingBackground = targetingButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	targetingBackground.width = 500;
	targetingBackground.height = 150;
	targetingBackground.tint = 0x0088FF;
	var targetingModeNames = {
		'first': 'First',
		'last': 'Last',
		'strong': 'Strong',
		'crowd': 'Crowd'
	};
	var targetingText = new Text2('Target: ' + targetingModeNames[self.tower.targetingMode], {
		size: 60,
		fill: 0xFFFFFF,
		weight: 800
	});
	targetingText.anchor.set(0.5, 0.5);
	targetingButton.addChild(targetingText);
	upgradeButton.y = -210;
	specialButton.y = -70;
	targetingButton.y = 70;
	sellButton.y = 210;
	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) {
		LK.getSound('button_click').play();
		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));
			}
			if (self.tower.id === 'inferno') {
				statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + (self.tower.damage + self.tower.level * 3) + ' DPS\nRange: ' + (self.tower.getRange() / CELL_SIZE).toFixed(1) + ' tiles');
			} else if (self.tower.id === 'church') {
				statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nLives per wave: ' + self.tower.level + '\nNo combat ability');
			} else {
				statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s');
			}
			// Update special ability button when upgrading
			if (self.tower.hasSpecialAbility && !hasAbility) {
				specialBackground.tint = 0x9400D3;
				specialText.setText(self.tower.getSpecialAbilityName());
			}
			buttonText.setText('Upgrade: ' + 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
					});
				}
			});
		}
	};
	specialButton.down = function () {
		if (self.tower.hasSpecialAbility) {
			var notification = game.addChild(new Notification("Special Ability: " + self.tower.getSpecialAbilityName()));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
		} else if (self.tower.level >= 3) {
			// Try to purchase special ability
			if (self.tower.unlockSpecialAbility()) {
				// Update button appearance after successful purchase
				specialBackground.tint = 0x9400D3;
				specialText.setText(self.tower.getSpecialAbilityName());
			}
		} else {
			var notification = game.addChild(new Notification("Reach level 3 to unlock special ability!"));
			notification.x = 2048 / 2;
			notification.y = grid.height - 50;
		}
	};
	targetingButton.down = function () {
		// Cycle through targeting modes
		var modes = ['first', 'last', 'strong', 'crowd'];
		var currentIndex = modes.indexOf(self.tower.targetingMode);
		var nextIndex = (currentIndex + 1) % modes.length;
		self.tower.targetingMode = modes[nextIndex];
		var targetingModeNames = {
			'first': 'First',
			'last': 'Last',
			'strong': 'Strong',
			'crowd': 'Crowd'
		};
		targetingText.setText('Target: ' + targetingModeNames[self.tower.targetingMode]);
		// Visual feedback
		tween(targetingButton, {
			scaleX: 1.1,
			scaleY: 1.1
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(targetingButton, {
					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();
		// Update laser walls if we removed a laser tower
		if (self.tower.id === 'laser') {
			updateLaserWalls();
		}
		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;
			}
		} else {
			// 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 newText = 'Upgrade: ' + currentUpgradeCost + ' gold';
			if (buttonText.text !== newText) {
				buttonText.setText(newText);
			}
		}
		// Update special ability button
		if (!self.tower.hasSpecialAbility && self.tower.level >= 3) {
			var abilityCost = self.tower.getSpecialAbilityCost();
			var canAffordAbility = gold >= abilityCost;
			specialBackground.tint = canAffordAbility ? 0x00AA00 : 0x888888;
			var newSpecialText = 'Buy: ' + abilityCost + ' gold';
			if (specialText.text !== newSpecialText) {
				specialText.setText(newSpecialText);
			}
		}
	};
	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;
			LK.getSound('wave_start').play();
		}
	};
	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 = "Normal";
			enemyType = "normal";
			enemyCount = 10;
		} else if (i === 1) {
			block.tint = 0x00AAFF;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if (i === 2) {
			block.tint = 0xAA0000;
			waveType = "Immune";
			enemyType = "immune";
			enemyCount = 10;
		} else if (i === 3) {
			block.tint = 0xFFFF00;
			waveType = "Flying";
			enemyType = "flying";
			enemyCount = 10;
		} else if (i === 4) {
			block.tint = 0xFF00FF;
			waveType = "Swarm";
			enemyType = "swarm";
			enemyCount = 30;
		} else if (i === 5) {
			block.tint = 0x00FFFF;
			waveType = "Flying Horde";
			enemyType = "flying_horde";
			enemyCount = 3; // Few spawners that create many
		} else if (i === 6) {
			block.tint = 0x8B4513;
			waveType = "Mole Digger";
			enemyType = "mole";
			enemyCount = 8;
		} else if (i === 7) {
			block.tint = 0xFFFFFF;
			waveType = "Mixed";
			enemyType = "mixed";
			enemyCount = 12;
		} else if (isBossWave) {
			// Boss waves: cycle through all boss types, last boss is always flying
			var bossTypes = ['normal', 'fast', 'immune', 'flying'];
			var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
			if (i === totalWaves - 1) {
				// Last boss is always flying
				enemyType = 'flying';
				waveType = "Boss Flying";
				block.tint = 0xFFFF00;
			} else {
				enemyType = bossTypes[bossTypeIndex % bossTypes.length];
				switch (enemyType) {
					case 'normal':
						block.tint = 0xAAAAAA;
						waveType = "Boss Normal";
						break;
					case 'fast':
						block.tint = 0x00AAFF;
						waveType = "Boss Fast";
						break;
					case 'immune':
						block.tint = 0xAA0000;
						waveType = "Boss Immune";
						break;
					case 'flying':
						block.tint = 0xFFFF00;
						waveType = "Boss Flying";
						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;
				default:
					block.tint = 0xFF0000;
					break;
			}
		} else if (i + 1 > 10) {
			// After wave 10, all non-boss waves are completely random
			var randomWaveTypes = [{
				type: 'normal',
				name: 'Normal',
				tint: 0xAAAAAA,
				count: 10
			}, {
				type: 'fast',
				name: 'Fast',
				tint: 0x00AAFF,
				count: 10
			}, {
				type: 'immune',
				name: 'Immune',
				tint: 0xAA0000,
				count: 10
			}, {
				type: 'flying',
				name: 'Flying',
				tint: 0xFFFF00,
				count: 10
			}, {
				type: 'swarm',
				name: 'Swarm',
				tint: 0xFF00FF,
				count: 30
			}, {
				type: 'flying_horde',
				name: 'Flying Horde',
				tint: 0x00FFFF,
				count: 3
			}, {
				type: 'mole',
				name: 'Mole Digger',
				tint: 0x8B4513,
				count: 8
			}, {
				type: 'mixed',
				name: 'Mixed',
				tint: 0xFFFFFF,
				count: 12
			}];
			var randomChoice = randomWaveTypes[Math.floor(Math.random() * randomWaveTypes.length)];
			enemyType = randomChoice.type;
			waveType = randomChoice.name;
			block.tint = randomChoice.tint;
			enemyCount = randomChoice.count;
		} else if ((i + 1) % 5 === 0) {
			// Every 5th non-boss wave is fast
			block.tint = 0x00AAFF;
			waveType = "Fast";
			enemyType = "fast";
			enemyCount = 10;
		} else if ((i + 1) % 4 === 0) {
			// Every 4th non-boss wave is immune
			block.tint = 0xAA0000;
			waveType = "Immune";
			enemyType = "immune";
			enemyCount = 10;
		} else if ((i + 1) % 7 === 0) {
			// Every 7th non-boss wave is flying
			block.tint = 0xFFFF00;
			waveType = "Flying";
			enemyType = "flying";
			enemyCount = 10;
		} else if ((i + 1) % 3 === 0) {
			// Every 3rd non-boss wave is swarm
			block.tint = 0xFF00FF;
			waveType = "Swarm";
			enemyType = "swarm";
			enemyCount = 30;
		} else if ((i + 1) % 8 === 0) {
			// Every 8th non-boss wave is flying horde
			block.tint = 0x00FFFF;
			waveType = "Flying Horde";
			enemyType = "flying_horde";
			enemyCount = 3;
		} else if ((i + 1) % 9 === 0) {
			// Every 9th non-boss wave is mole digger
			block.tint = 0x8B4513;
			waveType = "Mole Digger";
			enemyType = "mole";
			enemyCount = 8;
		} else if ((i + 1) % 6 === 0) {
			// Every 6th non-boss wave is mixed
			block.tint = 0xFFFFFF;
			waveType = "Mixed";
			enemyType = "mixed";
			enemyCount = 12;
		} else {
			block.tint = 0xAAAAAA;
			waveType = "Normal";
			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 () {
		var progress = waveTimer / nextWaveTime;
		var moveAmount = (progress + currentWave) * blockWidth;
		for (var i = 0; i < self.waveMarkers.length; i++) {
			var marker = self.waveMarkers[i];
			marker.x = -moveAmount + i * blockWidth;
		}
		self.positionIndicator.x = 0;
		for (var i = 0; i < totalWaves + 1; i++) {
			var marker = self.waveMarkers[i];
			if (i === 0) {
				continue;
			}
			var block = marker.children[0];
			if (i - 1 < currentWave) {
				block.alpha = .5;
			}
		}
		self.handleWaveProgression = function () {
			if (!self.gameStarted) {
				return;
			}
			if (currentWave < totalWaves) {
				waveTimer++;
				if (waveTimer >= nextWaveTime) {
					waveTimer = 0;
					currentWave++;
					waveInProgress = true;
					waveSpawned = false;
					if (currentWave != 1) {
						var waveType = self.getWaveTypeName(currentWave);
						var enemyCount = self.getEnemyCount(currentWave);
						var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) incoming!"));
						notification.x = 2048 / 2;
						notification.y = grid.height - 150;
					}
				}
			}
		};
		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 + 325
	}, {
		duration: 150,
		easing: tween.easeIn,
		onFinish: function onFinish() {
			menu.destroy();
			isHidingUpgradeMenu = false;
		}
	});
}
var CELL_SIZE = 76;
var pathId = 1;
var maxScore = 0;
var enemies = [];
var towers = [];
var bullets = [];
var defenses = [];
var laserWalls = [];
var selectedTower = null;
var gold = 100;
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
// Cheat variables
var unlimitedMoneyCheat = false;
var oneHitKillCheat = false;
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;
function updateUI() {
	goldText.setText('Gold: ' + gold);
	livesText.setText('Lives: ' + lives);
	scoreText.setText('Score: ' + score);
}
function setGold(value) {
	if (unlimitedMoneyCheat) {
		gold = 999999;
	} else {
		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 'rapid':
			cost = 15;
			break;
		case 'sniper':
			cost = 25;
			break;
		case 'splash':
			cost = 35;
			break;
		case 'slow':
			cost = 45;
			break;
		case 'farm':
			cost = 30;
			break;
		case 'laser':
			cost = 40;
			break;
		case 'inferno':
			cost = 50;
			break;
		case 'wizard':
			cost = 40;
			break;
		case 'church':
			cost = 60;
			break;
		case 'mortar':
			cost = 55;
			break;
	}
	return cost;
}
function getTowerSellValue(totalValue) {
	return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
}
function updateLaserWalls() {
	// Remove all existing laser walls
	for (var i = laserWalls.length - 1; i >= 0; i--) {
		game.removeChild(laserWalls[i]);
	}
	laserWalls = [];
	// Group laser towers by row
	var laserTowersByRow = {};
	for (var i = 0; i < towers.length; i++) {
		if (towers[i].id === 'laser') {
			var row = towers[i].gridY;
			if (!laserTowersByRow[row]) {
				laserTowersByRow[row] = [];
			}
			laserTowersByRow[row].push(towers[i]);
		}
	}
	// Create laser walls for rows with 2 or more laser towers
	for (var row in laserTowersByRow) {
		var rowTowers = laserTowersByRow[row];
		if (rowTowers.length >= 2) {
			// Sort towers by x position
			rowTowers.sort(function (a, b) {
				return a.x - b.x;
			});
			// Create walls between adjacent towers
			for (var i = 0; i < rowTowers.length - 1; i++) {
				var wall = new LaserWall(rowTowers[i], rowTowers[i + 1]);
				game.addChild(wall);
				laserWalls.push(wall);
			}
		}
	}
}
function placeTower(gridX, gridY, towerType) {
	var towerCost = getTowerCost(towerType);
	if (gold >= towerCost) {
		var tower = new Tower(towerType || 'default');
		tower.placeOnGrid(gridX, gridY);
		towerLayer.addChild(tower);
		towers.push(tower);
		setGold(gold - towerCost);
		LK.getSound('place_tower').play();
		grid.pathFind();
		grid.renderDebug();
		// Update laser walls if we placed a laser tower
		if (towerType === 'laser') {
			updateLaserWalls();
		}
		return true;
	} else {
		var notification = game.addChild(new Notification("Not enough gold!"));
		notification.x = 2048 / 2;
		notification.y = grid.height - 50;
		LK.getSound('error').play();
		return false;
	}
}
game.down = function (x, y, obj) {
	var upgradeMenuVisible = game.children.some(function (child) {
		return child instanceof UpgradeMenu;
	});
	if (upgradeMenuVisible) {
		return;
	}
	// Check if clicking on a class button
	for (var i = 0; i < classButtons.length; i++) {
		var button = classButtons[i];
		if (x >= button.x - button.width / 2 && x <= button.x + button.width / 2 && y >= button.y - button.height / 2 && y <= button.y + button.height / 2) {
			// Class button was clicked, let it handle the event
			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);
// Tower classes configuration
var towerClasses = {
	'Single Damage': {
		towers: ['default', 'rapid', 'sniper', 'inferno'],
		color: 0x4488FF
	},
	'Area Damage': {
		towers: ['splash', 'laser', 'mortar'],
		color: 0xFF8844
	},
	'Weakening': {
		towers: ['slow', 'wizard'],
		color: 0x8844FF
	},
	'Income/Lives': {
		towers: ['farm', 'church'],
		color: 0x44FF88
	}
};
var sourceTowers = [];
var classButtons = [];
var currentClass = null;
var towerSelectionContainer = new Container();
game.addChild(towerSelectionContainer);
// Create class buttons
var classButtonWidth = 400;
var classButtonHeight = 80;
var classButtonSpacing = 20;
var classNames = Object.keys(towerClasses);
var totalClassWidth = classNames.length * classButtonWidth + (classNames.length - 1) * classButtonSpacing;
var classStartX = 2048 / 2 - totalClassWidth / 2 + classButtonWidth / 2;
var classButtonY = 2732 - CELL_SIZE * 3 - 180;
for (var i = 0; i < classNames.length; i++) {
	var className = classNames[i];
	var classData = towerClasses[className];
	var classButton = new Container();
	classButton.className = className;
	classButton.classData = classData;
	var buttonBg = classButton.attachAsset('notification', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	buttonBg.width = classButtonWidth;
	buttonBg.height = classButtonHeight;
	buttonBg.tint = classData.color;
	buttonBg.alpha = 0.7;
	var buttonText = new Text2(className, {
		size: 40,
		fill: 0xFFFFFF,
		weight: 800
	});
	buttonText.anchor.set(0.5, 0.5);
	classButton.addChild(buttonText);
	classButton.x = classStartX + i * (classButtonWidth + classButtonSpacing);
	classButton.y = classButtonY;
	classButton.down = function () {
		selectTowerClass(this.className);
	};
	towerSelectionContainer.addChild(classButton);
	classButtons.push(classButton);
}
// Function to select a tower class
function selectTowerClass(className) {
	// Update class button appearances
	for (var i = 0; i < classButtons.length; i++) {
		var button = classButtons[i];
		var bg = button.children[0];
		if (button.className === className) {
			bg.alpha = 1.0;
			bg.tint = button.classData.color;
		} else {
			bg.alpha = 0.3;
			bg.tint = 0x666666;
		}
	}
	// Clear existing source towers
	for (var i = 0; i < sourceTowers.length; i++) {
		towerLayer.removeChild(sourceTowers[i]);
	}
	sourceTowers = [];
	// Create towers for selected class
	currentClass = className;
	var classData = towerClasses[className];
	var towerTypes = classData.towers;
	var towerSpacing = 300;
	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);
	}
}
// Select first class by default
selectTowerClass(classNames[0]);
// Play theme music
LK.playMusic('game_theme');
// Create manual button
var manualButton = new Container();
var manualBg = manualButton.attachAsset('manualButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
manualBg.tint = 0x4CAF50;
var manualText = new Text2('?', {
	size: 70,
	fill: 0xFFFFFF,
	weight: 800
});
manualText.anchor.set(0.5, 0.5);
manualButton.addChild(manualText);
manualButton.x = 2048 - 80;
manualButton.y = 150;
manualButton.down = function () {
	var manual = new Manual();
	game.addChild(manual);
};
game.addChild(manualButton);
// Create cheat button
var cheatButton = new Container();
var cheatBg = cheatButton.attachAsset('manualButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
cheatBg.tint = 0xFF0000;
var cheatText = new Text2('C', {
	size: 70,
	fill: 0xFFFFFF,
	weight: 800
});
cheatText.anchor.set(0.5, 0.5);
cheatButton.addChild(cheatText);
cheatButton.x = 2048 - 200;
cheatButton.y = 150;
cheatButton.down = function () {
	var cheatMenu = new CheatMenu();
	game.addChild(cheatMenu);
};
game.addChild(cheatButton);
sourceTower = null;
enemiesToSpawn = 10;
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;
				LK.getSound('boss_spawn').play();
			}
			// Spawn the appropriate number of enemies
			for (var i = 0; i < enemyCount; i++) {
				var enemy;
				if (waveType === 'mixed') {
					// Mixed wave spawns random enemy types
					var mixedTypes = ['normal', 'fast', 'immune', 'flying', 'swarm', 'mole'];
					var randomType = mixedTypes[Math.floor(Math.random() * mixedTypes.length)];
					enemy = new Enemy(randomType);
				} else {
					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;
			// Give income from all farm towers
			var totalFarmIncome = 0;
			for (var i = 0; i < towers.length; i++) {
				if (towers[i].id === 'farm') {
					// Base income 10, +15 per level
					var farmIncome = 10 + (towers[i].level - 1) * 15;
					totalFarmIncome += farmIncome;
				}
			}
			if (totalFarmIncome > 0) {
				setGold(gold + totalFarmIncome);
				var notification = game.addChild(new Notification("Farm income: +" + totalFarmIncome + " gold!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 250;
			}
			// Give lives from all church towers
			var totalChurchLives = 0;
			var hasDivineIntervention = false;
			for (var i = 0; i < towers.length; i++) {
				if (towers[i].id === 'church') {
					// Church gives 1 life per wave at level 1, +1 per level upgrade
					totalChurchLives += towers[i].level; // Level 1 = 1 life, Level 2 = 2 lives, etc.
					// Check for divine intervention ability
					if (towers[i].hasSpecialAbility && Math.random() < 0.1) {
						// 10% chance
						hasDivineIntervention = true;
					}
				}
			}
			if (totalChurchLives > 0) {
				lives += totalChurchLives;
				updateUI();
				var notification = game.addChild(new Notification("Church blessing: +" + totalChurchLives + " lives!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 300;
			}
			// Handle divine intervention
			if (hasDivineIntervention && currentWave < totalWaves) {
				// Skip the next wave and give 350 gold
				currentWave++;
				waveTimer = 0;
				setGold(gold + 350);
				var notification = game.addChild(new Notification("Divine Intervention! Wave skipped +350 gold!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 350;
				LK.getSound('divine_intervention').play();
			}
			// Check for laser tower pairs and create/update laser walls
			updateLaserWalls();
		}
	}
	for (var a = enemies.length - 1; a >= 0; a--) {
		var enemy = enemies[a];
		if (enemy.health <= 0) {
			for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
				var bullet = enemy.bulletsTargetingThis[i];
				bullet.targetEnemy = null;
			}
			// Boss enemies give more gold and score
			var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
			// Check if killed by a tower in range of a farm with special ability
			var farmBonus = 0;
			for (var i = 0; i < towers.length; i++) {
				if (towers[i].id === 'farm' && towers[i].hasSpecialAbility) {
					// Check if any tower that could have killed this enemy is in range of the farm
					var farmX = towers[i].x;
					var farmY = towers[i].y;
					var farmRange = 3 * CELL_SIZE; // Farm boost range
					for (var j = 0; j < towers.length; j++) {
						if (towers[j].id !== 'farm') {
							var dx = towers[j].x - farmX;
							var dy = towers[j].y - farmY;
							var distance = Math.sqrt(dx * dx + dy * dy);
							if (distance <= farmRange) {
								// Check if this tower could have killed the enemy
								var towerToEnemyDx = enemy.x - towers[j].x;
								var towerToEnemyDy = enemy.y - towers[j].y;
								var towerToEnemyDist = Math.sqrt(towerToEnemyDx * towerToEnemyDx + towerToEnemyDy * towerToEnemyDy);
								if (towerToEnemyDist <= towers[j].getRange()) {
									farmBonus = Math.ceil(goldEarned * 0.25); // 25% bonus
									break;
								}
							}
						}
					}
					if (farmBonus > 0) break;
				}
			}
			var totalGold = goldEarned + farmBonus;
			var goldIndicator = new GoldIndicator(totalGold, enemy.x, enemy.y);
			game.addChild(goldIndicator);
			setGold(gold + totalGold);
			LK.getSound('enemy_death').play();
			LK.getSound('gold_collect').play();
			// Give more score for defeating a boss
			var scoreValue = enemy.isBoss ? 100 : 5;
			score += scoreValue;
			// Add a notification for boss defeat
			if (enemy.isBoss) {
				var notification = game.addChild(new Notification("Boss defeated! +" + goldEarned + " gold!"));
				notification.x = 2048 / 2;
				notification.y = grid.height - 150;
			}
			updateUI();
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			continue;
		}
		if (grid.updateEnemy(enemy)) {
			// Clean up shadow if it's a flying enemy
			if (enemy.isFlying && enemy.shadow) {
				enemyLayerMiddle.removeChild(enemy.shadow);
				enemy.shadow = null;
			}
			// Remove enemy from the appropriate layer
			if (enemy.isFlying) {
				enemyLayerTop.removeChild(enemy);
			} else {
				enemyLayerBottom.removeChild(enemy);
			}
			enemies.splice(a, 1);
			lives = Math.max(0, lives - 1);
			updateUI();
			if (lives <= 0) {
				LK.getSound('game_over').play();
				LK.stopMusic();
				LK.showGameOver();
			}
		}
	}
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (!bullets[i].parent) {
			if (bullets[i].targetEnemy) {
				var targetEnemy = bullets[i].targetEnemy;
				var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
				if (bulletIndex !== -1) {
					targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
				}
			}
			bullets.splice(i, 1);
		}
	}
	if (towerPreview.visible) {
		towerPreview.checkPlacement();
	}
	// Update all laser walls
	for (var i = 0; i < laserWalls.length; i++) {
		laserWalls[i].update();
	}
	if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) {
		LK.getSound('victory').play();
		LK.stopMusic();
		LK.showYouWin();
	}
};
 
 White circle with black outline. Blue background.. In-Game asset. 2d. High contrast. No shadows
 Wooden Guard Tower. In-Game asset. 2d. High contrast. No shadows
 Bow: make it face 90 degrees In-Game asset. 2d. High contrast. No shadows
 Wooden Tower base like the ones the Cannons in Clash of Clans have. In-Game asset. 2d. High contrast. No shadows. Topdown
 Cannon without wheels or base, just the cannon. In-Game asset. 2d. High contrast. No shadows. Topdown
 Crossbow rotated 90 degrees. In-Game asset. 2d. High contrast. No shadows
 Sniper rifle rotated 90 degrees. In-Game asset. 2d. High contrast. No shadows
 Ice tower. In-Game asset. 2d. High contrast. No shadows
 Ice staff. In-Game asset. 2d. High contrast. No shadows
 Windmill. In-Game asset. 2d. High contrast. No shadows
 Laser pointer without pointing a laser. In-Game asset. 2d. High contrast. No shadows. Topdown
 Laser projectile In-Game asset. 2d. High contrast. No shadows
 Orc holding a small axe. In-Game asset. 2d. High contrast. No shadows
 Orc with a big wooden shield full of spikes. In-Game asset. 2d. High contrast. No shadows
 Orc in a wooden helicopter. In-Game asset. 2d. High contrast. No shadows
 Spider. In-Game asset. 2d. High contrast. No shadows
 One minion from Clash Royale. In-Game asset. 2d. High contrast. No shadows
 Mole with a minerer's hat and a pickaxe. In-Game asset. 2d. High contrast. No shadows
 Wolf. In-Game asset. 2d. High contrast. No shadows
 Dark magma tower. In-Game asset. 2d. High contrast. No shadows. Topdown
 Add outlines
 Magician's staff. In-Game asset. 2d. High contrast. No shadows
 Mortar from Clash Royale without base, just the Mortar. In-Game asset. 2d. High contrast. No shadows. Topdown
 Tophat house. In-Game asset. 2d. High contrast. No shadows
 Church. In-Game asset. 2d. High contrast. No shadows
tower_upgrade
Sound effect
enemy_hit
Sound effect
enemy_death
Sound effect
wave_start
Sound effect
place_tower
Sound effect
boss_spawn
Sound effect
game_over
Sound effect
victory
Sound effect
laser_beam
Sound effect
game_theme
Music
explosion
Sound effect
freeze
Sound effect
divine_intervention
Sound effect
gold_collect
Sound effect