/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Boss Class
var Boss = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy ball asset (boss face)
	var bossFace = self.attachAsset('enemyBall', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.2,
		scaleY: 2.2
	});
	self.bossFace = bossFace;
	self.speed = 8;
	self.targetX = 2048 / 2;
	self.targetY = 800;
	// Boss starts at top, then chases player
	self.x = 2048 / 2;
	self.y = -bossFace.height;
	self.update = function () {
		// Move boss into screen, then chase player
		if (self.y < self.targetY) {
			self.y += 18;
			if (self.y > self.targetY) self.y = self.targetY;
		} else {
			// Chase player
			var dx = playerBall.x - self.x;
			var dy = playerBall.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist > 10) {
				self.x += dx / dist * self.speed;
				self.y += dy / dist * self.speed * 0.7;
			}
		}
	};
	return self;
});
// Damage Ball Class
var DamageBall = Container.expand(function () {
	var self = Container.call(this);
	// Attach a yellow ball asset
	var ball = self.attachAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.1,
		scaleY: 1.1
	});
	ball.tint = 0xffe600;
	self.ball = ball;
	self.speed = 18;
	// Random X within game area
	var r = ball.width / 2;
	self.x = Math.random() * (2048 - 2 * r) + r;
	self.y = -r - 10;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Start the boss chase phase
// Enemy Ball Class
var EnemyBall = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy ball asset (red circle)
	var ball = self.attachAsset('enemyBall', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Assign ball asset to self.ball for external access
	self.ball = ball;
	// Speed will be set on creation
	self.speed = 6;
	// Update method: move down
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Player Ball Class
var PlayerBall = Container.expand(function () {
	var self = Container.call(this);
	// Attach player ball asset (blue circle)
	var ball = self.attachAsset('playerBall', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// For possible future use (e.g., effects)
	self.ball = ball;
	// No update needed; position is controlled by drag
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181818 // Dark background
});
/**** 
* Game Code
****/ 
// Start the boss chase phase
// --- Game Variables ---
// Tween plugin for future use (animations, etc.)
// --- Asset Initialization (shapes) ---
// --- Second Boss Phase Variables (moved to global scope for access in update and reset) ---
var secondBoss = null;
var secondBossHealth = 1000;
var secondBossHealthTxt = null;
var inSecondBossPhase = false;
var secondBossDamageBalls = [];
var secondBossDamageBallSpawnTicks = 0;
function startChasePhase() {
	inChasePhase = true;
	// Remove all enemies
	for (var i = 0; i < enemyBalls.length; i++) {
		enemyBalls[i].destroy();
	}
	enemyBalls = [];
	// Spawn boss
	boss = new Boss();
	game.addChild(boss);
	// Show boss health
	if (bossHealthTxt && bossHealthTxt.parent) bossHealthTxt.parent.removeChild(bossHealthTxt);
	bossHealth = 500;
	bossHealthTxt = new Text2("Boss: " + bossHealth, {
		size: 90,
		fill: 0xffe600,
		font: "Arial, Helvetica, sans-serif"
	});
	// Place boss health bar below score, yellow color
	bossHealthTxt.anchor.set(0.5, 0);
	bossHealthTxt.x = 2048 / 2;
	bossHealthTxt.y = 120; // just below score
	LK.gui.top.addChild(bossHealthTxt);
	// Reset damage balls
	for (var j = 0; j < damageBalls.length; j++) {
		damageBalls[j].destroy();
	}
	damageBalls = [];
	damageBallSpawnTicks = 0;
}
// Spawn a damage ball
function spawnDamageBall() {
	var dball = new DamageBall();
	damageBalls.push(dball);
	game.addChild(dball);
}
var playerBall;
var enemyBalls = [];
var lives = 3;
var score = 0;
var spawnInterval = 80; // Initial enemy spawn interval (ticks)
var enemySpeed = 6; // Initial enemy speed
var ticksSinceLastSpawn = 0;
var dragNode = null;
var lastGameOver = false;
// --- Boss & Chase Phase ---
var freezeEnemies = false;
var freezeTicks = 0;
var chasePhaseStarted = false;
var boss = null;
var bossHealth = 500;
var bossHealthTxt = null;
var damageBalls = [];
var damageBallSpawnTicks = 0;
var inChasePhase = false;
// --- Tap to Start Overlay & Villain Dialog Control ---
// (Removed tap-to-start overlay and tap logic. Game/dialog starts immediately.)
var gameStarted = true;
// Control for villain dialog per level (no tap-to-start)
var waitingForTap = false;
var pendingVillainText = null;
var pendingVillainState = null;
// Helper to show villain dialog (no tap-to-start overlay)
function showVillainAndWait(text, nextState) {
	// Show villain dialog
	showVillainBubble(text);
	waitingForTap = false;
	pendingVillainText = text;
	pendingVillainState = nextState;
	gameStarted = true;
}
// --- UI Elements ---
// Score Text
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives Text
var livesTxt = new Text2('❤ 3', {
	size: 90,
	fill: 0xFF5252
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
// --- Player Ball Setup ---
playerBall = new PlayerBall();
game.addChild(playerBall);
// Start at bottom center, above the bottom edge
playerBall.x = 2048 / 2;
playerBall.y = 2732 - 220;
// --- Drag Handling ---
function handleMove(x, y, obj) {
	if (dragNode) {
		// Clamp to game area (keep ball fully visible)
		var r = playerBall.ball.width / 2;
		var minX = r,
			maxX = 2048 - r;
		var minY = r,
			maxY = 2732 - r;
		dragNode.x = Math.max(minX, Math.min(maxX, x));
		dragNode.y = Math.max(minY, Math.min(maxY, y));
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Only start drag if touch/click is on the player ball
	var dx = x - playerBall.x;
	var dy = y - playerBall.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist <= playerBall.ball.width / 2) {
		dragNode = playerBall;
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// --- Enemy Spawning ---
function spawnEnemy() {
	var enemy = new EnemyBall();
	// Random X within game area, keeping ball fully visible
	var r = enemy.ball.width / 2;
	enemy.x = Math.random() * (2048 - 2 * r) + r;
	enemy.y = -r - 10; // Start just above the screen
	enemy.speed = enemySpeed + Math.random() * 2; // Add a bit of speed variation
	enemyBalls.push(enemy);
	game.addChild(enemy);
}
// --- Story & Level State ---
var villainState = 0; // 0: intro, 1: after 50, 2: after 100, 3: after 250 (win)
var villainBubble = null;
var villainTimeout = null;
var villainShowTicks = 0;
var villainShowDuration = 180; // 3 seconds at 60fps
function showVillainBubble(text) {
	// Remove previous if exists
	if (villainBubble && villainBubble.parent) villainBubble.parent.removeChild(villainBubble);
	villainBubble = new Container();
	// Villain face (red ball)
	var face = LK.getAsset('enemyBall', {
		anchorX: 0.5,
		anchorY: 1
	});
	face.x = 0;
	face.y = 0;
	villainBubble.addChild(face);
	// Speech bubble (white rounded box)
	var bubble = new Container();
	var bubbleShape = LK.getAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.5,
		scaleY: 1.2
	});
	bubbleShape.tint = 0xffffff;
	bubbleShape.alpha = 0.92;
	bubble.addChild(bubbleShape);
	// Text (English, white)
	var txt = new Text2(text, {
		size: 80,
		fill: 0xffffff,
		font: "Arial, Helvetica, sans-serif"
	});
	txt.anchor.set(0.5, 0.5);
	bubble.addChild(txt);
	bubble.x = 0;
	bubble.y = -180;
	villainBubble.addChild(bubble);
	// Position villainBubble at top center, but lower for readability
	villainBubble.x = 2048 / 2;
	villainBubble.y = 520; // moved down from 320 to 520
	game.addChild(villainBubble);
	villainShowTicks = 0;
}
function removeVillainBubble() {
	if (villainBubble && villainBubble.parent) villainBubble.parent.removeChild(villainBubble);
	villainBubble = null;
	villainShowTicks = 0;
}
// --- Game Update Loop ---
game.update = function () {
	// --- Villain Dialog Logic ---
	if (villainBubble) {
		villainShowTicks++;
		if (villainShowTicks > villainShowDuration) {
			removeVillainBubble();
		}
	}
	// --- Level/Story Progression ---
	// At each story point, show villain and advance automatically
	if (villainState === 0 && LK.ticks < 10) {
		showVillainAndWait("I will destroy the world!", 1);
		villainState = 0.25;
	}
	if (villainState === 0.25) {
		// Remove villain bubble after duration, then advance
		if (!villainBubble) {
			villainState = 1;
		}
	}
	if (villainState === 1 && score >= 50) {
		showVillainAndWait("You're finished now!", 2);
		// Speed up balls
		spawnInterval = Math.max(30, spawnInterval - 18);
		enemySpeed += 3.5;
		villainState = 1.25;
	}
	if (villainState === 1.25) {
		if (!villainBubble) {
			villainState = 2;
		}
	}
	if (villainState === 2 && score >= 100) {
		showVillainAndWait("Enough!", 3);
		// Balls get much faster
		spawnInterval = Math.max(18, spawnInterval - 10);
		enemySpeed += 4.5;
		villainState = 2.25;
	}
	if (villainState === 2.25) {
		if (!villainBubble) {
			villainState = 3;
		}
	}
	if (villainState === 3 && score >= 250) {
		showVillainAndWait("Stop right there!", 4);
		villainState = 3.25;
		// Freeze all enemies, but allow player to move
		for (var i = 0; i < enemyBalls.length; i++) {
			enemyBalls[i].frozen = true;
		}
		// Prevent new enemies from spawning
		freezeEnemies = true;
		freezeTicks = LK.ticks;
		chasePhaseStarted = false;
	}
	if (villainState === 3.25) {
		if (!villainBubble && !chasePhaseStarted) {
			// After villain dialog, wait 10 seconds, then start chase
			LK.setTimeout(function () {
				showVillainAndWait("Taste this!", 5);
				// After dialog, spawn boss and damage balls
				LK.setTimeout(function () {
					startChasePhase();
				}, villainShowDuration * 16.7); // villainShowDuration is in ticks, convert to ms
			}, 10000);
			chasePhaseStarted = true;
		}
		// Do not advance villainState until chase phase is started
	}
	// --- Enemy Spawning ---
	if (!freezeEnemies && !inChasePhase) {
		ticksSinceLastSpawn++;
		if (ticksSinceLastSpawn >= spawnInterval) {
			spawnEnemy();
			ticksSinceLastSpawn = 0;
		}
	}
	// --- Difficulty Scaling ---
	if (!freezeEnemies && !inChasePhase) {
		// Every 600 ticks (~10 seconds), increase difficulty
		if (LK.ticks % 600 === 0 && LK.ticks > 0) {
			if (spawnInterval > 30) spawnInterval -= 8; // Faster spawns
			if (enemySpeed < 22) enemySpeed += 1.2; // Faster enemies
		}
	}
	// --- Update Enemies ---
	for (var i = enemyBalls.length - 1; i >= 0; i--) {
		var enemy = enemyBalls[i];
		if (!enemy.frozen) {
			enemy.update();
		}
		// Check collision with player
		var collides = enemy.intersects(playerBall);
		if (collides && !enemy.frozen) {
			// Remove enemy
			enemy.destroy();
			enemyBalls.splice(i, 1);
			// Lose a life
			lives--;
			livesTxt.setText('❤ ' + lives);
			// Flash player ball
			LK.effects.flashObject(playerBall, 0xff0000, 400);
			// Game over if no lives left
			if (lives <= 0 && !lastGameOver) {
				lastGameOver = true;
				LK.effects.flashScreen(0xff0000, 800);
				LK.showGameOver();
				return;
			}
			continue;
		}
		// Remove if off screen
		if (enemy.y - enemy.ball.height / 2 > 2732 + 40) {
			enemy.destroy();
			enemyBalls.splice(i, 1);
			// Score for dodging
			score++;
			scoreTxt.setText(score + '');
		}
	}
	// --- Boss Chase Phase ---
	if (inChasePhase && boss) {
		boss.update();
		// Check collision with player (lose instantly)
		if (boss.intersects(playerBall) && !lastGameOver) {
			lastGameOver = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showGameOver();
			return;
		}
		// Update damage balls
		for (var j = damageBalls.length - 1; j >= 0; j--) {
			var dball = damageBalls[j];
			dball.update();
			// If player collects damage ball
			if (dball.intersects(playerBall)) {
				// Remove damage ball
				dball.destroy();
				damageBalls.splice(j, 1);
				// Deal 20 damage to boss
				bossHealth -= 20;
				if (bossHealth < 0) bossHealth = 0;
				if (bossHealthTxt) bossHealthTxt.setText("Boss: " + bossHealth);
				// Flash boss
				LK.effects.flashObject(boss, 0xffe600, 400);
				// If boss defeated, start second boss phase
				if (bossHealth <= 0 && !inSecondBossPhase) {
					// Remove first boss and health bar
					if (boss && boss.parent) boss.parent.removeChild(boss);
					boss = null;
					if (bossHealthTxt && bossHealthTxt.parent) bossHealthTxt.parent.removeChild(bossHealthTxt);
					bossHealthTxt = null;
					// Remove all damage balls
					for (var k = 0; k < damageBalls.length; k++) {
						damageBalls[k].destroy();
					}
					damageBalls = [];
					inChasePhase = false;
					// Villain dialog: "How is this possible?!"
					showVillainAndWait("How is this possible?!", 100);
					villainState = 99.5;
					inSecondBossPhase = true;
					// After dialog, start second boss attack after 2 seconds
					LK.setTimeout(function () {
						showVillainAndWait("Now face me!", 101);
						LK.setTimeout(function () {
							// Spawn second boss
							secondBoss = new Boss();
							secondBossHealth = 1000;
							secondBoss.speed = 13; // faster and angrier
							secondBoss.targetY = 700;
							secondBoss.bossFace.tint = 0xff2222; // visually more angry
							game.addChild(secondBoss);
							// Show second boss health bar
							if (secondBossHealthTxt && secondBossHealthTxt.parent) secondBossHealthTxt.parent.removeChild(secondBossHealthTxt);
							secondBossHealthTxt = new Text2("Villain: " + secondBossHealth, {
								size: 90,
								fill: 0xffe600,
								font: "Arial, Helvetica, sans-serif"
							});
							secondBossHealthTxt.anchor.set(0.5, 0);
							secondBossHealthTxt.x = 2048 / 2;
							secondBossHealthTxt.y = 220; // below score and first boss bar
							LK.gui.top.addChild(secondBossHealthTxt);
							// Reset second boss damage balls
							for (var m = 0; m < secondBossDamageBalls.length; m++) {
								secondBossDamageBalls[m].destroy();
							}
							secondBossDamageBalls = [];
							secondBossDamageBallSpawnTicks = 0;
						}, villainShowDuration * 16.7);
					}, 2000);
					return;
				}
			}
			// Remove if off screen
			if (dball.y > 2732 + 80) {
				dball.destroy();
				damageBalls.splice(j, 1);
			}
		}
		// Spawn damage balls every 90 ticks
		damageBallSpawnTicks++;
		if (damageBallSpawnTicks >= 90) {
			spawnDamageBall();
			damageBallSpawnTicks = 0;
		}
	}
	// --- Second Boss Phase ---
	if (inSecondBossPhase && secondBoss) {
		secondBoss.update();
		// If villain collides with player, game over
		if (secondBoss.intersects(playerBall) && !lastGameOver) {
			lastGameOver = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showGameOver();
			return;
		}
		// Update second boss damage balls
		for (var n = secondBossDamageBalls.length - 1; n >= 0; n--) {
			var sdball = secondBossDamageBalls[n];
			sdball.update();
			// If player collects damage ball
			if (sdball.intersects(playerBall)) {
				sdball.destroy();
				secondBossDamageBalls.splice(n, 1);
				// Deal 50 damage to second boss
				secondBossHealth -= 50;
				if (secondBossHealth < 0) secondBossHealth = 0;
				if (secondBossHealthTxt) secondBossHealthTxt.setText("Villain: " + secondBossHealth);
				LK.effects.flashObject(secondBoss, 0xffe600, 400);
				// If second boss defeated
				if (secondBossHealth <= 0 && !lastGameOver) {
					lastGameOver = true;
					// Boss explosion effect
					if (secondBoss && secondBoss.parent) {
						// Create a quick yellow flash and scale up for explosion
						// Use tween.to for boss explosion
						tween.to(secondBoss, {
							scaleX: 3.5,
							scaleY: 3.5,
							alpha: 0
						}, 700, {
							easing: "easeOutCubic"
						});
						LK.effects.flashObject(secondBoss, 0xffe600, 400);
						LK.setTimeout(function () {
							if (secondBoss && secondBoss.parent) secondBoss.parent.removeChild(secondBoss);
						}, 700);
					} else if (secondBoss && !secondBoss.parent) {
						// fallback
						secondBoss = null;
					}
					if (secondBossHealthTxt && secondBossHealthTxt.parent) secondBossHealthTxt.parent.removeChild(secondBossHealthTxt);
					// Remove all second boss damage balls
					for (var p = 0; p < secondBossDamageBalls.length; p++) {
						secondBossDamageBalls[p].destroy();
					}
					secondBossDamageBalls = [];
					// Final villain dialog: "No! How could you?!"
					showVillainAndWait("No! How could you?!", 200);
					// After dialog, show crowd rescue message
					LK.setTimeout(function () {
						// Remove villain bubble if still present
						removeVillainBubble();
						// Show crowd dialog at bottom of screen
						var crowdBubble = new Container();
						// Crowd "face" (use playerBall asset as a group icon)
						var crowdFace = LK.getAsset('playerBall', {
							anchorX: 0.5,
							anchorY: 1,
							scaleX: 1.5,
							scaleY: 1.5
						});
						crowdFace.x = 0;
						crowdFace.y = 0;
						crowdFace.tint = 0x4caf50; // green for hope
						crowdBubble.addChild(crowdFace);
						// Speech bubble (white, wide)
						var bubble = new Container();
						var bubbleShape = LK.getAsset('centerCircle', {
							anchorX: 0.5,
							anchorY: 0.5,
							scaleX: 3.2,
							scaleY: 1.3
						});
						bubbleShape.tint = 0xffffff;
						bubbleShape.alpha = 0.95;
						bubble.addChild(bubbleShape);
						// Text (English, green)
						var txt = new Text2("You saved us! Thank you, hero!", {
							size: 90,
							fill: 0x4caf50,
							font: "Arial, Helvetica, sans-serif"
						});
						txt.anchor.set(0.5, 0.5);
						bubble.addChild(txt);
						bubble.x = 0;
						bubble.y = -180;
						crowdBubble.addChild(bubble);
						// Position at bottom center
						crowdBubble.x = 2048 / 2;
						crowdBubble.y = 2732 - 220;
						game.addChild(crowdBubble);
						// Flash green for celebration
						LK.effects.flashScreen(0x00ff00, 800);
						// Remove crowd bubble and show win after 2.5s
						LK.setTimeout(function () {
							if (crowdBubble && crowdBubble.parent) crowdBubble.parent.removeChild(crowdBubble);
							LK.showYouWin();
						}, 2500);
					}, 1800 + 1200); // after villain dialog and a short pause
					return;
				}
			}
			// Remove if off screen
			if (sdball.y > 2732 + 80) {
				sdball.destroy();
				secondBossDamageBalls.splice(n, 1);
			}
		}
		// Spawn second boss damage balls every 60 ticks (faster)
		secondBossDamageBallSpawnTicks++;
		if (secondBossDamageBallSpawnTicks >= 60) {
			var sdb = new DamageBall();
			sdb.ball.tint = 0xffe600;
			secondBossDamageBalls.push(sdb);
			game.addChild(sdb);
			secondBossDamageBallSpawnTicks = 0;
		}
	}
};
// --- Reset Handler (for when game restarts) ---
game.on('destroy', function () {
	// Clean up
	for (var i = 0; i < enemyBalls.length; i++) {
		enemyBalls[i].destroy();
	}
	enemyBalls = [];
	// Remove boss if exists
	if (boss && boss.parent) boss.parent.removeChild(boss);
	boss = null;
	// Remove boss health text
	if (bossHealthTxt && bossHealthTxt.parent) bossHealthTxt.parent.removeChild(bossHealthTxt);
	bossHealthTxt = null;
	// Remove damage balls
	for (var j = 0; j < damageBalls.length; j++) {
		damageBalls[j].destroy();
	}
	damageBalls = [];
	inChasePhase = false;
	freezeEnemies = false;
	chasePhaseStarted = false;
	bossHealth = 500;
	damageBallSpawnTicks = 0;
	// Remove second boss and its UI
	if (secondBoss && secondBoss.parent) secondBoss.parent.removeChild(secondBoss);
	secondBoss = null;
	if (secondBossHealthTxt && secondBossHealthTxt.parent) secondBossHealthTxt.parent.removeChild(secondBossHealthTxt);
	secondBossHealthTxt = null;
	for (var q = 0; q < secondBossDamageBalls.length; q++) {
		secondBossDamageBalls[q].destroy();
	}
	secondBossDamageBalls = [];
	inSecondBossPhase = false;
	secondBossHealth = 1000;
	secondBossDamageBallSpawnTicks = 0;
	lives = 3;
	score = 0;
	spawnInterval = 80;
	enemySpeed = 6;
	ticksSinceLastSpawn = 0;
	lastGameOver = false;
	scoreTxt.setText('0');
	livesTxt.setText('❤ 3');
	// Reset player position
	playerBall.x = 2048 / 2;
	playerBall.y = 2732 - 220;
	// Reset gameStarted and villain state
	gameStarted = true;
	waitingForTap = false;
	pendingVillainText = null;
	pendingVillainState = null;
	villainState = 0;
	removeVillainBubble();
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Boss Class
var Boss = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy ball asset (boss face)
	var bossFace = self.attachAsset('enemyBall', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.2,
		scaleY: 2.2
	});
	self.bossFace = bossFace;
	self.speed = 8;
	self.targetX = 2048 / 2;
	self.targetY = 800;
	// Boss starts at top, then chases player
	self.x = 2048 / 2;
	self.y = -bossFace.height;
	self.update = function () {
		// Move boss into screen, then chase player
		if (self.y < self.targetY) {
			self.y += 18;
			if (self.y > self.targetY) self.y = self.targetY;
		} else {
			// Chase player
			var dx = playerBall.x - self.x;
			var dy = playerBall.y - self.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			if (dist > 10) {
				self.x += dx / dist * self.speed;
				self.y += dy / dist * self.speed * 0.7;
			}
		}
	};
	return self;
});
// Damage Ball Class
var DamageBall = Container.expand(function () {
	var self = Container.call(this);
	// Attach a yellow ball asset
	var ball = self.attachAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.1,
		scaleY: 1.1
	});
	ball.tint = 0xffe600;
	self.ball = ball;
	self.speed = 18;
	// Random X within game area
	var r = ball.width / 2;
	self.x = Math.random() * (2048 - 2 * r) + r;
	self.y = -r - 10;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Start the boss chase phase
// Enemy Ball Class
var EnemyBall = Container.expand(function () {
	var self = Container.call(this);
	// Attach enemy ball asset (red circle)
	var ball = self.attachAsset('enemyBall', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Assign ball asset to self.ball for external access
	self.ball = ball;
	// Speed will be set on creation
	self.speed = 6;
	// Update method: move down
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Player Ball Class
var PlayerBall = Container.expand(function () {
	var self = Container.call(this);
	// Attach player ball asset (blue circle)
	var ball = self.attachAsset('playerBall', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// For possible future use (e.g., effects)
	self.ball = ball;
	// No update needed; position is controlled by drag
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181818 // Dark background
});
/**** 
* Game Code
****/ 
// Start the boss chase phase
// --- Game Variables ---
// Tween plugin for future use (animations, etc.)
// --- Asset Initialization (shapes) ---
// --- Second Boss Phase Variables (moved to global scope for access in update and reset) ---
var secondBoss = null;
var secondBossHealth = 1000;
var secondBossHealthTxt = null;
var inSecondBossPhase = false;
var secondBossDamageBalls = [];
var secondBossDamageBallSpawnTicks = 0;
function startChasePhase() {
	inChasePhase = true;
	// Remove all enemies
	for (var i = 0; i < enemyBalls.length; i++) {
		enemyBalls[i].destroy();
	}
	enemyBalls = [];
	// Spawn boss
	boss = new Boss();
	game.addChild(boss);
	// Show boss health
	if (bossHealthTxt && bossHealthTxt.parent) bossHealthTxt.parent.removeChild(bossHealthTxt);
	bossHealth = 500;
	bossHealthTxt = new Text2("Boss: " + bossHealth, {
		size: 90,
		fill: 0xffe600,
		font: "Arial, Helvetica, sans-serif"
	});
	// Place boss health bar below score, yellow color
	bossHealthTxt.anchor.set(0.5, 0);
	bossHealthTxt.x = 2048 / 2;
	bossHealthTxt.y = 120; // just below score
	LK.gui.top.addChild(bossHealthTxt);
	// Reset damage balls
	for (var j = 0; j < damageBalls.length; j++) {
		damageBalls[j].destroy();
	}
	damageBalls = [];
	damageBallSpawnTicks = 0;
}
// Spawn a damage ball
function spawnDamageBall() {
	var dball = new DamageBall();
	damageBalls.push(dball);
	game.addChild(dball);
}
var playerBall;
var enemyBalls = [];
var lives = 3;
var score = 0;
var spawnInterval = 80; // Initial enemy spawn interval (ticks)
var enemySpeed = 6; // Initial enemy speed
var ticksSinceLastSpawn = 0;
var dragNode = null;
var lastGameOver = false;
// --- Boss & Chase Phase ---
var freezeEnemies = false;
var freezeTicks = 0;
var chasePhaseStarted = false;
var boss = null;
var bossHealth = 500;
var bossHealthTxt = null;
var damageBalls = [];
var damageBallSpawnTicks = 0;
var inChasePhase = false;
// --- Tap to Start Overlay & Villain Dialog Control ---
// (Removed tap-to-start overlay and tap logic. Game/dialog starts immediately.)
var gameStarted = true;
// Control for villain dialog per level (no tap-to-start)
var waitingForTap = false;
var pendingVillainText = null;
var pendingVillainState = null;
// Helper to show villain dialog (no tap-to-start overlay)
function showVillainAndWait(text, nextState) {
	// Show villain dialog
	showVillainBubble(text);
	waitingForTap = false;
	pendingVillainText = text;
	pendingVillainState = nextState;
	gameStarted = true;
}
// --- UI Elements ---
// Score Text
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives Text
var livesTxt = new Text2('❤ 3', {
	size: 90,
	fill: 0xFF5252
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
// --- Player Ball Setup ---
playerBall = new PlayerBall();
game.addChild(playerBall);
// Start at bottom center, above the bottom edge
playerBall.x = 2048 / 2;
playerBall.y = 2732 - 220;
// --- Drag Handling ---
function handleMove(x, y, obj) {
	if (dragNode) {
		// Clamp to game area (keep ball fully visible)
		var r = playerBall.ball.width / 2;
		var minX = r,
			maxX = 2048 - r;
		var minY = r,
			maxY = 2732 - r;
		dragNode.x = Math.max(minX, Math.min(maxX, x));
		dragNode.y = Math.max(minY, Math.min(maxY, y));
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Only start drag if touch/click is on the player ball
	var dx = x - playerBall.x;
	var dy = y - playerBall.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist <= playerBall.ball.width / 2) {
		dragNode = playerBall;
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// --- Enemy Spawning ---
function spawnEnemy() {
	var enemy = new EnemyBall();
	// Random X within game area, keeping ball fully visible
	var r = enemy.ball.width / 2;
	enemy.x = Math.random() * (2048 - 2 * r) + r;
	enemy.y = -r - 10; // Start just above the screen
	enemy.speed = enemySpeed + Math.random() * 2; // Add a bit of speed variation
	enemyBalls.push(enemy);
	game.addChild(enemy);
}
// --- Story & Level State ---
var villainState = 0; // 0: intro, 1: after 50, 2: after 100, 3: after 250 (win)
var villainBubble = null;
var villainTimeout = null;
var villainShowTicks = 0;
var villainShowDuration = 180; // 3 seconds at 60fps
function showVillainBubble(text) {
	// Remove previous if exists
	if (villainBubble && villainBubble.parent) villainBubble.parent.removeChild(villainBubble);
	villainBubble = new Container();
	// Villain face (red ball)
	var face = LK.getAsset('enemyBall', {
		anchorX: 0.5,
		anchorY: 1
	});
	face.x = 0;
	face.y = 0;
	villainBubble.addChild(face);
	// Speech bubble (white rounded box)
	var bubble = new Container();
	var bubbleShape = LK.getAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 2.5,
		scaleY: 1.2
	});
	bubbleShape.tint = 0xffffff;
	bubbleShape.alpha = 0.92;
	bubble.addChild(bubbleShape);
	// Text (English, white)
	var txt = new Text2(text, {
		size: 80,
		fill: 0xffffff,
		font: "Arial, Helvetica, sans-serif"
	});
	txt.anchor.set(0.5, 0.5);
	bubble.addChild(txt);
	bubble.x = 0;
	bubble.y = -180;
	villainBubble.addChild(bubble);
	// Position villainBubble at top center, but lower for readability
	villainBubble.x = 2048 / 2;
	villainBubble.y = 520; // moved down from 320 to 520
	game.addChild(villainBubble);
	villainShowTicks = 0;
}
function removeVillainBubble() {
	if (villainBubble && villainBubble.parent) villainBubble.parent.removeChild(villainBubble);
	villainBubble = null;
	villainShowTicks = 0;
}
// --- Game Update Loop ---
game.update = function () {
	// --- Villain Dialog Logic ---
	if (villainBubble) {
		villainShowTicks++;
		if (villainShowTicks > villainShowDuration) {
			removeVillainBubble();
		}
	}
	// --- Level/Story Progression ---
	// At each story point, show villain and advance automatically
	if (villainState === 0 && LK.ticks < 10) {
		showVillainAndWait("I will destroy the world!", 1);
		villainState = 0.25;
	}
	if (villainState === 0.25) {
		// Remove villain bubble after duration, then advance
		if (!villainBubble) {
			villainState = 1;
		}
	}
	if (villainState === 1 && score >= 50) {
		showVillainAndWait("You're finished now!", 2);
		// Speed up balls
		spawnInterval = Math.max(30, spawnInterval - 18);
		enemySpeed += 3.5;
		villainState = 1.25;
	}
	if (villainState === 1.25) {
		if (!villainBubble) {
			villainState = 2;
		}
	}
	if (villainState === 2 && score >= 100) {
		showVillainAndWait("Enough!", 3);
		// Balls get much faster
		spawnInterval = Math.max(18, spawnInterval - 10);
		enemySpeed += 4.5;
		villainState = 2.25;
	}
	if (villainState === 2.25) {
		if (!villainBubble) {
			villainState = 3;
		}
	}
	if (villainState === 3 && score >= 250) {
		showVillainAndWait("Stop right there!", 4);
		villainState = 3.25;
		// Freeze all enemies, but allow player to move
		for (var i = 0; i < enemyBalls.length; i++) {
			enemyBalls[i].frozen = true;
		}
		// Prevent new enemies from spawning
		freezeEnemies = true;
		freezeTicks = LK.ticks;
		chasePhaseStarted = false;
	}
	if (villainState === 3.25) {
		if (!villainBubble && !chasePhaseStarted) {
			// After villain dialog, wait 10 seconds, then start chase
			LK.setTimeout(function () {
				showVillainAndWait("Taste this!", 5);
				// After dialog, spawn boss and damage balls
				LK.setTimeout(function () {
					startChasePhase();
				}, villainShowDuration * 16.7); // villainShowDuration is in ticks, convert to ms
			}, 10000);
			chasePhaseStarted = true;
		}
		// Do not advance villainState until chase phase is started
	}
	// --- Enemy Spawning ---
	if (!freezeEnemies && !inChasePhase) {
		ticksSinceLastSpawn++;
		if (ticksSinceLastSpawn >= spawnInterval) {
			spawnEnemy();
			ticksSinceLastSpawn = 0;
		}
	}
	// --- Difficulty Scaling ---
	if (!freezeEnemies && !inChasePhase) {
		// Every 600 ticks (~10 seconds), increase difficulty
		if (LK.ticks % 600 === 0 && LK.ticks > 0) {
			if (spawnInterval > 30) spawnInterval -= 8; // Faster spawns
			if (enemySpeed < 22) enemySpeed += 1.2; // Faster enemies
		}
	}
	// --- Update Enemies ---
	for (var i = enemyBalls.length - 1; i >= 0; i--) {
		var enemy = enemyBalls[i];
		if (!enemy.frozen) {
			enemy.update();
		}
		// Check collision with player
		var collides = enemy.intersects(playerBall);
		if (collides && !enemy.frozen) {
			// Remove enemy
			enemy.destroy();
			enemyBalls.splice(i, 1);
			// Lose a life
			lives--;
			livesTxt.setText('❤ ' + lives);
			// Flash player ball
			LK.effects.flashObject(playerBall, 0xff0000, 400);
			// Game over if no lives left
			if (lives <= 0 && !lastGameOver) {
				lastGameOver = true;
				LK.effects.flashScreen(0xff0000, 800);
				LK.showGameOver();
				return;
			}
			continue;
		}
		// Remove if off screen
		if (enemy.y - enemy.ball.height / 2 > 2732 + 40) {
			enemy.destroy();
			enemyBalls.splice(i, 1);
			// Score for dodging
			score++;
			scoreTxt.setText(score + '');
		}
	}
	// --- Boss Chase Phase ---
	if (inChasePhase && boss) {
		boss.update();
		// Check collision with player (lose instantly)
		if (boss.intersects(playerBall) && !lastGameOver) {
			lastGameOver = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showGameOver();
			return;
		}
		// Update damage balls
		for (var j = damageBalls.length - 1; j >= 0; j--) {
			var dball = damageBalls[j];
			dball.update();
			// If player collects damage ball
			if (dball.intersects(playerBall)) {
				// Remove damage ball
				dball.destroy();
				damageBalls.splice(j, 1);
				// Deal 20 damage to boss
				bossHealth -= 20;
				if (bossHealth < 0) bossHealth = 0;
				if (bossHealthTxt) bossHealthTxt.setText("Boss: " + bossHealth);
				// Flash boss
				LK.effects.flashObject(boss, 0xffe600, 400);
				// If boss defeated, start second boss phase
				if (bossHealth <= 0 && !inSecondBossPhase) {
					// Remove first boss and health bar
					if (boss && boss.parent) boss.parent.removeChild(boss);
					boss = null;
					if (bossHealthTxt && bossHealthTxt.parent) bossHealthTxt.parent.removeChild(bossHealthTxt);
					bossHealthTxt = null;
					// Remove all damage balls
					for (var k = 0; k < damageBalls.length; k++) {
						damageBalls[k].destroy();
					}
					damageBalls = [];
					inChasePhase = false;
					// Villain dialog: "How is this possible?!"
					showVillainAndWait("How is this possible?!", 100);
					villainState = 99.5;
					inSecondBossPhase = true;
					// After dialog, start second boss attack after 2 seconds
					LK.setTimeout(function () {
						showVillainAndWait("Now face me!", 101);
						LK.setTimeout(function () {
							// Spawn second boss
							secondBoss = new Boss();
							secondBossHealth = 1000;
							secondBoss.speed = 13; // faster and angrier
							secondBoss.targetY = 700;
							secondBoss.bossFace.tint = 0xff2222; // visually more angry
							game.addChild(secondBoss);
							// Show second boss health bar
							if (secondBossHealthTxt && secondBossHealthTxt.parent) secondBossHealthTxt.parent.removeChild(secondBossHealthTxt);
							secondBossHealthTxt = new Text2("Villain: " + secondBossHealth, {
								size: 90,
								fill: 0xffe600,
								font: "Arial, Helvetica, sans-serif"
							});
							secondBossHealthTxt.anchor.set(0.5, 0);
							secondBossHealthTxt.x = 2048 / 2;
							secondBossHealthTxt.y = 220; // below score and first boss bar
							LK.gui.top.addChild(secondBossHealthTxt);
							// Reset second boss damage balls
							for (var m = 0; m < secondBossDamageBalls.length; m++) {
								secondBossDamageBalls[m].destroy();
							}
							secondBossDamageBalls = [];
							secondBossDamageBallSpawnTicks = 0;
						}, villainShowDuration * 16.7);
					}, 2000);
					return;
				}
			}
			// Remove if off screen
			if (dball.y > 2732 + 80) {
				dball.destroy();
				damageBalls.splice(j, 1);
			}
		}
		// Spawn damage balls every 90 ticks
		damageBallSpawnTicks++;
		if (damageBallSpawnTicks >= 90) {
			spawnDamageBall();
			damageBallSpawnTicks = 0;
		}
	}
	// --- Second Boss Phase ---
	if (inSecondBossPhase && secondBoss) {
		secondBoss.update();
		// If villain collides with player, game over
		if (secondBoss.intersects(playerBall) && !lastGameOver) {
			lastGameOver = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showGameOver();
			return;
		}
		// Update second boss damage balls
		for (var n = secondBossDamageBalls.length - 1; n >= 0; n--) {
			var sdball = secondBossDamageBalls[n];
			sdball.update();
			// If player collects damage ball
			if (sdball.intersects(playerBall)) {
				sdball.destroy();
				secondBossDamageBalls.splice(n, 1);
				// Deal 50 damage to second boss
				secondBossHealth -= 50;
				if (secondBossHealth < 0) secondBossHealth = 0;
				if (secondBossHealthTxt) secondBossHealthTxt.setText("Villain: " + secondBossHealth);
				LK.effects.flashObject(secondBoss, 0xffe600, 400);
				// If second boss defeated
				if (secondBossHealth <= 0 && !lastGameOver) {
					lastGameOver = true;
					// Boss explosion effect
					if (secondBoss && secondBoss.parent) {
						// Create a quick yellow flash and scale up for explosion
						// Use tween.to for boss explosion
						tween.to(secondBoss, {
							scaleX: 3.5,
							scaleY: 3.5,
							alpha: 0
						}, 700, {
							easing: "easeOutCubic"
						});
						LK.effects.flashObject(secondBoss, 0xffe600, 400);
						LK.setTimeout(function () {
							if (secondBoss && secondBoss.parent) secondBoss.parent.removeChild(secondBoss);
						}, 700);
					} else if (secondBoss && !secondBoss.parent) {
						// fallback
						secondBoss = null;
					}
					if (secondBossHealthTxt && secondBossHealthTxt.parent) secondBossHealthTxt.parent.removeChild(secondBossHealthTxt);
					// Remove all second boss damage balls
					for (var p = 0; p < secondBossDamageBalls.length; p++) {
						secondBossDamageBalls[p].destroy();
					}
					secondBossDamageBalls = [];
					// Final villain dialog: "No! How could you?!"
					showVillainAndWait("No! How could you?!", 200);
					// After dialog, show crowd rescue message
					LK.setTimeout(function () {
						// Remove villain bubble if still present
						removeVillainBubble();
						// Show crowd dialog at bottom of screen
						var crowdBubble = new Container();
						// Crowd "face" (use playerBall asset as a group icon)
						var crowdFace = LK.getAsset('playerBall', {
							anchorX: 0.5,
							anchorY: 1,
							scaleX: 1.5,
							scaleY: 1.5
						});
						crowdFace.x = 0;
						crowdFace.y = 0;
						crowdFace.tint = 0x4caf50; // green for hope
						crowdBubble.addChild(crowdFace);
						// Speech bubble (white, wide)
						var bubble = new Container();
						var bubbleShape = LK.getAsset('centerCircle', {
							anchorX: 0.5,
							anchorY: 0.5,
							scaleX: 3.2,
							scaleY: 1.3
						});
						bubbleShape.tint = 0xffffff;
						bubbleShape.alpha = 0.95;
						bubble.addChild(bubbleShape);
						// Text (English, green)
						var txt = new Text2("You saved us! Thank you, hero!", {
							size: 90,
							fill: 0x4caf50,
							font: "Arial, Helvetica, sans-serif"
						});
						txt.anchor.set(0.5, 0.5);
						bubble.addChild(txt);
						bubble.x = 0;
						bubble.y = -180;
						crowdBubble.addChild(bubble);
						// Position at bottom center
						crowdBubble.x = 2048 / 2;
						crowdBubble.y = 2732 - 220;
						game.addChild(crowdBubble);
						// Flash green for celebration
						LK.effects.flashScreen(0x00ff00, 800);
						// Remove crowd bubble and show win after 2.5s
						LK.setTimeout(function () {
							if (crowdBubble && crowdBubble.parent) crowdBubble.parent.removeChild(crowdBubble);
							LK.showYouWin();
						}, 2500);
					}, 1800 + 1200); // after villain dialog and a short pause
					return;
				}
			}
			// Remove if off screen
			if (sdball.y > 2732 + 80) {
				sdball.destroy();
				secondBossDamageBalls.splice(n, 1);
			}
		}
		// Spawn second boss damage balls every 60 ticks (faster)
		secondBossDamageBallSpawnTicks++;
		if (secondBossDamageBallSpawnTicks >= 60) {
			var sdb = new DamageBall();
			sdb.ball.tint = 0xffe600;
			secondBossDamageBalls.push(sdb);
			game.addChild(sdb);
			secondBossDamageBallSpawnTicks = 0;
		}
	}
};
// --- Reset Handler (for when game restarts) ---
game.on('destroy', function () {
	// Clean up
	for (var i = 0; i < enemyBalls.length; i++) {
		enemyBalls[i].destroy();
	}
	enemyBalls = [];
	// Remove boss if exists
	if (boss && boss.parent) boss.parent.removeChild(boss);
	boss = null;
	// Remove boss health text
	if (bossHealthTxt && bossHealthTxt.parent) bossHealthTxt.parent.removeChild(bossHealthTxt);
	bossHealthTxt = null;
	// Remove damage balls
	for (var j = 0; j < damageBalls.length; j++) {
		damageBalls[j].destroy();
	}
	damageBalls = [];
	inChasePhase = false;
	freezeEnemies = false;
	chasePhaseStarted = false;
	bossHealth = 500;
	damageBallSpawnTicks = 0;
	// Remove second boss and its UI
	if (secondBoss && secondBoss.parent) secondBoss.parent.removeChild(secondBoss);
	secondBoss = null;
	if (secondBossHealthTxt && secondBossHealthTxt.parent) secondBossHealthTxt.parent.removeChild(secondBossHealthTxt);
	secondBossHealthTxt = null;
	for (var q = 0; q < secondBossDamageBalls.length; q++) {
		secondBossDamageBalls[q].destroy();
	}
	secondBossDamageBalls = [];
	inSecondBossPhase = false;
	secondBossHealth = 1000;
	secondBossDamageBallSpawnTicks = 0;
	lives = 3;
	score = 0;
	spawnInterval = 80;
	enemySpeed = 6;
	ticksSinceLastSpawn = 0;
	lastGameOver = false;
	scoreTxt.setText('0');
	livesTxt.setText('❤ 3');
	// Reset player position
	playerBall.x = 2048 / 2;
	playerBall.y = 2732 - 220;
	// Reset gameStarted and villain state
	gameStarted = true;
	waitingForTap = false;
	pendingVillainText = null;
	pendingVillainState = null;
	villainState = 0;
	removeVillainBubble();
});