/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Energy Core (collectible)
var Core = Container.expand(function () {
	var self = Container.call(this);
	var coreSprite = self.attachAsset('core', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 6;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Enemy Robot
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemySprite = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 4 + Math.random() * 2;
	self.shootCooldown = 60 + Math.floor(Math.random() * 60); // frames
	self.update = function () {
		self.y += self.speed;
		self.shootCooldown--;
	};
	return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletSprite = self.attachAsset('enemyBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 13;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Player Mech
var Mech = Container.expand(function () {
	var self = Container.call(this);
	var mechSprite = self.attachAsset('mech', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.hp = 3;
	self.invincible = false;
	// For drag
	self.down = function (x, y, obj) {};
	self.up = function (x, y, obj) {};
	// Flash when hit
	self.flash = function () {
		if (self.invincible) return;
		self.invincible = true;
		tween(mechSprite, {
			alpha: 0.3
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(mechSprite, {
					alpha: 1
				}, {
					duration: 200,
					easing: tween.linear,
					onFinish: function onFinish() {
						self.invincible = false;
					}
				});
			}
		});
	};
	return self;
});
// Player Bullet
var MechBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletSprite = self.attachAsset('mechBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = -22;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Repair Node (objective)
var RepairNode = Container.expand(function () {
	var self = Container.call(this);
	var repairSprite = self.attachAsset('repair', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.repairing = false;
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181c2c
});
/**** 
* Game Code
****/ 
// Music
// Sound effects
// Bullet (enemy)
// Bullet (player)
// Repair node (for "repair" objective)
// Energy core collectible
// Enemy robot
// Mech (player)
// Play background music
LK.playMusic('mechaverse_bgm');
// Game state variables
var mech;
var enemies = [];
var mechBullets = [];
var enemyBullets = [];
var cores = [];
var repairNodes = [];
var dragNode = null;
var lastMechX = 0,
	lastMechY = 0;
var score = 0;
var coresCollected = 0;
var repairsDone = 0;
var hp = 3;
var gameOver = false;
var canShoot = true;
var shootCooldown = 0;
var level = 1;
var levelProgress = 0;
var levelTarget = 5; // Number of cores to collect or repairs to do per level
// GUI
var scoreTxt = new Text2('Cores: 0', {
	size: 90,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var hpTxt = new Text2('HP: 3', {
	size: 90,
	fill: 0xFF6B6B
});
hpTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(hpTxt);
var levelTxt = new Text2('Level 1', {
	size: 70,
	fill: 0xFFE066
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
// Place player mech at bottom center
mech = new Mech();
mech.x = 2048 / 2;
mech.y = 2732 - 350;
game.addChild(mech);
// Place first repair node (for variety, alternate between core and repair objectives)
function spawnRepairNode() {
	var node = new RepairNode();
	node.x = 2048 / 2;
	node.y = 600 + Math.random() * 600;
	repairNodes.push(node);
	game.addChild(node);
}
// Spawn an energy core at a random x
function spawnCore() {
	var core = new Core();
	core.x = 200 + Math.random() * (2048 - 400);
	core.y = -100;
	cores.push(core);
	game.addChild(core);
}
// Spawn an enemy at a random x
function spawnEnemy() {
	var enemy = new Enemy();
	enemy.x = 200 + Math.random() * (2048 - 400);
	enemy.y = -120;
	enemies.push(enemy);
	game.addChild(enemy);
}
// Fire a bullet from the mech
function fireMechBullet() {
	if (!canShoot) return;
	var bullet = new MechBullet();
	bullet.x = mech.x;
	bullet.y = mech.y - 120;
	mechBullets.push(bullet);
	game.addChild(bullet);
	canShoot = false;
	shootCooldown = 12;
	LK.getSound('shoot').play();
}
// Touch/drag controls
function handleMove(x, y, obj) {
	if (dragNode) {
		// Clamp to game area, avoid top 100px (menu)
		var nx = Math.max(100, Math.min(2048 - 100, x));
		var ny = Math.max(300, Math.min(2732 - 100, y));
		dragNode.x = nx;
		dragNode.y = ny;
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Only allow drag if touch is not in top left 100x100
	if (x < 100 && y < 100) return;
	dragNode = mech;
	handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// Tap to shoot (anywhere except top left)
game.tap = function (x, y, obj) {
	if (x < 100 && y < 100) return;
	fireMechBullet();
};
// For compatibility, also allow shooting on down if not dragging
game.down = function (x, y, obj) {
	if (x < 100 && y < 100) return;
	dragNode = mech;
	handleMove(x, y, obj);
	fireMechBullet();
};
// Main game update loop
game.update = function () {
	if (gameOver) return;
	// Cooldown for shooting
	if (!canShoot) {
		shootCooldown--;
		if (shootCooldown <= 0) {
			canShoot = true;
		}
	}
	// Spawn logic: enemies, cores, repair nodes
	if (level % 2 === 1) {
		// Odd levels: collect cores
		if (LK.ticks % Math.max(60, 120 - level * 10) === 0) {
			spawnCore();
		}
		if (LK.ticks % Math.max(90, 180 - level * 12) === 0) {
			spawnEnemy();
		}
	} else {
		// Even levels: repair nodes
		if (repairNodes.length === 0) {
			spawnRepairNode();
		}
		if (LK.ticks % Math.max(90, 180 - level * 12) === 0) {
			spawnEnemy();
		}
	}
	// Update enemies
	for (var i = enemies.length - 1; i >= 0; i--) {
		var enemy = enemies[i];
		enemy.update();
		// Enemy shoots
		if (enemy.shootCooldown <= 0 && enemy.y > 0) {
			var eb = new EnemyBullet();
			eb.x = enemy.x;
			eb.y = enemy.y + 80;
			enemyBullets.push(eb);
			game.addChild(eb);
			enemy.shootCooldown = 60 + Math.floor(Math.random() * 60);
		}
		// Remove if off screen
		if (enemy.y > 2732 + 100) {
			enemy.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Collision: enemy with mech
		if (!mech.invincible && enemy.intersects(mech)) {
			LK.getSound('hit').play();
			mech.flash();
			hp--;
			hpTxt.setText('HP: ' + hp);
			enemy.destroy();
			enemies.splice(i, 1);
			if (hp <= 0) {
				LK.effects.flashScreen(0xff0000, 1000);
				LK.showGameOver();
				gameOver = true;
				return;
			}
		}
	}
	// Update mech bullets
	for (var i = mechBullets.length - 1; i >= 0; i--) {
		var b = mechBullets[i];
		b.update();
		// Remove if off screen
		if (b.y < -60) {
			b.destroy();
			mechBullets.splice(i, 1);
			continue;
		}
		// Collision: bullet with enemy
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (b.intersects(enemy)) {
				LK.getSound('hit').play();
				enemy.destroy();
				enemies.splice(j, 1);
				b.destroy();
				mechBullets.splice(i, 1);
				break;
			}
		}
	}
	// Update enemy bullets
	for (var i = enemyBullets.length - 1; i >= 0; i--) {
		var eb = enemyBullets[i];
		eb.update();
		if (eb.y > 2732 + 60) {
			eb.destroy();
			enemyBullets.splice(i, 1);
			continue;
		}
		// Collision: enemy bullet with mech
		if (!mech.invincible && eb.intersects(mech)) {
			LK.getSound('hit').play();
			mech.flash();
			hp--;
			hpTxt.setText('HP: ' + hp);
			eb.destroy();
			enemyBullets.splice(i, 1);
			if (hp <= 0) {
				LK.effects.flashScreen(0xff0000, 1000);
				LK.showGameOver();
				gameOver = true;
				return;
			}
		}
	}
	// Update cores
	for (var i = cores.length - 1; i >= 0; i--) {
		var core = cores[i];
		core.update();
		if (core.y > 2732 + 60) {
			core.destroy();
			cores.splice(i, 1);
			continue;
		}
		// Collect core
		if (core.intersects(mech)) {
			LK.getSound('core').play();
			score++;
			coresCollected++;
			scoreTxt.setText('Cores: ' + coresCollected);
			core.destroy();
			cores.splice(i, 1);
			// Level up if enough cores
			if (coresCollected >= levelTarget) {
				level++;
				levelTxt.setText('Level ' + level);
				coresCollected = 0;
				repairsDone = 0;
				scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0');
				// Show win screen if level 5 reached
				if (level > 5) {
					LK.showYouWin();
					gameOver = true;
					return;
				}
			}
		}
	}
	// Update repair nodes
	for (var i = repairNodes.length - 1; i >= 0; i--) {
		var node = repairNodes[i];
		// "Repair" by holding mech over node for 1 second
		if (node.intersects(mech)) {
			if (!node.repairing) {
				node.repairing = true;
				tween(node, {
					scaleX: 1.3,
					scaleY: 1.3
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						LK.getSound('repair').play();
						repairsDone++;
						scoreTxt.setText('Repairs: ' + repairsDone);
						node.destroy();
						repairNodes.splice(i, 1);
						// Level up if enough repairs
						if (repairsDone >= levelTarget) {
							level++;
							levelTxt.setText('Level ' + level);
							coresCollected = 0;
							repairsDone = 0;
							scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0');
							if (level > 5) {
								LK.showYouWin();
								gameOver = true;
								return;
							}
						}
					}
				});
			}
		} else {
			if (node.repairing) {
				node.repairing = false;
				tween.stop(node, {
					scaleX: true,
					scaleY: true
				});
				node.scaleX = 1;
				node.scaleY = 1;
			}
		}
	}
};
// Fade in music at start
LK.playMusic('mechaverse_bgm', {
	fade: {
		start: 0,
		end: 0.7,
		duration: 1200
	}
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Energy Core (collectible)
var Core = Container.expand(function () {
	var self = Container.call(this);
	var coreSprite = self.attachAsset('core', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 6;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Enemy Robot
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemySprite = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 4 + Math.random() * 2;
	self.shootCooldown = 60 + Math.floor(Math.random() * 60); // frames
	self.update = function () {
		self.y += self.speed;
		self.shootCooldown--;
	};
	return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletSprite = self.attachAsset('enemyBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 13;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Player Mech
var Mech = Container.expand(function () {
	var self = Container.call(this);
	var mechSprite = self.attachAsset('mech', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.hp = 3;
	self.invincible = false;
	// For drag
	self.down = function (x, y, obj) {};
	self.up = function (x, y, obj) {};
	// Flash when hit
	self.flash = function () {
		if (self.invincible) return;
		self.invincible = true;
		tween(mechSprite, {
			alpha: 0.3
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(mechSprite, {
					alpha: 1
				}, {
					duration: 200,
					easing: tween.linear,
					onFinish: function onFinish() {
						self.invincible = false;
					}
				});
			}
		});
	};
	return self;
});
// Player Bullet
var MechBullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletSprite = self.attachAsset('mechBullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = -22;
	self.update = function () {
		self.y += self.speed;
	};
	return self;
});
// Repair Node (objective)
var RepairNode = Container.expand(function () {
	var self = Container.call(this);
	var repairSprite = self.attachAsset('repair', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.repairing = false;
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181c2c
});
/**** 
* Game Code
****/ 
// Music
// Sound effects
// Bullet (enemy)
// Bullet (player)
// Repair node (for "repair" objective)
// Energy core collectible
// Enemy robot
// Mech (player)
// Play background music
LK.playMusic('mechaverse_bgm');
// Game state variables
var mech;
var enemies = [];
var mechBullets = [];
var enemyBullets = [];
var cores = [];
var repairNodes = [];
var dragNode = null;
var lastMechX = 0,
	lastMechY = 0;
var score = 0;
var coresCollected = 0;
var repairsDone = 0;
var hp = 3;
var gameOver = false;
var canShoot = true;
var shootCooldown = 0;
var level = 1;
var levelProgress = 0;
var levelTarget = 5; // Number of cores to collect or repairs to do per level
// GUI
var scoreTxt = new Text2('Cores: 0', {
	size: 90,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var hpTxt = new Text2('HP: 3', {
	size: 90,
	fill: 0xFF6B6B
});
hpTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(hpTxt);
var levelTxt = new Text2('Level 1', {
	size: 70,
	fill: 0xFFE066
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
// Place player mech at bottom center
mech = new Mech();
mech.x = 2048 / 2;
mech.y = 2732 - 350;
game.addChild(mech);
// Place first repair node (for variety, alternate between core and repair objectives)
function spawnRepairNode() {
	var node = new RepairNode();
	node.x = 2048 / 2;
	node.y = 600 + Math.random() * 600;
	repairNodes.push(node);
	game.addChild(node);
}
// Spawn an energy core at a random x
function spawnCore() {
	var core = new Core();
	core.x = 200 + Math.random() * (2048 - 400);
	core.y = -100;
	cores.push(core);
	game.addChild(core);
}
// Spawn an enemy at a random x
function spawnEnemy() {
	var enemy = new Enemy();
	enemy.x = 200 + Math.random() * (2048 - 400);
	enemy.y = -120;
	enemies.push(enemy);
	game.addChild(enemy);
}
// Fire a bullet from the mech
function fireMechBullet() {
	if (!canShoot) return;
	var bullet = new MechBullet();
	bullet.x = mech.x;
	bullet.y = mech.y - 120;
	mechBullets.push(bullet);
	game.addChild(bullet);
	canShoot = false;
	shootCooldown = 12;
	LK.getSound('shoot').play();
}
// Touch/drag controls
function handleMove(x, y, obj) {
	if (dragNode) {
		// Clamp to game area, avoid top 100px (menu)
		var nx = Math.max(100, Math.min(2048 - 100, x));
		var ny = Math.max(300, Math.min(2732 - 100, y));
		dragNode.x = nx;
		dragNode.y = ny;
	}
}
game.move = handleMove;
game.down = function (x, y, obj) {
	// Only allow drag if touch is not in top left 100x100
	if (x < 100 && y < 100) return;
	dragNode = mech;
	handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// Tap to shoot (anywhere except top left)
game.tap = function (x, y, obj) {
	if (x < 100 && y < 100) return;
	fireMechBullet();
};
// For compatibility, also allow shooting on down if not dragging
game.down = function (x, y, obj) {
	if (x < 100 && y < 100) return;
	dragNode = mech;
	handleMove(x, y, obj);
	fireMechBullet();
};
// Main game update loop
game.update = function () {
	if (gameOver) return;
	// Cooldown for shooting
	if (!canShoot) {
		shootCooldown--;
		if (shootCooldown <= 0) {
			canShoot = true;
		}
	}
	// Spawn logic: enemies, cores, repair nodes
	if (level % 2 === 1) {
		// Odd levels: collect cores
		if (LK.ticks % Math.max(60, 120 - level * 10) === 0) {
			spawnCore();
		}
		if (LK.ticks % Math.max(90, 180 - level * 12) === 0) {
			spawnEnemy();
		}
	} else {
		// Even levels: repair nodes
		if (repairNodes.length === 0) {
			spawnRepairNode();
		}
		if (LK.ticks % Math.max(90, 180 - level * 12) === 0) {
			spawnEnemy();
		}
	}
	// Update enemies
	for (var i = enemies.length - 1; i >= 0; i--) {
		var enemy = enemies[i];
		enemy.update();
		// Enemy shoots
		if (enemy.shootCooldown <= 0 && enemy.y > 0) {
			var eb = new EnemyBullet();
			eb.x = enemy.x;
			eb.y = enemy.y + 80;
			enemyBullets.push(eb);
			game.addChild(eb);
			enemy.shootCooldown = 60 + Math.floor(Math.random() * 60);
		}
		// Remove if off screen
		if (enemy.y > 2732 + 100) {
			enemy.destroy();
			enemies.splice(i, 1);
			continue;
		}
		// Collision: enemy with mech
		if (!mech.invincible && enemy.intersects(mech)) {
			LK.getSound('hit').play();
			mech.flash();
			hp--;
			hpTxt.setText('HP: ' + hp);
			enemy.destroy();
			enemies.splice(i, 1);
			if (hp <= 0) {
				LK.effects.flashScreen(0xff0000, 1000);
				LK.showGameOver();
				gameOver = true;
				return;
			}
		}
	}
	// Update mech bullets
	for (var i = mechBullets.length - 1; i >= 0; i--) {
		var b = mechBullets[i];
		b.update();
		// Remove if off screen
		if (b.y < -60) {
			b.destroy();
			mechBullets.splice(i, 1);
			continue;
		}
		// Collision: bullet with enemy
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (b.intersects(enemy)) {
				LK.getSound('hit').play();
				enemy.destroy();
				enemies.splice(j, 1);
				b.destroy();
				mechBullets.splice(i, 1);
				break;
			}
		}
	}
	// Update enemy bullets
	for (var i = enemyBullets.length - 1; i >= 0; i--) {
		var eb = enemyBullets[i];
		eb.update();
		if (eb.y > 2732 + 60) {
			eb.destroy();
			enemyBullets.splice(i, 1);
			continue;
		}
		// Collision: enemy bullet with mech
		if (!mech.invincible && eb.intersects(mech)) {
			LK.getSound('hit').play();
			mech.flash();
			hp--;
			hpTxt.setText('HP: ' + hp);
			eb.destroy();
			enemyBullets.splice(i, 1);
			if (hp <= 0) {
				LK.effects.flashScreen(0xff0000, 1000);
				LK.showGameOver();
				gameOver = true;
				return;
			}
		}
	}
	// Update cores
	for (var i = cores.length - 1; i >= 0; i--) {
		var core = cores[i];
		core.update();
		if (core.y > 2732 + 60) {
			core.destroy();
			cores.splice(i, 1);
			continue;
		}
		// Collect core
		if (core.intersects(mech)) {
			LK.getSound('core').play();
			score++;
			coresCollected++;
			scoreTxt.setText('Cores: ' + coresCollected);
			core.destroy();
			cores.splice(i, 1);
			// Level up if enough cores
			if (coresCollected >= levelTarget) {
				level++;
				levelTxt.setText('Level ' + level);
				coresCollected = 0;
				repairsDone = 0;
				scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0');
				// Show win screen if level 5 reached
				if (level > 5) {
					LK.showYouWin();
					gameOver = true;
					return;
				}
			}
		}
	}
	// Update repair nodes
	for (var i = repairNodes.length - 1; i >= 0; i--) {
		var node = repairNodes[i];
		// "Repair" by holding mech over node for 1 second
		if (node.intersects(mech)) {
			if (!node.repairing) {
				node.repairing = true;
				tween(node, {
					scaleX: 1.3,
					scaleY: 1.3
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						LK.getSound('repair').play();
						repairsDone++;
						scoreTxt.setText('Repairs: ' + repairsDone);
						node.destroy();
						repairNodes.splice(i, 1);
						// Level up if enough repairs
						if (repairsDone >= levelTarget) {
							level++;
							levelTxt.setText('Level ' + level);
							coresCollected = 0;
							repairsDone = 0;
							scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0');
							if (level > 5) {
								LK.showYouWin();
								gameOver = true;
								return;
							}
						}
					}
				});
			}
		} else {
			if (node.repairing) {
				node.repairing = false;
				tween.stop(node, {
					scaleX: true,
					scaleY: true
				});
				node.scaleX = 1;
				node.scaleY = 1;
			}
		}
	}
};
// Fade in music at start
LK.playMusic('mechaverse_bgm', {
	fade: {
		start: 0,
		end: 0.7,
		duration: 1200
	}
});