/**** 
* Classes
****/ 
var Bullet = Container.expand(function (damage) {
	var self = Container.call(this);
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.vx = 0;
	self.vy = 0;
	self.damage = damage || 10;
	self.lifetime = 60; // Bullets disappear after 1 second
	self.update = function () {
		// Move bullet
		self.x += self.vx;
		self.y += self.vy;
		// Decrease lifetime
		self.lifetime--;
		return self.lifetime <= 0;
	};
	return self;
});
var Explosion = Container.expand(function () {
	var self = Container.call(this);
	var explosionGraphics = self.attachAsset('explosion', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.lifetime = 15;
	self.scale.set(0.2);
	self.update = function () {
		self.lifetime--;
		self.scale.set(1 - self.lifetime / 20);
		self.alpha = self.lifetime / 15;
		return self.lifetime <= 0;
	};
	return self;
});
var ManualTarget = Container.expand(function () {
	var self = Container.call(this);
	var targetGraphics = self.attachAsset('manualTarget', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.lifetime = 15;
	self.alpha = 0.5;
	self.update = function () {
		self.lifetime--;
		self.alpha = self.lifetime / 15;
		self.rotation += 0.1;
		return self.lifetime <= 0;
	};
	return self;
});
var Tower = Container.expand(function () {
	var self = Container.call(this);
	// Tower base (doesn't rotate)
	var base = self.attachAsset('towerBase', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Tower turret (rotates to aim)
	var turret = new Container();
	var turretGraphics = turret.attachAsset('tower', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(turret);
	// Tower stats
	self.health = 100;
	self.maxHealth = 100;
	self.damage = 10;
	self.fireRate = 60; // frames between shots
	self.fireTimer = 0;
	self.range = 800;
	self.upgradeLevel = {
		damage: 1,
		fireRate: 1,
		range: 1,
		health: 1
	};
	// Health bar
	var healthBarContainer = new Container();
	var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 200
	});
	var healthBarFill = new Container();
	var healthBarGraphics = healthBarFill.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5,
		width: 200
	});
	healthBarContainer.addChild(healthBarFill);
	healthBarContainer.y = -150;
	self.addChild(healthBarContainer);
	// Methods
	self.update = function () {
		// Decrease fire timer
		if (self.fireTimer > 0) {
			self.fireTimer--;
		}
		// Update health bar
		healthBarFill.scale.x = self.health / self.maxHealth;
		// Find target if none currently
		var target = null;
		var closestDist = self.range;
		for (var i = 0; i < zombies.length; i++) {
			var zombie = zombies[i];
			var dx = zombie.x - self.x;
			var dy = zombie.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < closestDist) {
				closestDist = dist;
				target = zombie;
			}
		}
		// Aim at target
		if (target) {
			var angle = Math.atan2(target.y - self.y, target.x - self.x);
			turret.rotation = angle;
			// Fire if ready
			if (self.fireTimer <= 0) {
				var bullet = new Bullet(self.damage);
				bullet.x = self.x;
				bullet.y = self.y;
				bullet.rotation = angle;
				bullet.vx = Math.cos(angle) * 15;
				bullet.vy = Math.sin(angle) * 15;
				game.addChild(bullet);
				bullets.push(bullet);
				self.fireTimer = self.fireRate;
				LK.getSound('shoot').play();
			}
		}
	};
	self.manualShoot = function (x, y) {
		var angle = Math.atan2(y - self.y, x - self.x);
		turret.rotation = angle;
		var bullet = new Bullet(self.damage * 2); // Manual shots do double damage
		bullet.x = self.x;
		bullet.y = self.y;
		bullet.rotation = angle;
		bullet.vx = Math.cos(angle) * 15;
		bullet.vy = Math.sin(angle) * 15;
		game.addChild(bullet);
		bullets.push(bullet);
		LK.getSound('shoot').play();
	};
	self.takeDamage = function (amount) {
		self.health -= amount;
		// Flash the tower when hit
		LK.effects.flashObject(self, 0xff0000, 300);
		LK.getSound('towerHit').play();
		if (self.health <= 0) {
			return true; // Tower destroyed
		}
		return false;
	};
	self.upgradeDamage = function () {
		self.upgradeLevel.damage++;
		self.damage += 5;
		LK.getSound('upgrade').play();
	};
	self.upgradeFireRate = function () {
		self.upgradeLevel.fireRate++;
		self.fireRate = Math.max(10, self.fireRate - 10);
		LK.getSound('upgrade').play();
	};
	self.upgradeRange = function () {
		self.upgradeLevel.range++;
		self.range += 100;
		LK.getSound('upgrade').play();
	};
	self.upgradeHealth = function () {
		self.upgradeLevel.health++;
		var oldMaxHealth = self.maxHealth;
		self.maxHealth += 50;
		self.health += self.maxHealth - oldMaxHealth;
		LK.getSound('upgrade').play();
	};
	return self;
});
var UpgradePanel = Container.expand(function (tower) {
	var self = Container.call(this);
	// Panel background
	var panelBg = self.attachAsset('upgradePanel', {
		anchorX: 0,
		anchorY: 0
	});
	// Gold display
	var goldContainer = new Container();
	var goldIcon = goldContainer.attachAsset('goldIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var goldText = new Text2("0", {
		size: 40,
		fill: 0xffcc00
	});
	goldText.x = 60;
	goldText.anchor.set(0, 0.5);
	goldContainer.addChild(goldText);
	goldContainer.x = 100;
	goldContainer.y = 100;
	self.addChild(goldContainer);
	// Tower stats display
	var statsContainer = new Container();
	var damageText = new Text2("Damage: " + tower.damage, {
		size: 30,
		fill: 0xffffff
	});
	damageText.y = 0;
	statsContainer.addChild(damageText);
	var fireRateText = new Text2("Fire Rate: " + (60 / tower.fireRate).toFixed(1) + "/s", {
		size: 30,
		fill: 0xffffff
	});
	fireRateText.y = 40;
	statsContainer.addChild(fireRateText);
	var rangeText = new Text2("Range: " + tower.range, {
		size: 30,
		fill: 0xffffff
	});
	rangeText.y = 80;
	statsContainer.addChild(rangeText);
	var healthText = new Text2("Health: " + tower.health + "/" + tower.maxHealth, {
		size: 30,
		fill: 0xffffff
	});
	healthText.y = 120;
	statsContainer.addChild(healthText);
	statsContainer.x = 100;
	statsContainer.y = 200;
	self.addChild(statsContainer);
	// Upgrade buttons
	var upgradeButtons = [];
	var upgradeCosts = {
		damage: function damage() {
			return tower.upgradeLevel.damage * 50;
		},
		fireRate: function fireRate() {
			return tower.upgradeLevel.fireRate * 75;
		},
		range: function range() {
			return tower.upgradeLevel.range * 40;
		},
		health: function health() {
			return tower.upgradeLevel.health * 60;
		}
	};
	function createUpgradeButton(label, y, upgradeFunc, getCostFunc) {
		var button = new Container();
		var buttonBg = button.attachAsset('upgradeButton', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 30,
			fill: 0xffffff
		});
		buttonText.anchor.set(0, 0.5);
		buttonText.x = -buttonBg.width / 2 + 20;
		button.addChild(buttonText);
		var costText = new Text2("Cost: " + getCostFunc() + " Gold", {
			size: 25,
			fill: 0xffcc00
		});
		costText.anchor.set(1, 0.5);
		costText.x = buttonBg.width / 2 - 20;
		button.addChild(costText);
		button.x = 250;
		button.y = y;
		button.upgrade = upgradeFunc;
		button.getCost = getCostFunc;
		button.updateCost = function () {
			costText.setText("Cost: " + getCostFunc() + " Gold");
		};
		self.addChild(button);
		upgradeButtons.push(button);
		return button;
	}
	var damageButton = createUpgradeButton("Upgrade Damage", 400, function () {
		tower.upgradeDamage();
	}, upgradeCosts.damage);
	var fireRateButton = createUpgradeButton("Upgrade Fire Rate", 520, function () {
		tower.upgradeFireRate();
	}, upgradeCosts.fireRate);
	var rangeButton = createUpgradeButton("Upgrade Range", 640, function () {
		tower.upgradeRange();
	}, upgradeCosts.range);
	var healthButton = createUpgradeButton("Upgrade Health", 760, function () {
		tower.upgradeHealth();
	}, upgradeCosts.health);
	self.checkUpgradeClick = function (x, y, gold) {
		var localX = x - self.x;
		var localY = y - self.y;
		for (var i = 0; i < upgradeButtons.length; i++) {
			var button = upgradeButtons[i];
			var buttonX = button.x;
			var buttonY = button.y;
			var buttonWidth = 450;
			var buttonHeight = 100;
			if (localX >= buttonX - buttonWidth / 2 && localX <= buttonX + buttonWidth / 2 && localY >= buttonY - buttonHeight / 2 && localY <= buttonY + buttonHeight / 2) {
				var cost = button.getCost();
				if (gold >= cost) {
					button.upgrade();
					self.updateStats();
					return cost;
				} else {
					// Not enough gold
					button.alpha = 0.5;
					LK.setTimeout(function () {
						button.alpha = 1;
					}, 300);
					return 0;
				}
			}
		}
		return 0;
	};
	self.updateGold = function (gold) {
		goldText.setText(gold.toString());
	};
	self.updateStats = function () {
		damageText.setText("Damage: " + tower.damage);
		fireRateText.setText("Fire Rate: " + (60 / tower.fireRate).toFixed(1) + "/s");
		rangeText.setText("Range: " + tower.range);
		healthText.setText("Health: " + tower.health + "/" + tower.maxHealth);
		// Update costs
		for (var i = 0; i < upgradeButtons.length; i++) {
			upgradeButtons[i].updateCost();
		}
	};
	self.update = function () {
		self.updateStats();
	};
	return self;
});
var Zombie = Container.expand(function (waveNumber) {
	var self = Container.call(this);
	var zombieGraphics = self.attachAsset('zombie', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Stats scale with wave number
	var waveMultiplier = 1 + waveNumber * 0.2;
	self.health = 20 * waveMultiplier;
	self.maxHealth = self.health;
	self.speed = 2 + Math.random() * 1;
	self.damage = 5 * waveMultiplier;
	self.value = 10 + Math.floor(waveNumber * 5);
	// Chance to be a special zombie
	if (Math.random() < 0.2) {
		// Tank zombie - slower but more health
		self.health *= 3;
		self.maxHealth = self.health;
		self.speed *= 0.5;
		self.damage *= 2;
		self.value *= 3;
		zombieGraphics.tint = 0xff0000;
		zombieGraphics.width = 80;
		zombieGraphics.height = 80;
	} else if (Math.random() < 0.3) {
		// Fast zombie - faster but less health
		self.health *= 0.7;
		self.maxHealth = self.health;
		self.speed *= 2;
		self.value *= 2;
		zombieGraphics.tint = 0xffff00;
	}
	// Health bar
	var healthBarContainer = new Container();
	var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var healthBarFill = new Container();
	var healthBarGraphics = healthBarFill.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	healthBarContainer.addChild(healthBarFill);
	healthBarContainer.y = -50;
	self.addChild(healthBarContainer);
	self.update = function () {
		// Move towards tower
		var dx = CENTER_X - self.x;
		var dy = CENTER_Y - self.y;
		var dist = Math.sqrt(dx * dx + dy * dy);
		if (dist < 50) {
			// Attack tower
			if (tower.takeDamage(self.damage)) {
				return "gameover";
			}
			// Destroy self
			self.destroy();
			zombies.splice(zombies.indexOf(self), 1);
		} else {
			// Move towards tower
			self.x += dx / dist * self.speed;
			self.y += dy / dist * self.speed;
		}
		// Update health bar
		healthBarFill.scale.x = self.health / self.maxHealth;
		// Zombie looks where it's going
		self.rotation = Math.atan2(dy, dx);
		return "ok";
	};
	self.takeDamage = function (amount) {
		self.health -= amount;
		return self.health <= 0;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
/**** 
* Game Variables
****/ 
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CENTER_X = GAME_WIDTH / 2;
var CENTER_Y = GAME_HEIGHT / 2;
// Game state
var isGameActive = false;
var waitingForNextWave = false;
// Game objects
var tower;
var upgradePanel;
var waveIndicator;
var waveCompleteText;
var bonusText;
var waveTextInterval;
// Collections
var zombies = [];
var bullets = [];
var explosions = [];
var targets = [];
// Game stats
var wave = 0;
var zombiesInWave = 0;
var waveInterval = 60; // Frames between zombie spawns
var zombiesKilled = 0;
var gold = 100;
var manualCooldown = 0;
/**** 
* Game Functions
****/ 
function startGame() {
	// Create background
	var background = new Container();
	var backgroundGraphics = background.attachAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.x = CENTER_X;
	background.y = CENTER_Y;
	game.addChild(background);
	// Create tower
	tower = new Tower();
	tower.x = CENTER_X;
	tower.y = CENTER_Y;
	game.addChild(tower);
	// Create upgrade panel
	upgradePanel = new UpgradePanel(tower);
	upgradePanel.x = GAME_WIDTH - 500;
	upgradePanel.y = 0;
	game.addChild(upgradePanel);
	// Create wave indicator
	waveIndicator = new Container();
	var waveIndicatorBg = waveIndicator.attachAsset('waveIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var waveText = new Text2("WAVE 1", {
		size: 40,
		fill: 0xffffff
	});
	waveText.anchor.set(0.5);
	waveIndicator.addChild(waveText);
	waveIndicator.x = GAME_WIDTH - 250;
	waveIndicator.y = GAME_HEIGHT - 100;
	game.addChild(waveIndicator);
	// Start the game
	isGameActive = true;
	// Start first wave
	startWave();
	// Start background music
	LK.getSound('background').play();
	// Update gold display
	upgradePanel.updateGold(gold);
}
function startWave() {
	// Clean up any previous wave text elements
	if (waveCompleteText) {
		waveCompleteText.destroy();
		waveCompleteText = null;
	}
	if (bonusText) {
		bonusText.destroy();
		bonusText = null;
	}
	if (waveTextInterval) {
		LK.clearInterval(waveTextInterval);
		waveTextInterval = null;
	}
	waitingForNextWave = false;
	waveIndicator.children[1].setText("WAVE " + wave);
	zombiesInWave = 10 + wave * 5;
	waveInterval = Math.max(20, 60 - wave * 5); // Spawn zombies faster in later waves
	// Show wave start message
	var waveStartText = new Text2("WAVE " + wave + " STARTING!", {
		size: 80,
		fill: 0xff9900
	});
	waveStartText.x = CENTER_X;
	waveStartText.y = CENTER_Y;
	waveStartText.anchor.set(0.5);
	game.addChild(waveStartText);
	LK.getSound('waveStart').play();
	// Fade out text
	var fadeInterval = LK.setInterval(function () {
		waveStartText.alpha -= 0.05;
		if (waveStartText.alpha <= 0) {
			waveStartText.destroy();
			LK.clearInterval(fadeInterval);
		}
	}, 30);
}
function spawnZombie() {
	if (zombiesInWave <= 0) {
		return;
	}
	var zombie = new Zombie(wave);
	// Spawn at random edge position
	var angle = Math.random() * Math.PI * 2;
	var distance = 1200; // Spawn outside visible area
	zombie.x = CENTER_X + Math.cos(angle) * distance;
	zombie.y = CENTER_Y + Math.sin(angle) * distance;
	game.addChild(zombie);
	zombies.push(zombie);
	zombiesInWave--;
}
function gameOver() {
	isGameActive = false;
	// Play game over sound
	LK.getSound('gameOver').play();
	// Display message
	var gameOverText = new Text2("GAME OVER!", {
		size: 120,
		fill: 0xff0000
	});
	gameOverText.x = CENTER_X;
	gameOverText.y = CENTER_Y;
	gameOverText.anchor.set(0.5);
	game.addChild(gameOverText);
	var scoreText = new Text2("Waves Survived: " + wave + "\nZombies Killed: " + zombiesKilled, {
		size: 60,
		fill: 0xffffff
	});
	scoreText.x = CENTER_X;
	scoreText.y = CENTER_Y + 150;
	scoreText.anchor.set(0.5);
	game.addChild(scoreText);
	// Set final score (waves survived * zombies killed)
	LK.setScore(wave * zombiesKilled);
	// Show game over screen after delay
	LK.setTimeout(function () {
		LK.showGameOver();
	}, 3000);
}
/**** 
* Event Handlers
****/ 
game.on('down', function (x, y, obj) {
	if (!isGameActive) {
		return;
	}
	var event = obj;
	var pos = game.toLocal(event.global);
	// Check if clicking on upgrade panel
	if (pos.x > GAME_WIDTH - 500) {
		var upgradeCost = upgradePanel.checkUpgradeClick(pos.x, pos.y, gold);
		if (upgradeCost > 0) {
			gold -= upgradeCost;
			upgradePanel.updateGold(gold);
		}
	} else {
		// Manual targeting - can only fire once per second
		if (manualCooldown <= 0) {
			// Create target indicator
			var target = new ManualTarget();
			target.x = pos.x;
			target.y = pos.y;
			game.addChild(target);
			targets.push(target);
			// Fire at clicked location
			tower.manualShoot(pos.x, pos.y);
			manualCooldown = 60; // 1 second cooldown
		}
	}
});
/**** 
* Game Loop
****/ 
LK.on('tick', function () {
	if (!isGameActive) {
		return;
	}
	// Update tower
	tower.update();
	// Update upgrade panel
	upgradePanel.update();
	// Update bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (bullets[i].update()) {
			bullets[i].destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check for zombie hits
		for (var j = zombies.length - 1; j >= 0; j--) {
			if (bullets[i] && bullets[i].intersects(zombies[j])) {
				if (zombies[j].takeDamage(bullets[i].damage)) {
					// Zombie killed
					var explosion = new Explosion();
					explosion.x = zombies[j].x;
					explosion.y = zombies[j].y;
					game.addChild(explosion);
					explosions.push(explosion);
					// Add gold
					gold += zombies[j].value;
					upgradePanel.updateGold(gold);
					// Show gold pop-up
					var goldPop = new Text2("+" + zombies[j].value, {
						size: 30,
						fill: 0xffcc00
					});
					goldPop.x = zombies[j].x;
					goldPop.y = zombies[j].y - 50;
					goldPop.anchor.set(0.5);
					game.addChild(goldPop);
					// Fade out gold text
					var fadeInterval = LK.setInterval(function () {
						goldPop.alpha -= 0.05;
						goldPop.y -= 1;
						if (goldPop.alpha <= 0) {
							goldPop.destroy();
							LK.clearInterval(fadeInterval);
						}
					}, 30);
					LK.getSound('zombieDeath').play();
					zombies[j].destroy();
					zombies.splice(j, 1);
					zombiesKilled++;
				}
				// Remove bullet
				bullets[i].destroy();
				bullets.splice(i, 1);
				break;
			}
		}
	}
	// Update zombies
	for (var k = zombies.length - 1; k >= 0; k--) {
		var result = zombies[k].update();
		if (result === "gameover") {
			gameOver();
			return;
		}
	}
	// Update explosions
	for (var l = explosions.length - 1; l >= 0; l--) {
		if (explosions[l].update()) {
			explosions[l].destroy();
			explosions.splice(l, 1);
		}
	}
	// Update targets
	for (var m = targets.length - 1; m >= 0; m--) {
		if (targets[m].update()) {
			targets[m].destroy();
			targets.splice(m, 1);
		}
	}
	// Spawn zombies
	if (LK.ticks % waveInterval === 0 && zombiesInWave > 0) {
		spawnZombie();
	}
	// Check if wave is complete
	if (zombiesInWave <= 0 && zombies.length === 0 && !waitingForNextWave) {
		// Set flag to prevent multiple wave completions
		waitingForNextWave = true;
		// Start next wave after delay
		wave++;
		LK.setTimeout(function () {
			startWave();
		}, 3000);
		// Grant bonus gold between waves
		var bonus = 50 + (wave - 1) * 10;
		gold += bonus;
		upgradePanel.updateGold(gold);
		// Show wave complete message
		waveCompleteText = new Text2("WAVE " + (wave - 1) + " COMPLETE!", {
			size: 80,
			fill: 0x33ff33
		});
		waveCompleteText.x = CENTER_X;
		waveCompleteText.y = CENTER_Y;
		waveCompleteText.anchor.set(0.5);
		game.addChild(waveCompleteText);
		bonusText = new Text2("BONUS: +" + bonus + " GOLD", {
			size: 60,
			fill: 0xffcc00
		});
		bonusText.x = CENTER_X;
		bonusText.y = CENTER_Y + 100;
		bonusText.anchor.set(0.5);
		game.addChild(bonusText);
		// Fade out text
		waveTextInterval = LK.setInterval(function () {
			waveCompleteText.alpha -= 0.02;
			bonusText.alpha -= 0.02;
			if (waveCompleteText.alpha <= 0) {
				waveCompleteText.destroy();
				bonusText.destroy();
				LK.clearInterval(waveTextInterval);
				waveCompleteText = null;
				bonusText = null;
				waveTextInterval = null;
			}
		}, 30);
	}
	// Update manual cooldown
	if (manualCooldown > 0) {
		manualCooldown--;
	}
});
// Start the game
startGame(); /**** 
* Classes
****/ 
var Bullet = Container.expand(function (damage) {
	var self = Container.call(this);
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.vx = 0;
	self.vy = 0;
	self.damage = damage || 10;
	self.lifetime = 60; // Bullets disappear after 1 second
	self.update = function () {
		// Move bullet
		self.x += self.vx;
		self.y += self.vy;
		// Decrease lifetime
		self.lifetime--;
		return self.lifetime <= 0;
	};
	return self;
});
var Explosion = Container.expand(function () {
	var self = Container.call(this);
	var explosionGraphics = self.attachAsset('explosion', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.lifetime = 15;
	self.scale.set(0.2);
	self.update = function () {
		self.lifetime--;
		self.scale.set(1 - self.lifetime / 20);
		self.alpha = self.lifetime / 15;
		return self.lifetime <= 0;
	};
	return self;
});
var ManualTarget = Container.expand(function () {
	var self = Container.call(this);
	var targetGraphics = self.attachAsset('manualTarget', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.lifetime = 15;
	self.alpha = 0.5;
	self.update = function () {
		self.lifetime--;
		self.alpha = self.lifetime / 15;
		self.rotation += 0.1;
		return self.lifetime <= 0;
	};
	return self;
});
var Tower = Container.expand(function () {
	var self = Container.call(this);
	// Tower base (doesn't rotate)
	var base = self.attachAsset('towerBase', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Tower turret (rotates to aim)
	var turret = new Container();
	var turretGraphics = turret.attachAsset('tower', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(turret);
	// Tower stats
	self.health = 100;
	self.maxHealth = 100;
	self.damage = 10;
	self.fireRate = 60; // frames between shots
	self.fireTimer = 0;
	self.range = 800;
	self.upgradeLevel = {
		damage: 1,
		fireRate: 1,
		range: 1,
		health: 1
	};
	// Health bar
	var healthBarContainer = new Container();
	var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 200
	});
	var healthBarFill = new Container();
	var healthBarGraphics = healthBarFill.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5,
		width: 200
	});
	healthBarContainer.addChild(healthBarFill);
	healthBarContainer.y = -150;
	self.addChild(healthBarContainer);
	// Methods
	self.update = function () {
		// Decrease fire timer
		if (self.fireTimer > 0) {
			self.fireTimer--;
		}
		// Update health bar
		healthBarFill.scale.x = self.health / self.maxHealth;
		// Find target if none currently
		var target = null;
		var closestDist = self.range;
		for (var i = 0; i < zombies.length; i++) {
			var zombie = zombies[i];
			var dx = zombie.x - self.x;
			var dy = zombie.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist < closestDist) {
				closestDist = dist;
				target = zombie;
			}
		}
		// Aim at target
		if (target) {
			var angle = Math.atan2(target.y - self.y, target.x - self.x);
			turret.rotation = angle;
			// Fire if ready
			if (self.fireTimer <= 0) {
				var bullet = new Bullet(self.damage);
				bullet.x = self.x;
				bullet.y = self.y;
				bullet.rotation = angle;
				bullet.vx = Math.cos(angle) * 15;
				bullet.vy = Math.sin(angle) * 15;
				game.addChild(bullet);
				bullets.push(bullet);
				self.fireTimer = self.fireRate;
				LK.getSound('shoot').play();
			}
		}
	};
	self.manualShoot = function (x, y) {
		var angle = Math.atan2(y - self.y, x - self.x);
		turret.rotation = angle;
		var bullet = new Bullet(self.damage * 2); // Manual shots do double damage
		bullet.x = self.x;
		bullet.y = self.y;
		bullet.rotation = angle;
		bullet.vx = Math.cos(angle) * 15;
		bullet.vy = Math.sin(angle) * 15;
		game.addChild(bullet);
		bullets.push(bullet);
		LK.getSound('shoot').play();
	};
	self.takeDamage = function (amount) {
		self.health -= amount;
		// Flash the tower when hit
		LK.effects.flashObject(self, 0xff0000, 300);
		LK.getSound('towerHit').play();
		if (self.health <= 0) {
			return true; // Tower destroyed
		}
		return false;
	};
	self.upgradeDamage = function () {
		self.upgradeLevel.damage++;
		self.damage += 5;
		LK.getSound('upgrade').play();
	};
	self.upgradeFireRate = function () {
		self.upgradeLevel.fireRate++;
		self.fireRate = Math.max(10, self.fireRate - 10);
		LK.getSound('upgrade').play();
	};
	self.upgradeRange = function () {
		self.upgradeLevel.range++;
		self.range += 100;
		LK.getSound('upgrade').play();
	};
	self.upgradeHealth = function () {
		self.upgradeLevel.health++;
		var oldMaxHealth = self.maxHealth;
		self.maxHealth += 50;
		self.health += self.maxHealth - oldMaxHealth;
		LK.getSound('upgrade').play();
	};
	return self;
});
var UpgradePanel = Container.expand(function (tower) {
	var self = Container.call(this);
	// Panel background
	var panelBg = self.attachAsset('upgradePanel', {
		anchorX: 0,
		anchorY: 0
	});
	// Gold display
	var goldContainer = new Container();
	var goldIcon = goldContainer.attachAsset('goldIcon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var goldText = new Text2("0", {
		size: 40,
		fill: 0xffcc00
	});
	goldText.x = 60;
	goldText.anchor.set(0, 0.5);
	goldContainer.addChild(goldText);
	goldContainer.x = 100;
	goldContainer.y = 100;
	self.addChild(goldContainer);
	// Tower stats display
	var statsContainer = new Container();
	var damageText = new Text2("Damage: " + tower.damage, {
		size: 30,
		fill: 0xffffff
	});
	damageText.y = 0;
	statsContainer.addChild(damageText);
	var fireRateText = new Text2("Fire Rate: " + (60 / tower.fireRate).toFixed(1) + "/s", {
		size: 30,
		fill: 0xffffff
	});
	fireRateText.y = 40;
	statsContainer.addChild(fireRateText);
	var rangeText = new Text2("Range: " + tower.range, {
		size: 30,
		fill: 0xffffff
	});
	rangeText.y = 80;
	statsContainer.addChild(rangeText);
	var healthText = new Text2("Health: " + tower.health + "/" + tower.maxHealth, {
		size: 30,
		fill: 0xffffff
	});
	healthText.y = 120;
	statsContainer.addChild(healthText);
	statsContainer.x = 100;
	statsContainer.y = 200;
	self.addChild(statsContainer);
	// Upgrade buttons
	var upgradeButtons = [];
	var upgradeCosts = {
		damage: function damage() {
			return tower.upgradeLevel.damage * 50;
		},
		fireRate: function fireRate() {
			return tower.upgradeLevel.fireRate * 75;
		},
		range: function range() {
			return tower.upgradeLevel.range * 40;
		},
		health: function health() {
			return tower.upgradeLevel.health * 60;
		}
	};
	function createUpgradeButton(label, y, upgradeFunc, getCostFunc) {
		var button = new Container();
		var buttonBg = button.attachAsset('upgradeButton', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 30,
			fill: 0xffffff
		});
		buttonText.anchor.set(0, 0.5);
		buttonText.x = -buttonBg.width / 2 + 20;
		button.addChild(buttonText);
		var costText = new Text2("Cost: " + getCostFunc() + " Gold", {
			size: 25,
			fill: 0xffcc00
		});
		costText.anchor.set(1, 0.5);
		costText.x = buttonBg.width / 2 - 20;
		button.addChild(costText);
		button.x = 250;
		button.y = y;
		button.upgrade = upgradeFunc;
		button.getCost = getCostFunc;
		button.updateCost = function () {
			costText.setText("Cost: " + getCostFunc() + " Gold");
		};
		self.addChild(button);
		upgradeButtons.push(button);
		return button;
	}
	var damageButton = createUpgradeButton("Upgrade Damage", 400, function () {
		tower.upgradeDamage();
	}, upgradeCosts.damage);
	var fireRateButton = createUpgradeButton("Upgrade Fire Rate", 520, function () {
		tower.upgradeFireRate();
	}, upgradeCosts.fireRate);
	var rangeButton = createUpgradeButton("Upgrade Range", 640, function () {
		tower.upgradeRange();
	}, upgradeCosts.range);
	var healthButton = createUpgradeButton("Upgrade Health", 760, function () {
		tower.upgradeHealth();
	}, upgradeCosts.health);
	self.checkUpgradeClick = function (x, y, gold) {
		var localX = x - self.x;
		var localY = y - self.y;
		for (var i = 0; i < upgradeButtons.length; i++) {
			var button = upgradeButtons[i];
			var buttonX = button.x;
			var buttonY = button.y;
			var buttonWidth = 450;
			var buttonHeight = 100;
			if (localX >= buttonX - buttonWidth / 2 && localX <= buttonX + buttonWidth / 2 && localY >= buttonY - buttonHeight / 2 && localY <= buttonY + buttonHeight / 2) {
				var cost = button.getCost();
				if (gold >= cost) {
					button.upgrade();
					self.updateStats();
					return cost;
				} else {
					// Not enough gold
					button.alpha = 0.5;
					LK.setTimeout(function () {
						button.alpha = 1;
					}, 300);
					return 0;
				}
			}
		}
		return 0;
	};
	self.updateGold = function (gold) {
		goldText.setText(gold.toString());
	};
	self.updateStats = function () {
		damageText.setText("Damage: " + tower.damage);
		fireRateText.setText("Fire Rate: " + (60 / tower.fireRate).toFixed(1) + "/s");
		rangeText.setText("Range: " + tower.range);
		healthText.setText("Health: " + tower.health + "/" + tower.maxHealth);
		// Update costs
		for (var i = 0; i < upgradeButtons.length; i++) {
			upgradeButtons[i].updateCost();
		}
	};
	self.update = function () {
		self.updateStats();
	};
	return self;
});
var Zombie = Container.expand(function (waveNumber) {
	var self = Container.call(this);
	var zombieGraphics = self.attachAsset('zombie', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Stats scale with wave number
	var waveMultiplier = 1 + waveNumber * 0.2;
	self.health = 20 * waveMultiplier;
	self.maxHealth = self.health;
	self.speed = 2 + Math.random() * 1;
	self.damage = 5 * waveMultiplier;
	self.value = 10 + Math.floor(waveNumber * 5);
	// Chance to be a special zombie
	if (Math.random() < 0.2) {
		// Tank zombie - slower but more health
		self.health *= 3;
		self.maxHealth = self.health;
		self.speed *= 0.5;
		self.damage *= 2;
		self.value *= 3;
		zombieGraphics.tint = 0xff0000;
		zombieGraphics.width = 80;
		zombieGraphics.height = 80;
	} else if (Math.random() < 0.3) {
		// Fast zombie - faster but less health
		self.health *= 0.7;
		self.maxHealth = self.health;
		self.speed *= 2;
		self.value *= 2;
		zombieGraphics.tint = 0xffff00;
	}
	// Health bar
	var healthBarContainer = new Container();
	var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var healthBarFill = new Container();
	var healthBarGraphics = healthBarFill.attachAsset('healthBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	healthBarContainer.addChild(healthBarFill);
	healthBarContainer.y = -50;
	self.addChild(healthBarContainer);
	self.update = function () {
		// Move towards tower
		var dx = CENTER_X - self.x;
		var dy = CENTER_Y - self.y;
		var dist = Math.sqrt(dx * dx + dy * dy);
		if (dist < 50) {
			// Attack tower
			if (tower.takeDamage(self.damage)) {
				return "gameover";
			}
			// Destroy self
			self.destroy();
			zombies.splice(zombies.indexOf(self), 1);
		} else {
			// Move towards tower
			self.x += dx / dist * self.speed;
			self.y += dy / dist * self.speed;
		}
		// Update health bar
		healthBarFill.scale.x = self.health / self.maxHealth;
		// Zombie looks where it's going
		self.rotation = Math.atan2(dy, dx);
		return "ok";
	};
	self.takeDamage = function (amount) {
		self.health -= amount;
		return self.health <= 0;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
/**** 
* Game Variables
****/ 
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CENTER_X = GAME_WIDTH / 2;
var CENTER_Y = GAME_HEIGHT / 2;
// Game state
var isGameActive = false;
var waitingForNextWave = false;
// Game objects
var tower;
var upgradePanel;
var waveIndicator;
var waveCompleteText;
var bonusText;
var waveTextInterval;
// Collections
var zombies = [];
var bullets = [];
var explosions = [];
var targets = [];
// Game stats
var wave = 0;
var zombiesInWave = 0;
var waveInterval = 60; // Frames between zombie spawns
var zombiesKilled = 0;
var gold = 100;
var manualCooldown = 0;
/**** 
* Game Functions
****/ 
function startGame() {
	// Create background
	var background = new Container();
	var backgroundGraphics = background.attachAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.x = CENTER_X;
	background.y = CENTER_Y;
	game.addChild(background);
	// Create tower
	tower = new Tower();
	tower.x = CENTER_X;
	tower.y = CENTER_Y;
	game.addChild(tower);
	// Create upgrade panel
	upgradePanel = new UpgradePanel(tower);
	upgradePanel.x = GAME_WIDTH - 500;
	upgradePanel.y = 0;
	game.addChild(upgradePanel);
	// Create wave indicator
	waveIndicator = new Container();
	var waveIndicatorBg = waveIndicator.attachAsset('waveIndicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var waveText = new Text2("WAVE 1", {
		size: 40,
		fill: 0xffffff
	});
	waveText.anchor.set(0.5);
	waveIndicator.addChild(waveText);
	waveIndicator.x = GAME_WIDTH - 250;
	waveIndicator.y = GAME_HEIGHT - 100;
	game.addChild(waveIndicator);
	// Start the game
	isGameActive = true;
	// Start first wave
	startWave();
	// Start background music
	LK.getSound('background').play();
	// Update gold display
	upgradePanel.updateGold(gold);
}
function startWave() {
	// Clean up any previous wave text elements
	if (waveCompleteText) {
		waveCompleteText.destroy();
		waveCompleteText = null;
	}
	if (bonusText) {
		bonusText.destroy();
		bonusText = null;
	}
	if (waveTextInterval) {
		LK.clearInterval(waveTextInterval);
		waveTextInterval = null;
	}
	waitingForNextWave = false;
	waveIndicator.children[1].setText("WAVE " + wave);
	zombiesInWave = 10 + wave * 5;
	waveInterval = Math.max(20, 60 - wave * 5); // Spawn zombies faster in later waves
	// Show wave start message
	var waveStartText = new Text2("WAVE " + wave + " STARTING!", {
		size: 80,
		fill: 0xff9900
	});
	waveStartText.x = CENTER_X;
	waveStartText.y = CENTER_Y;
	waveStartText.anchor.set(0.5);
	game.addChild(waveStartText);
	LK.getSound('waveStart').play();
	// Fade out text
	var fadeInterval = LK.setInterval(function () {
		waveStartText.alpha -= 0.05;
		if (waveStartText.alpha <= 0) {
			waveStartText.destroy();
			LK.clearInterval(fadeInterval);
		}
	}, 30);
}
function spawnZombie() {
	if (zombiesInWave <= 0) {
		return;
	}
	var zombie = new Zombie(wave);
	// Spawn at random edge position
	var angle = Math.random() * Math.PI * 2;
	var distance = 1200; // Spawn outside visible area
	zombie.x = CENTER_X + Math.cos(angle) * distance;
	zombie.y = CENTER_Y + Math.sin(angle) * distance;
	game.addChild(zombie);
	zombies.push(zombie);
	zombiesInWave--;
}
function gameOver() {
	isGameActive = false;
	// Play game over sound
	LK.getSound('gameOver').play();
	// Display message
	var gameOverText = new Text2("GAME OVER!", {
		size: 120,
		fill: 0xff0000
	});
	gameOverText.x = CENTER_X;
	gameOverText.y = CENTER_Y;
	gameOverText.anchor.set(0.5);
	game.addChild(gameOverText);
	var scoreText = new Text2("Waves Survived: " + wave + "\nZombies Killed: " + zombiesKilled, {
		size: 60,
		fill: 0xffffff
	});
	scoreText.x = CENTER_X;
	scoreText.y = CENTER_Y + 150;
	scoreText.anchor.set(0.5);
	game.addChild(scoreText);
	// Set final score (waves survived * zombies killed)
	LK.setScore(wave * zombiesKilled);
	// Show game over screen after delay
	LK.setTimeout(function () {
		LK.showGameOver();
	}, 3000);
}
/**** 
* Event Handlers
****/ 
game.on('down', function (x, y, obj) {
	if (!isGameActive) {
		return;
	}
	var event = obj;
	var pos = game.toLocal(event.global);
	// Check if clicking on upgrade panel
	if (pos.x > GAME_WIDTH - 500) {
		var upgradeCost = upgradePanel.checkUpgradeClick(pos.x, pos.y, gold);
		if (upgradeCost > 0) {
			gold -= upgradeCost;
			upgradePanel.updateGold(gold);
		}
	} else {
		// Manual targeting - can only fire once per second
		if (manualCooldown <= 0) {
			// Create target indicator
			var target = new ManualTarget();
			target.x = pos.x;
			target.y = pos.y;
			game.addChild(target);
			targets.push(target);
			// Fire at clicked location
			tower.manualShoot(pos.x, pos.y);
			manualCooldown = 60; // 1 second cooldown
		}
	}
});
/**** 
* Game Loop
****/ 
LK.on('tick', function () {
	if (!isGameActive) {
		return;
	}
	// Update tower
	tower.update();
	// Update upgrade panel
	upgradePanel.update();
	// Update bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		if (bullets[i].update()) {
			bullets[i].destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check for zombie hits
		for (var j = zombies.length - 1; j >= 0; j--) {
			if (bullets[i] && bullets[i].intersects(zombies[j])) {
				if (zombies[j].takeDamage(bullets[i].damage)) {
					// Zombie killed
					var explosion = new Explosion();
					explosion.x = zombies[j].x;
					explosion.y = zombies[j].y;
					game.addChild(explosion);
					explosions.push(explosion);
					// Add gold
					gold += zombies[j].value;
					upgradePanel.updateGold(gold);
					// Show gold pop-up
					var goldPop = new Text2("+" + zombies[j].value, {
						size: 30,
						fill: 0xffcc00
					});
					goldPop.x = zombies[j].x;
					goldPop.y = zombies[j].y - 50;
					goldPop.anchor.set(0.5);
					game.addChild(goldPop);
					// Fade out gold text
					var fadeInterval = LK.setInterval(function () {
						goldPop.alpha -= 0.05;
						goldPop.y -= 1;
						if (goldPop.alpha <= 0) {
							goldPop.destroy();
							LK.clearInterval(fadeInterval);
						}
					}, 30);
					LK.getSound('zombieDeath').play();
					zombies[j].destroy();
					zombies.splice(j, 1);
					zombiesKilled++;
				}
				// Remove bullet
				bullets[i].destroy();
				bullets.splice(i, 1);
				break;
			}
		}
	}
	// Update zombies
	for (var k = zombies.length - 1; k >= 0; k--) {
		var result = zombies[k].update();
		if (result === "gameover") {
			gameOver();
			return;
		}
	}
	// Update explosions
	for (var l = explosions.length - 1; l >= 0; l--) {
		if (explosions[l].update()) {
			explosions[l].destroy();
			explosions.splice(l, 1);
		}
	}
	// Update targets
	for (var m = targets.length - 1; m >= 0; m--) {
		if (targets[m].update()) {
			targets[m].destroy();
			targets.splice(m, 1);
		}
	}
	// Spawn zombies
	if (LK.ticks % waveInterval === 0 && zombiesInWave > 0) {
		spawnZombie();
	}
	// Check if wave is complete
	if (zombiesInWave <= 0 && zombies.length === 0 && !waitingForNextWave) {
		// Set flag to prevent multiple wave completions
		waitingForNextWave = true;
		// Start next wave after delay
		wave++;
		LK.setTimeout(function () {
			startWave();
		}, 3000);
		// Grant bonus gold between waves
		var bonus = 50 + (wave - 1) * 10;
		gold += bonus;
		upgradePanel.updateGold(gold);
		// Show wave complete message
		waveCompleteText = new Text2("WAVE " + (wave - 1) + " COMPLETE!", {
			size: 80,
			fill: 0x33ff33
		});
		waveCompleteText.x = CENTER_X;
		waveCompleteText.y = CENTER_Y;
		waveCompleteText.anchor.set(0.5);
		game.addChild(waveCompleteText);
		bonusText = new Text2("BONUS: +" + bonus + " GOLD", {
			size: 60,
			fill: 0xffcc00
		});
		bonusText.x = CENTER_X;
		bonusText.y = CENTER_Y + 100;
		bonusText.anchor.set(0.5);
		game.addChild(bonusText);
		// Fade out text
		waveTextInterval = LK.setInterval(function () {
			waveCompleteText.alpha -= 0.02;
			bonusText.alpha -= 0.02;
			if (waveCompleteText.alpha <= 0) {
				waveCompleteText.destroy();
				bonusText.destroy();
				LK.clearInterval(waveTextInterval);
				waveCompleteText = null;
				bonusText = null;
				waveTextInterval = null;
			}
		}, 30);
	}
	// Update manual cooldown
	if (manualCooldown > 0) {
		manualCooldown--;
	}
});
// Start the game
startGame();