/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Archer = Container.expand(function () { var self = Container.call(this); var archerGraphics = self.attachAsset('archer', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Arrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.update = function () { self.x += self.speedX; self.y += self.speedY; }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); self.health = 10; self.shootTimer = 0; self.shootRate = 60; // Faster shooting than regular enemies self.moveToNewPosition = function () { var newX = Math.random() * (2048 - 400) + 200; var newY = Math.random() * (2732 - 400) + 200; // Make sure boss doesn't spawn too close to archer var distToArcher = Math.sqrt(Math.pow(newX - archer.x, 2) + Math.pow(newY - archer.y, 2)); if (distToArcher < 300) { newX = Math.random() * (2048 - 600) + 300; if (newX > archer.x - 300 && newX < archer.x + 300) { newX += 400; } } // Animate movement to new position tween(self, { x: newX, y: newY }, { duration: 800, easing: tween.easeInOut }); }; self.update = function () { // Skip shooting if frozen if (freezeActive) { return; } self.shootTimer++; if (self.shootTimer >= self.shootRate) { self.shootTimer = 0; // Shoot at player var dirX = archer.x - self.x; var dirY = archer.y - self.y; var distance = Math.sqrt(dirX * dirX + dirY * dirY); var normalX = dirX / distance; var normalY = dirY / distance; // Make boss face the shooting direction self.rotation = Math.atan2(normalY, normalX); // Boss shoots 3 arrows at once for (var i = 0; i < 3; i++) { var spreadAngle = (i - 1) * 0.15; // Reduced from 0.3 to 0.15 for tighter spread var finalAngle = Math.atan2(normalY, normalX) + spreadAngle; var finalNormalX = Math.cos(finalAngle); var finalNormalY = Math.sin(finalAngle); var enemyArrow = new EnemyArrow(); enemyArrow.x = self.x; enemyArrow.y = self.y; enemyArrow.speedX = finalNormalX * 10; enemyArrow.speedY = finalNormalY * 10; enemyArrow.rotation = finalAngle; enemyArrows.push(enemyArrow); game.addChild(enemyArrow); } } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; // Small enemies have 2 health self.shootTimer = 0; self.shootRate = 120 + Math.random() * 60; // Random shooting interval // Create health display text self.healthTxt = new Text2(self.health.toString(), { size: 50, fill: 0xff0000 }); self.healthTxt.anchor.set(0.5, 1); self.addChild(self.healthTxt); self.healthTxt.y = -60; self.update = function () { // Enemies don't move, they stay in place and shoot // Skip shooting if frozen if (freezeActive) { return; } self.shootTimer++; if (self.shootTimer >= self.shootRate) { self.shootTimer = 0; // Shoot at player var dirX = archer.x - self.x; var dirY = archer.y - self.y; var distance = Math.sqrt(dirX * dirX + dirY * dirY); var normalX = dirX / distance; var normalY = dirY / distance; // Make enemy face the shooting direction self.rotation = Math.atan2(normalY, normalX); var enemyArrow = new EnemyArrow(); enemyArrow.x = self.x; enemyArrow.y = self.y; enemyArrow.speedX = normalX * 8; enemyArrow.speedY = normalY * 8; enemyArrow.rotation = Math.atan2(normalY, normalX); enemyArrows.push(enemyArrow); game.addChild(enemyArrow); } }; return self; }); var EnemyArrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('enemyArrow', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.update = function () { self.x += self.speedX; self.y += self.speedY; }; return self; }); var MiniBoss = Container.expand(function () { var self = Container.call(this); var miniBossGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, tint: 0x800080 }); self.health = 3; self.shootTimer = 0; self.shootRate = Math.max(10, 40 - (currentWave - 1) * 3); // Gets faster each wave, minimum 10 // Create health display text self.healthTxt = new Text2(self.health.toString(), { size: 60, fill: 0x800080 }); self.healthTxt.anchor.set(0.5, 1); self.addChild(self.healthTxt); self.healthTxt.y = -70; self.update = function () { // Skip shooting if frozen if (freezeActive) { return; } self.shootTimer++; if (self.shootTimer >= self.shootRate) { self.shootTimer = 0; // Shoot at player var dirX = archer.x - self.x; var dirY = archer.y - self.y; var distance = Math.sqrt(dirX * dirX + dirY * dirY); var normalX = dirX / distance; var normalY = dirY / distance; // Make enemy face the shooting direction self.rotation = Math.atan2(normalY, normalX); // Shoot 2 arrows at once for (var i = 0; i < 2; i++) { var spreadAngle = (i - 0.5) * 0.1; // Reduced from 0.2 to 0.1 for tighter spread var finalAngle = Math.atan2(normalY, normalX) + spreadAngle; var finalNormalX = Math.cos(finalAngle); var finalNormalY = Math.sin(finalAngle); var enemyArrow = new EnemyArrow(); enemyArrow.x = self.x; enemyArrow.y = self.y; enemyArrow.speedX = finalNormalX * 9; enemyArrow.speedY = finalNormalY * 9; enemyArrow.rotation = finalAngle; enemyArrows.push(enemyArrow); game.addChild(enemyArrow); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ var archer = game.addChild(new Archer()); archer.x = 150; archer.y = 2732 / 2; var arrows = []; var enemies = []; var miniBosses = []; var enemyArrows = []; var enemySpawnTimer = 0; var enemySpawnRate = 120; // frames between spawns var playerHealth = 10; var maxEnemies = 1; // Start with 1 enemy, increase over time var energy = 100; var energyRegenTimer = 0; var isShooting = false; var shootingTimer = 0; var money = storage.money || 0; var kills = storage.kills || 0; var shopVisible = false; var gamePaused = false; var energyUpgradeLevel = storage.energyUpgradeLevel || 0; var speedUpgradeLevel = storage.speedUpgradeLevel || 0; var damageUpgradeLevel = storage.damageUpgradeLevel || 0; var healthUpgradeLevel = storage.healthUpgradeLevel || 0; var rangeUpgradeLevel = storage.rangeUpgradeLevel || 0; var maxHealth = 10 + healthUpgradeLevel * 2; var shieldActive = false; var shieldTimer = 0; var freezeActive = false; var freezeTimer = 0; var explosiveActive = false; var explosiveTimer = 0; var doubleMoneyActive = false; var doubleMoneyTimer = 0; var moneyTxt = new Text2('Money: 0', { size: 100, fill: 0xFFD700 }); moneyTxt.anchor.set(0.5, 0); LK.gui.top.addChild(moneyTxt); moneyTxt.setText('Money: ' + money); var energyTxt = new Text2('Energy: 100', { size: 80, fill: 0x00ff00 }); energyTxt.anchor.set(1, 0); LK.gui.topRight.addChild(energyTxt); energyTxt.x = -20; energyTxt.y = 20; var healthTxt = new Text2('Health: 10', { size: 80, fill: 0xff0000 }); healthTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(healthTxt); healthTxt.x = 120; // Avoid the platform menu icon healthTxt.y = 20; var autoShootTimer = 0; var autoBattleActive = false; // Create hack mode button var autoBattleButton = new Text2('HACK MODE', { size: 80, fill: 0xff0000 }); autoBattleButton.anchor.set(0.5, 1); LK.gui.bottom.addChild(autoBattleButton); autoBattleButton.y = -50; // Button click handler autoBattleButton.down = function (x, y, obj) { autoBattleActive = !autoBattleActive; if (autoBattleActive) { autoBattleButton.setText('STOP HACK'); autoBattleButton.tint = 0x00ff00; // Green when active } else { autoBattleButton.setText('HACK MODE'); autoBattleButton.tint = 0xff0000; // Red when inactive } ; }; // Triple shoot variables var tripleShootActive = false; var tripleShootTimer = 0; var boss = null; var bossHealth = 10; var bossSpawnScore = Math.floor(Math.random() * 21) + 30; // Random between 30-50 kills var currentWave = 1; var bossesKilled = 0; var bossHealthTxt = new Text2('', { size: 80, fill: 0xff0000 }); bossHealthTxt.anchor.set(0.5, 1); bossHealthTxt.visible = false; game.addChild(bossHealthTxt); // Upgrade system variables var upgradeLevel = 0; // 0=normal, 1=triple, 2=octa, 3=16-arrow, 4=32-arrow, 5=64-arrow var upgradeNames = ['NORMAL', 'TRIPLE', 'OCTA', '16-ARROW', '32-ARROW', '64-ARROW']; var upgradeArrowCounts = [1, 3, 8, 16, 32, 64]; // Create cycling upgrade button var upgradeButton = new Text2('NORMAL', { size: 50, fill: 0x00ff00 }); upgradeButton.anchor.set(0.5, 1); LK.gui.bottom.addChild(upgradeButton); upgradeButton.y = -250; // Create reset button var resetButton = new Text2('RESET', { size: 60, fill: 0xff0000 }); resetButton.anchor.set(0.5, 1); LK.gui.bottom.addChild(resetButton); resetButton.x = -600; resetButton.y = -50; // Cycling button handler upgradeButton.down = function (x, y, obj) { upgradeLevel = (upgradeLevel + 1) % upgradeNames.length; upgradeButton.setText(upgradeNames[upgradeLevel]); // Update triple shoot active state based on upgrade level tripleShootActive = upgradeLevel > 0; }; // Reset button handler resetButton.down = function (x, y, obj) { // Reset all game variables to initial state money = 0; kills = 0; playerHealth = 10; energy = 100; energyUpgradeLevel = 0; speedUpgradeLevel = 0; damageUpgradeLevel = 0; healthUpgradeLevel = 0; rangeUpgradeLevel = 0; maxHealth = 10; currentWave = 1; bossesKilled = 0; bossSpawnScore = 200; maxEnemies = 1; enemySpawnRate = 120; // Reset power-up states shieldActive = false; shieldTimer = 0; freezeActive = false; freezeTimer = 0; explosiveActive = false; explosiveTimer = 0; doubleMoneyActive = false; doubleMoneyTimer = 0; superShieldActive = false; superShieldTimer = 0; timeSlowActive = false; timeSlowTimer = 0; tripleMoneyActive = false; tripleMoneyTimer = 0; // Reset upgrade system upgradeLevel = 0; tripleShootActive = false; // Reset auto battle autoBattleActive = false; autoBattleButton.setText('HACK MODE'); autoBattleButton.tint = 0xff0000; // Clear all game objects for (var i = arrows.length - 1; i >= 0; i--) { arrows[i].destroy(); arrows.splice(i, 1); } for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); enemies.splice(i, 1); } for (var i = miniBosses.length - 1; i >= 0; i--) { miniBosses[i].destroy(); miniBosses.splice(i, 1); } for (var i = enemyArrows.length - 1; i >= 0; i--) { enemyArrows[i].destroy(); enemyArrows.splice(i, 1); } // Clear boss if (boss) { boss.destroy(); boss = null; } // Remove hacker text if exists if (game.hackerText) { game.hackerText.destroy(); game.hackerText = null; } // Reset archer appearance archer.tint = 0xFFFFFF; archer.x = 150; archer.y = 2732 / 2; // Reset all timer displays shieldTimerTxt.visible = false; freezeTimerTxt.visible = false; explosiveTimerTxt.visible = false; doubleMoneyTimerTxt.visible = false; superShieldTimerTxt.visible = false; timeSlowTimerTxt.visible = false; tripleMoneyTimerTxt.visible = false; bossHealthTxt.visible = false; bossCountdownTxt.visible = false; // Update storage storage.money = money; storage.kills = kills; storage.energyUpgradeLevel = energyUpgradeLevel; storage.speedUpgradeLevel = speedUpgradeLevel; storage.damageUpgradeLevel = damageUpgradeLevel; storage.healthUpgradeLevel = healthUpgradeLevel; storage.rangeUpgradeLevel = rangeUpgradeLevel; // Update UI displays moneyTxt.setText('Money: ' + money); healthTxt.setText('Health: ' + playerHealth); energyTxt.setText('Energy: ' + energy); energyTxt.tint = 0x00ff00; waveTxt.setText('Wave: ' + currentWave); upgradeButton.setText('NORMAL'); // Close shop if open shopVisible = false; shopContainer.visible = false; gamePaused = false; }; // Shop UI elements var shopContainer = new Container(); var shopBackground = LK.getAsset('shop_bg', { width: 1400, height: 2000, color: 0x444444, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); shopContainer.addChild(shopBackground); var shopTitle = new Text2('SHOP', { size: 100, fill: 0xFFFFFF }); shopTitle.anchor.set(0.5, 0.5); shopTitle.y = -950; shopContainer.addChild(shopTitle); // Health Potion button var healthPotionBtn = new Text2('Health Potion (Cost: 30)', { size: 60, fill: 0xFF69B4 }); healthPotionBtn.anchor.set(0.5, 0.5); healthPotionBtn.y = -800; shopContainer.addChild(healthPotionBtn); // Shield button var shieldBtn = new Text2('Shield 30sec (Cost: 80)', { size: 60, fill: 0x4169E1 }); shieldBtn.anchor.set(0.5, 0.5); shieldBtn.y = -720; shopContainer.addChild(shieldBtn); // Freeze Enemies button var freezeBtn = new Text2('Freeze 10sec (Cost: 60)', { size: 60, fill: 0x00FFFF }); freezeBtn.anchor.set(0.5, 0.5); freezeBtn.y = -640; shopContainer.addChild(freezeBtn); // Explosive Arrows button var explosiveBtn = new Text2('Explosive 20sec (Cost: 120)', { size: 60, fill: 0xFF4500 }); explosiveBtn.anchor.set(0.5, 0.5); explosiveBtn.y = -560; shopContainer.addChild(explosiveBtn); // Double Money button var doubleMoneyBtn = new Text2('2x Money 60sec (Cost: 150)', { size: 60, fill: 0xFFD700 }); doubleMoneyBtn.anchor.set(0.5, 0.5); doubleMoneyBtn.y = -480; shopContainer.addChild(doubleMoneyBtn); // Energy Upgrade button var energyUpgradeBtn = new Text2('Energy +10 (Cost: 100)', { size: 60, fill: 0x00FF00 }); energyUpgradeBtn.anchor.set(0.5, 0.5); energyUpgradeBtn.y = -400; energyUpgradeBtn.x = -100; shopContainer.addChild(energyUpgradeBtn); // Energy Upgrade buy button var energyUpgradeBuyBtn = new Text2('BUY', { size: 70, fill: 0x00AA00 }); energyUpgradeBuyBtn.anchor.set(0.5, 0.5); energyUpgradeBuyBtn.y = -400; energyUpgradeBuyBtn.x = 200; shopContainer.addChild(energyUpgradeBuyBtn); // Speed Upgrade button var speedUpgradeBtn = new Text2('Speed +1 (Cost: 150)', { size: 60, fill: 0x00AAFF }); speedUpgradeBtn.anchor.set(0.5, 0.5); speedUpgradeBtn.y = -320; speedUpgradeBtn.x = -100; shopContainer.addChild(speedUpgradeBtn); // Max Energy Upgrade button // Speed Upgrade buy button var speedUpgradeBuyBtn = new Text2('BUY', { size: 70, fill: 0x0088CC }); speedUpgradeBuyBtn.anchor.set(0.5, 0.5); speedUpgradeBuyBtn.y = -320; speedUpgradeBuyBtn.x = 200; shopContainer.addChild(speedUpgradeBuyBtn); var maxEnergyUpgradeBtn = new Text2('Max Energy +20 (Cost: 300)', { size: 60, fill: 0x80FF00 }); maxEnergyUpgradeBtn.anchor.set(0.5, 0.5); maxEnergyUpgradeBtn.y = -240; maxEnergyUpgradeBtn.x = -100; shopContainer.addChild(maxEnergyUpgradeBtn); // Damage Upgrade button var damageUpgradeBtn = new Text2('Damage +1 (Cost: 200)', { size: 60, fill: 0xFF6600 }); damageUpgradeBtn.anchor.set(0.5, 0.5); damageUpgradeBtn.y = -160; damageUpgradeBtn.x = -100; shopContainer.addChild(damageUpgradeBtn); // Health Upgrade button // Max Energy Upgrade buy button var maxEnergyUpgradeBuyBtn = new Text2('BUY', { size: 70, fill: 0x66CC00 }); maxEnergyUpgradeBuyBtn.anchor.set(0.5, 0.5); maxEnergyUpgradeBuyBtn.y = -240; maxEnergyUpgradeBuyBtn.x = 200; shopContainer.addChild(maxEnergyUpgradeBuyBtn); var healthUpgradeBtn = new Text2('Max Health +2 (Cost: 250)', { size: 60, fill: 0xFF1493 }); healthUpgradeBtn.anchor.set(0.5, 0.5); healthUpgradeBtn.y = -80; healthUpgradeBtn.x = -100; shopContainer.addChild(healthUpgradeBtn); // Arrow Range Upgrade button // Damage Upgrade buy button var damageUpgradeBuyBtn = new Text2('BUY', { size: 70, fill: 0xCC4400 }); damageUpgradeBuyBtn.anchor.set(0.5, 0.5); damageUpgradeBuyBtn.y = -160; damageUpgradeBuyBtn.x = 200; shopContainer.addChild(damageUpgradeBuyBtn); // Health Upgrade buy button var healthUpgradeBuyBtn = new Text2('BUY', { size: 70, fill: 0xCC1077 }); healthUpgradeBuyBtn.anchor.set(0.5, 0.5); healthUpgradeBuyBtn.y = -80; healthUpgradeBuyBtn.x = 200; shopContainer.addChild(healthUpgradeBuyBtn); var rangeUpgradeBtn = new Text2('Arrow Range +20% (Cost: 180)', { size: 60, fill: 0x9932CC }); rangeUpgradeBtn.anchor.set(0.5, 0.5); rangeUpgradeBtn.y = 0; rangeUpgradeBtn.x = -100; shopContainer.addChild(rangeUpgradeBtn); // Range Upgrade buy button var rangeUpgradeBuyBtn = new Text2('BUY', { size: 70, fill: 0x7722AA }); rangeUpgradeBuyBtn.anchor.set(0.5, 0.5); rangeUpgradeBuyBtn.y = 0; rangeUpgradeBuyBtn.x = 200; shopContainer.addChild(rangeUpgradeBuyBtn); // Close shop button var closeShopBtn = new Text2('CLOSE', { size: 70, fill: 0xFF0000 }); closeShopBtn.anchor.set(0.5, 0.5); closeShopBtn.y = 120; shopContainer.addChild(closeShopBtn); shopContainer.x = 2048 / 2; shopContainer.y = 2732 / 2; shopContainer.visible = false; // Create shop button var shopButton = new Text2('SHOP', { size: 60, fill: 0xFFD700 }); shopButton.anchor.set(0.5, 1); LK.gui.bottom.addChild(shopButton); shopButton.x = -300; shopButton.y = -50; // Removed navigation button - all items now in main shop // Removed advanced shop variables - all items now in main shop // All shop items now in main shop - removed advanced shop container // Advanced shop power-up variables var superShieldActive = false; var superShieldTimer = 0; var timeSlowActive = false; var timeSlowTimer = 0; var tripleMoneyActive = false; var tripleMoneyTimer = 0; // Timer display texts for power-ups var shieldTimerTxt = new Text2('', { size: 60, fill: 0x4169E1 }); shieldTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(shieldTimerTxt); shieldTimerTxt.x = 120; shieldTimerTxt.y = 120; shieldTimerTxt.visible = false; var freezeTimerTxt = new Text2('', { size: 60, fill: 0x00FFFF }); freezeTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(freezeTimerTxt); freezeTimerTxt.x = 120; freezeTimerTxt.y = 180; freezeTimerTxt.visible = false; var explosiveTimerTxt = new Text2('', { size: 60, fill: 0xFF4500 }); explosiveTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(explosiveTimerTxt); explosiveTimerTxt.x = 120; explosiveTimerTxt.y = 240; explosiveTimerTxt.visible = false; var doubleMoneyTimerTxt = new Text2('', { size: 60, fill: 0xFFD700 }); doubleMoneyTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(doubleMoneyTimerTxt); doubleMoneyTimerTxt.x = 120; doubleMoneyTimerTxt.y = 300; doubleMoneyTimerTxt.visible = false; var superShieldTimerTxt = new Text2('', { size: 60, fill: 0x8000FF }); superShieldTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(superShieldTimerTxt); superShieldTimerTxt.x = 120; superShieldTimerTxt.y = 360; superShieldTimerTxt.visible = false; var timeSlowTimerTxt = new Text2('', { size: 60, fill: 0x80FF80 }); timeSlowTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(timeSlowTimerTxt); timeSlowTimerTxt.x = 120; timeSlowTimerTxt.y = 420; timeSlowTimerTxt.visible = false; var tripleMoneyTimerTxt = new Text2('', { size: 60, fill: 0xFFFF00 }); tripleMoneyTimerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(tripleMoneyTimerTxt); tripleMoneyTimerTxt.x = 120; tripleMoneyTimerTxt.y = 480; tripleMoneyTimerTxt.visible = false; // Boss countdown timer display var bossCountdownTxt = new Text2('', { size: 80, fill: 0xff8800 }); bossCountdownTxt.anchor.set(0.5, 0); LK.gui.top.addChild(bossCountdownTxt); bossCountdownTxt.y = 120; // Wave display var waveTxt = new Text2('Wave: 1', { size: 90, fill: 0x00ff88 }); waveTxt.anchor.set(0.5, 0); LK.gui.top.addChild(waveTxt); waveTxt.y = 200; // Shop button handler shopButton.down = function (x, y, obj) { shopVisible = true; shopContainer.visible = true; // Update upgrade button costs energyUpgradeBtn.setText('Energy +10 (Cost: ' + (100 + energyUpgradeLevel * 20) + ')'); speedUpgradeBtn.setText('Speed +1 (Cost: ' + (150 + speedUpgradeLevel * 30) + ')'); maxEnergyUpgradeBtn.setText('Max Energy +20 (Cost: ' + (300 + energyUpgradeLevel * 50) + ')'); damageUpgradeBtn.setText('Damage +1 (Cost: ' + (200 + damageUpgradeLevel * 40) + ')'); healthUpgradeBtn.setText('Max Health +2 (Cost: ' + (250 + healthUpgradeLevel * 50) + ')'); rangeUpgradeBtn.setText('Arrow Range +20% (Cost: ' + (180 + rangeUpgradeLevel * 35) + ')'); // Pause the game when shop opens gamePaused = true; // Clear all enemies when shop opens for (var e = enemies.length - 1; e >= 0; e--) { enemies[e].destroy(); enemies.splice(e, 1); } // Clear all mini bosses when shop opens for (var mb = miniBosses.length - 1; mb >= 0; mb--) { miniBosses[mb].destroy(); miniBosses.splice(mb, 1); } // Clear all enemy arrows when shop opens for (var a = enemyArrows.length - 1; a >= 0; a--) { enemyArrows[a].destroy(); enemyArrows.splice(a, 1); } // Clear boss when shop opens if (boss) { boss.destroy(); boss = null; } }; // Removed navigation handler - all items now in main shop // Add shop event handlers healthPotionBtn.down = function (x, y, obj) { if (money >= 30) { money -= 30; playerHealth += 3; if (playerHealth > maxHealth) playerHealth = maxHealth; storage.money = money; moneyTxt.setText('Money: ' + money); healthTxt.setText('Health: ' + playerHealth); } }; shieldBtn.down = function (x, y, obj) { if (money >= 80 && !shieldActive) { money -= 80; shieldActive = true; shieldTimer = 1800; // 30 seconds at 60 FPS storage.money = money; moneyTxt.setText('Money: ' + money); archer.tint = 0x4169E1; // Blue tint for shield } }; freezeBtn.down = function (x, y, obj) { if (money >= 60 && !freezeActive) { money -= 60; freezeActive = true; freezeTimer = 600; // 10 seconds at 60 FPS storage.money = money; moneyTxt.setText('Money: ' + money); } }; explosiveBtn.down = function (x, y, obj) { if (money >= 120 && !explosiveActive) { money -= 120; explosiveActive = true; explosiveTimer = 1200; // 20 seconds at 60 FPS storage.money = money; moneyTxt.setText('Money: ' + money); } ; }; doubleMoneyBtn.down = function (x, y, obj) { if (money >= 150 && !doubleMoneyActive) { money -= 150; doubleMoneyActive = true; doubleMoneyTimer = 3600; // 60 seconds at 60 FPS storage.money = money; moneyTxt.setText('Money: ' + money); } ; }; energyUpgradeBuyBtn.down = function (x, y, obj) { if (money >= 100 + energyUpgradeLevel * 20) { var cost = 100 + energyUpgradeLevel * 20; money -= cost; energyUpgradeLevel++; energy += 10; // Give immediate energy boost var maxEnergy = 100 + energyUpgradeLevel * 10; if (energy > maxEnergy) energy = maxEnergy; storage.money = money; storage.energyUpgradeLevel = energyUpgradeLevel; moneyTxt.setText('Money: ' + money); energyTxt.setText('Energy: ' + energy); energyUpgradeBtn.setText('Energy +10 (Cost: ' + (100 + energyUpgradeLevel * 20) + ')'); } }; // Speed upgrade handler speedUpgradeBuyBtn.down = function (x, y, obj) { var cost = 150 + speedUpgradeLevel * 30; if (money >= cost) { money -= cost; speedUpgradeLevel++; storage.money = money; storage.speedUpgradeLevel = speedUpgradeLevel; moneyTxt.setText('Money: ' + money); speedUpgradeBtn.setText('Speed +1 (Cost: ' + (150 + speedUpgradeLevel * 30) + ')'); } }; // Max energy upgrade handler maxEnergyUpgradeBuyBtn.down = function (x, y, obj) { var cost = 300 + energyUpgradeLevel * 50; if (money >= cost) { money -= cost; energyUpgradeLevel += 2; energy += 20; // Give immediate energy boost var maxEnergy = 100 + energyUpgradeLevel * 10; if (energy > maxEnergy) energy = maxEnergy; storage.money = money; storage.energyUpgradeLevel = energyUpgradeLevel; moneyTxt.setText('Money: ' + money); energyTxt.setText('Energy: ' + energy); maxEnergyUpgradeBtn.setText('Max Energy +20 (Cost: ' + (300 + energyUpgradeLevel * 50) + ')'); } }; // Damage upgrade handler damageUpgradeBuyBtn.down = function (x, y, obj) { var cost = 200 + damageUpgradeLevel * 40; if (money >= cost) { money -= cost; damageUpgradeLevel++; storage.money = money; storage.damageUpgradeLevel = damageUpgradeLevel; moneyTxt.setText('Money: ' + money); damageUpgradeBtn.setText('Damage +1 (Cost: ' + (200 + damageUpgradeLevel * 40) + ')'); } }; // Health upgrade handler healthUpgradeBuyBtn.down = function (x, y, obj) { var cost = 250 + healthUpgradeLevel * 50; if (money >= cost) { money -= cost; healthUpgradeLevel++; maxHealth = 10 + healthUpgradeLevel * 2; playerHealth += 2; // Give immediate health boost if (playerHealth > maxHealth) playerHealth = maxHealth; storage.money = money; storage.healthUpgradeLevel = healthUpgradeLevel; moneyTxt.setText('Money: ' + money); healthTxt.setText('Health: ' + playerHealth); healthUpgradeBtn.setText('Max Health +2 (Cost: ' + (250 + healthUpgradeLevel * 50) + ')'); } }; // Range upgrade handler rangeUpgradeBuyBtn.down = function (x, y, obj) { var cost = 180 + rangeUpgradeLevel * 35; if (money >= cost) { money -= cost; rangeUpgradeLevel++; storage.money = money; storage.rangeUpgradeLevel = rangeUpgradeLevel; moneyTxt.setText('Money: ' + money); rangeUpgradeBtn.setText('Arrow Range +20% (Cost: ' + (180 + rangeUpgradeLevel * 35) + ')'); } }; closeShopBtn.down = function (x, y, obj) { shopVisible = false; shopContainer.visible = false; // Resume the game when shop closes gamePaused = false; // Increase difficulty slightly each time shop closes if (maxEnemies < 8) { maxEnemies++; } if (enemySpawnRate > 20) { enemySpawnRate -= 2; } }; // Removed advanced shop event handlers - items moved to main shop game.addChild(shopContainer); // Manual shooting - touch screen to shoot game.down = function (x, y, obj) { // Only allow manual shooting when hack mode is not active if (!autoBattleActive && energy > 0) { // Convert touch position to game coordinates // Check if obj and obj.parent exist before calling toGlobal if (obj && obj.parent && obj.parent.toGlobal) { var gamePos = game.toLocal(obj.parent.toGlobal({ x: x, y: y })); shootArrowAtTarget(gamePos.x, gamePos.y); } else { // Fallback: use x, y directly as they should already be in the correct coordinate system shootArrowAtTarget(x, y); } } }; function shootArrowAtTarget(targetX, targetY) { // Check if player has enough energy if (energy <= 0) { return; } // Calculate direction from archer to target point var dirX = targetX - archer.x; var dirY = targetY - archer.y; var distance = Math.sqrt(dirX * dirX + dirY * dirY); // Normalize direction var normalX = dirX / distance; var normalY = dirY / distance; // Calculate base angle for arrow direction var baseAngle = Math.atan2(normalY, normalX); // Make archer face the shooting direction archer.rotation = baseAngle; // Fire arrows based on upgrade level var arrowCount = upgradeArrowCounts[upgradeLevel]; var energyCost = upgradeLevel === 0 ? 2 : upgradeLevel === 1 ? 6 : upgradeLevel === 2 ? 12 : upgradeLevel === 3 ? 20 : upgradeLevel === 4 ? 35 : 50; // Normal: 2, Triple: 6, Octa: 12, 16-Arrow: 20, 32-Arrow: 35, 64-Arrow: 50 // Check if we have enough energy for the shot type if (energy < energyCost) { return; } for (var i = 0; i < arrowCount; i++) { // Add spread based on upgrade level var spreadAngle = 0; if (upgradeLevel === 1) { // Triple shot spreadAngle = (i - 1) * 0.2; // -0.2, 0, 0.2 radians spread } else if (upgradeLevel === 2) { // Octa shot spreadAngle = (i - 3.5) * 0.15; // Spread 8 arrows in fan pattern } else if (upgradeLevel === 3) { // 16-arrow shot spreadAngle = (i - 7.5) * 0.12; // Spread 16 arrows in wide fan pattern } else if (upgradeLevel === 4) { // 32-arrow shot spreadAngle = (i - 15.5) * 0.10; // Spread 32 arrows in very wide fan pattern } else if (upgradeLevel === 5) { // 64-arrow shot spreadAngle = (i - 31.5) * 0.08; // Spread 64 arrows in extremely wide fan pattern } var finalAngle = baseAngle + spreadAngle; var finalNormalX = Math.cos(finalAngle); var finalNormalY = Math.sin(finalAngle); // Create arrow var newArrow = new Arrow(); newArrow.x = archer.x; newArrow.y = archer.y; var arrowSpeed = 15 + speedUpgradeLevel * 3; newArrow.speedX = finalNormalX * arrowSpeed; newArrow.speedY = finalNormalY * arrowSpeed; // Rotate arrow to face direction newArrow.rotation = finalAngle; arrows.push(newArrow); game.addChild(newArrow); } LK.getSound('shoot').play(); // Decrease energy energy -= energyCost; // Set shooting state isShooting = true; shootingTimer = 0; // Update energy display energyTxt.setText('Energy: ' + energy); // Change color based on energy level if (energy <= 20) { energyTxt.tint = 0xff0000; // Red when low } else if (energy <= 50) { energyTxt.tint = 0xffff00; // Yellow when medium } else { energyTxt.tint = 0x00ff00; // Green when high } } game.update = function () { // Skip all game logic when game is paused (shop is open) if (gamePaused) { return; } // Update power-up timers if (shieldActive) { shieldTimer--; var seconds = Math.ceil(shieldTimer / 60); shieldTimerTxt.setText('Shield: ' + seconds + 's'); shieldTimerTxt.visible = true; if (shieldTimer <= 0) { shieldActive = false; shieldTimerTxt.visible = false; if (!superShieldActive) { archer.tint = 0xFFFFFF; // Reset archer color only if super shield not active } } } if (superShieldActive) { superShieldTimer--; var seconds = Math.ceil(superShieldTimer / 60); superShieldTimerTxt.setText('Super Shield: ' + seconds + 's'); superShieldTimerTxt.visible = true; if (superShieldTimer <= 0) { superShieldActive = false; superShieldTimerTxt.visible = false; if (!shieldActive) { archer.tint = 0xFFFFFF; // Reset archer color only if regular shield not active } } } if (timeSlowActive) { timeSlowTimer--; var seconds = Math.ceil(timeSlowTimer / 60); timeSlowTimerTxt.setText('Time Slow: ' + seconds + 's'); timeSlowTimerTxt.visible = true; if (timeSlowTimer <= 0) { timeSlowActive = false; timeSlowTimerTxt.visible = false; } } if (tripleMoneyActive) { tripleMoneyTimer--; var seconds = Math.ceil(tripleMoneyTimer / 60); tripleMoneyTimerTxt.setText('3x Money: ' + seconds + 's'); tripleMoneyTimerTxt.visible = true; if (tripleMoneyTimer <= 0) { tripleMoneyActive = false; tripleMoneyTimerTxt.visible = false; } } if (freezeActive) { freezeTimer--; var seconds = Math.ceil(freezeTimer / 60); freezeTimerTxt.setText('Freeze: ' + seconds + 's'); freezeTimerTxt.visible = true; if (freezeTimer <= 0) { freezeActive = false; freezeTimerTxt.visible = false; } } if (explosiveActive) { explosiveTimer--; var seconds = Math.ceil(explosiveTimer / 60); explosiveTimerTxt.setText('Explosive: ' + seconds + 's'); explosiveTimerTxt.visible = true; if (explosiveTimer <= 0) { explosiveActive = false; explosiveTimerTxt.visible = false; } } if (doubleMoneyActive) { doubleMoneyTimer--; var seconds = Math.ceil(doubleMoneyTimer / 60); doubleMoneyTimerTxt.setText('2x Money: ' + seconds + 's'); doubleMoneyTimerTxt.visible = true; if (doubleMoneyTimer <= 0) { doubleMoneyActive = false; doubleMoneyTimerTxt.visible = false; } } // Automatic shooting logic - only when hack mode is active if (autoBattleActive) { autoShootTimer++; if (autoShootTimer >= 15) { // Shoot every 0.25 seconds (faster rate for hack mode) autoShootTimer = 0; // Shoot at boss first if present, then mini bosses, then regular enemies var targets = []; if (boss) { targets.push(boss); } for (var m = 0; m < miniBosses.length; m++) { if (miniBosses[m]) { targets.push(miniBosses[m]); } } for (var e = 0; e < enemies.length; e++) { if (enemies[e]) { targets.push(enemies[e]); } } for (var t = 0; t < targets.length; t++) { var target = targets[t]; // Calculate direction from archer to target var dirX = target.x - archer.x; var dirY = target.y - archer.y; var distance = Math.sqrt(dirX * dirX + dirY * dirY); // Normalize direction var normalX = dirX / distance; var normalY = dirY / distance; // Make archer face the shooting direction archer.rotation = Math.atan2(normalY, normalX); // Create arrow without energy cost var newArrow = new Arrow(); newArrow.x = archer.x; newArrow.y = archer.y; newArrow.speedX = normalX * 15; newArrow.speedY = normalY * 15; // Rotate arrow to face direction newArrow.rotation = Math.atan2(normalY, normalX); arrows.push(newArrow); game.addChild(newArrow); } // Play shoot sound if we shot any arrows if (targets.length > 0) { LK.getSound('shoot').play(); } } } // Update shooting timer if (isShooting) { shootingTimer++; if (shootingTimer >= 30) { // Stop shooting state after 0.5 seconds isShooting = false; } } // Update energy regeneration only when not shooting (every 60 frames = 1 second at 60 FPS) if (!isShooting) { energyRegenTimer++; if (energyRegenTimer >= 60) { energyRegenTimer = 0; var maxEnergy = 100 + energyUpgradeLevel * 10; if (energy < maxEnergy) { energy += 1; // Update energy display energyTxt.setText('Energy: ' + energy); // Change color based on energy level if (energy <= 20) { energyTxt.tint = 0xff0000; // Red when low } else if (energy <= 50) { energyTxt.tint = 0xffff00; // Yellow when medium } else { energyTxt.tint = 0x00ff00; // Green when high } } } } else { energyRegenTimer = 0; // Reset regen timer when shooting } // Spawn enemies randomly on screen when needed (only when no boss is active) if (!boss && enemies.length + miniBosses.length < maxEnemies) { enemySpawnTimer++; var currentSpawnRate = timeSlowActive ? enemySpawnRate * 2 : enemySpawnRate; if (enemySpawnTimer >= currentSpawnRate) { enemySpawnTimer = 0; // 30% chance to spawn mini boss, 70% chance for regular enemy var spawnMiniBoss = Math.random() < 0.3; if (spawnMiniBoss && miniBosses.length < 2) { // Spawn mini boss var newMiniBoss = new MiniBoss(); // Scale mini boss health with wave var baseHealth = 3; var waveHealthBonus = Math.floor((currentWave - 1) / 2); newMiniBoss.health = baseHealth + waveHealthBonus; newMiniBoss.healthTxt.setText(newMiniBoss.health.toString()); newMiniBoss.x = Math.random() * (2048 - 200) + 100; newMiniBoss.y = Math.random() * (2732 - 200) + 100; // Make sure mini boss doesn't spawn too close to archer var distToArcher = Math.sqrt(Math.pow(newMiniBoss.x - archer.x, 2) + Math.pow(newMiniBoss.y - archer.y, 2)); if (distToArcher < 200) { newMiniBoss.x = Math.random() * (2048 - 400) + 200; if (newMiniBoss.x > archer.x - 200 && newMiniBoss.x < archer.x + 200) { newMiniBoss.x += 300; } } miniBosses.push(newMiniBoss); game.addChild(newMiniBoss); } else { // Spawn regular enemy var newEnemy = new Enemy(); // Scale enemy health with wave var baseHealth = 2; var waveHealthBonus = Math.floor((currentWave - 1) / 2); newEnemy.health = baseHealth + waveHealthBonus; newEnemy.healthTxt.setText(newEnemy.health.toString()); newEnemy.x = Math.random() * (2048 - 200) + 100; newEnemy.y = Math.random() * (2732 - 200) + 100; // Make sure enemy doesn't spawn too close to archer var distToArcher = Math.sqrt(Math.pow(newEnemy.x - archer.x, 2) + Math.pow(newEnemy.y - archer.y, 2)); if (distToArcher < 200) { // Respawn farther away newEnemy.x = Math.random() * (2048 - 400) + 200; if (newEnemy.x > archer.x - 200 && newEnemy.x < archer.x + 200) { newEnemy.x += 300; } } enemies.push(newEnemy); game.addChild(newEnemy); } } } // Update arrows for (var i = arrows.length - 1; i >= 0; i--) { var arrow = arrows[i]; // Remove arrows that hit walls or go off screen if (arrow.x >= 2048 || arrow.x <= 0 || arrow.y >= 2732 || arrow.y <= 0) { arrow.destroy(); arrows.splice(i, 1); continue; } // Check arrow-enemy arrow collisions var arrowDestroyed = false; for (var k = enemyArrows.length - 1; k >= 0; k--) { var enemyArrow = enemyArrows[k]; if (arrow && enemyArrow && arrow.intersects(enemyArrow)) { // Both arrows destroy each other arrow.destroy(); arrows.splice(i, 1); enemyArrow.destroy(); enemyArrows.splice(k, 1); arrowDestroyed = true; break; } } // Skip enemy collision check if arrow was destroyed by enemy arrow if (arrowDestroyed) { continue; } // Check arrow-enemy collisions for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (enemy && arrow && arrow.intersects(enemy)) { // Hit enemy - reduce health enemy.health -= 1 + damageUpgradeLevel; enemy.healthTxt.setText(enemy.health.toString()); LK.getSound('hit').play(); LK.effects.flashObject(enemy, explosiveActive ? 0xFF4500 : 0xff0000, 200); // Check if enemy is defeated if (enemy.health <= 0) { // Give money with bonuses var moneyGain = tripleMoneyActive ? 15 : doubleMoneyActive ? 10 : 5; money += moneyGain; kills++; storage.money = money; storage.kills = kills; moneyTxt.setText('Money: ' + money); // Explosive arrows destroy nearby enemies if (explosiveActive) { for (var k = enemies.length - 1; k >= 0; k--) { if (k !== j && enemies[k]) { var dist = Math.sqrt(Math.pow(enemies[k].x - enemy.x, 2) + Math.pow(enemies[k].y - enemy.y, 2)); if (dist < 150) { // Explosion radius var bonusGain = tripleMoneyActive ? 15 : doubleMoneyActive ? 10 : 5; money += bonusGain; kills++; storage.money = money; storage.kills = kills; LK.effects.flashObject(enemies[k], 0xFF4500, 300); enemies[k].destroy(); enemies.splice(k, 1); if (k < j) j--; // Adjust index if we removed an enemy before current one } } } moneyTxt.setText('Money: ' + money); } // Remove enemy enemy.destroy(); enemies.splice(j, 1); } // Remove arrow arrow.destroy(); arrows.splice(i, 1); break; } } // Check arrow-mini boss collisions for (var mb = miniBosses.length - 1; mb >= 0; mb--) { var miniBoss = miniBosses[mb]; if (miniBoss && arrow && arrow.intersects(miniBoss)) { // Hit mini boss - reduce health miniBoss.health -= 1 + damageUpgradeLevel; miniBoss.healthTxt.setText(miniBoss.health.toString()); LK.getSound('hit').play(); LK.effects.flashObject(miniBoss, explosiveActive ? 0xFF4500 : 0x800080, 200); // Check if mini boss is defeated if (miniBoss.health <= 0) { // Give more money for mini boss var moneyGain = tripleMoneyActive ? 30 : doubleMoneyActive ? 20 : 10; money += moneyGain; kills += 3; // Mini boss counts as 3 kills storage.money = money; storage.kills = kills; moneyTxt.setText('Money: ' + money); // Explosive arrows destroy nearby enemies if (explosiveActive) { // Check explosion damage to regular enemies for (var k = enemies.length - 1; k >= 0; k--) { if (enemies[k]) { var dist = Math.sqrt(Math.pow(enemies[k].x - miniBoss.x, 2) + Math.pow(enemies[k].y - miniBoss.y, 2)); if (dist < 150) { var bonusGain = tripleMoneyActive ? 15 : doubleMoneyActive ? 10 : 5; money += bonusGain; kills++; storage.money = money; storage.kills = kills; LK.effects.flashObject(enemies[k], 0xFF4500, 300); enemies[k].destroy(); enemies.splice(k, 1); } } } // Check explosion damage to other mini bosses for (var k = miniBosses.length - 1; k >= 0; k--) { if (k !== mb && miniBosses[k]) { var dist = Math.sqrt(Math.pow(miniBosses[k].x - miniBoss.x, 2) + Math.pow(miniBosses[k].y - miniBoss.y, 2)); if (dist < 150) { miniBosses[k].health--; miniBosses[k].healthTxt.setText(miniBosses[k].health.toString()); LK.effects.flashObject(miniBosses[k], 0xFF4500, 300); if (miniBosses[k].health <= 0) { var bonusGain = tripleMoneyActive ? 30 : doubleMoneyActive ? 20 : 10; money += bonusGain; kills += 3; storage.money = money; storage.kills = kills; miniBosses[k].destroy(); miniBosses.splice(k, 1); if (k < mb) mb--; } } } } moneyTxt.setText('Money: ' + money); } // Remove mini boss miniBoss.destroy(); miniBosses.splice(mb, 1); } // Remove arrow arrow.destroy(); arrows.splice(i, 1); break; } } // Check arrow-boss collision if (boss && arrow && arrow.intersects(boss)) { // Hit boss boss.health--; LK.getSound('hit').play(); LK.effects.flashObject(boss, 0xff0000, 300); // Remove arrow arrow.destroy(); arrows.splice(i, 1); // Boss moves to new position when hit boss.moveToNewPosition(); // Check if boss is defeated if (boss.health <= 0) { money += 50; // Bonus money for defeating boss kills += 10; // Count boss as 10 kills bossesKilled++; currentWave++; // Increase difficulty with each wave maxEnemies = Math.min(10, 1 + Math.floor(currentWave / 2)); enemySpawnRate = Math.max(15, 120 - currentWave * 8); // Enemies get stronger each wave if (currentWave >= 3) { // Starting from wave 3, some enemies have more health var healthBonus = Math.floor((currentWave - 2) / 2); // This will be applied when spawning enemies } storage.money = money; storage.kills = kills; moneyTxt.setText('Money: ' + money); waveTxt.setText('Wave: ' + currentWave); boss.destroy(); boss = null; bossSpawnScore = kills + Math.floor(Math.random() * 21) + 30; // Next boss spawns after random 30-50 more kills } break; } } // Update enemy arrows for (var m = enemyArrows.length - 1; m >= 0; m--) { var enemyArrow = enemyArrows[m]; // Remove arrows that hit walls or go off screen if (enemyArrow.x >= 2048 || enemyArrow.x <= 0 || enemyArrow.y >= 2732 || enemyArrow.y <= 0) { enemyArrow.destroy(); enemyArrows.splice(m, 1); continue; } // Check if enemy arrow hits player if (enemyArrow.intersects(archer)) { if (!shieldActive && !superShieldActive) { playerHealth--; healthTxt.setText('Health: ' + playerHealth); LK.getSound('playerHit').play(); LK.effects.flashObject(archer, 0xff0000, 300); // Check if player is dead if (playerHealth <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } else { // Shield blocks the arrow var shieldColor = superShieldActive ? 0x8000FF : 0x4169E1; LK.effects.flashObject(archer, shieldColor, 200); } enemyArrow.destroy(); enemyArrows.splice(m, 1); continue; } } // Check if hack mode is active and score exceeds 200 to show HACKER text if (autoBattleActive && LK.getScore() > 200) { // Create red HACKER text if it doesn't exist if (!game.hackerText) { game.hackerText = new Text2('HACKER', { size: 200, fill: 0xff0000 }); game.hackerText.anchor.set(0.5, 0.5); game.hackerText.x = 2048 / 2; game.hackerText.y = 2732 / 2; game.addChild(game.hackerText); // Apply pulsing red glow effect tween(game.hackerText, { alpha: 0.3 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(game.hackerText, { alpha: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { // Restart the pulsing effect if (game.hackerText) { tween(game.hackerText, { alpha: 0.3 }, { duration: 500, easing: tween.easeInOut, onFinish: arguments.callee.caller }); } } }); } }); } } else if (game.hackerText) { // Remove HACKER text if conditions not met game.hackerText.destroy(); game.hackerText = null; } // Update boss health display if (boss) { bossHealthTxt.setText('Boss Health: ' + boss.health); bossHealthTxt.x = boss.x; bossHealthTxt.y = boss.y - 80; bossHealthTxt.visible = true; } else { bossHealthTxt.visible = false; } // Update boss countdown display if (boss === null) { var killsUntilBoss = bossSpawnScore - kills; if (killsUntilBoss > 0) { bossCountdownTxt.setText('Boss in: ' + killsUntilBoss + ' kills'); bossCountdownTxt.visible = true; } else { bossCountdownTxt.visible = false; } } else { bossCountdownTxt.visible = false; } // Spawn boss every 20 kills if (boss === null && kills >= bossSpawnScore) { // Clear all existing enemies when boss spawns for (var e = enemies.length - 1; e >= 0; e--) { enemies[e].destroy(); enemies.splice(e, 1); } // Clear all mini bosses when boss spawns for (var mb = miniBosses.length - 1; mb >= 0; mb--) { miniBosses[mb].destroy(); miniBosses.splice(mb, 1); } boss = new Boss(); boss.x = Math.random() * (2048 - 400) + 200; boss.y = Math.random() * (2732 - 400) + 200; // Make sure boss doesn't spawn too close to archer var distToArcher = Math.sqrt(Math.pow(boss.x - archer.x, 2) + Math.pow(boss.y - archer.y, 2)); if (distToArcher < 300) { boss.x = Math.random() * (2048 - 600) + 300; if (boss.x > archer.x - 300 && boss.x < archer.x + 300) { boss.x += 400; } } // Scale boss health with wave var baseHealth = 10; var waveHealthBonus = Math.floor((currentWave - 1) / 3) * 5; // +5 health every 3 waves boss.health = baseHealth + waveHealthBonus; game.addChild(boss); } // When enemy dies, increase max enemies and spawn rate for difficulty if (LK.getScore() > 0 && LK.getScore() % 50 === 0) { if (maxEnemies < 5) { maxEnemies++; } if (enemySpawnRate > 30) { enemySpawnRate -= 5; } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Archer = Container.expand(function () {
var self = Container.call(this);
var archerGraphics = self.attachAsset('archer', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Arrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.health = 10;
self.shootTimer = 0;
self.shootRate = 60; // Faster shooting than regular enemies
self.moveToNewPosition = function () {
var newX = Math.random() * (2048 - 400) + 200;
var newY = Math.random() * (2732 - 400) + 200;
// Make sure boss doesn't spawn too close to archer
var distToArcher = Math.sqrt(Math.pow(newX - archer.x, 2) + Math.pow(newY - archer.y, 2));
if (distToArcher < 300) {
newX = Math.random() * (2048 - 600) + 300;
if (newX > archer.x - 300 && newX < archer.x + 300) {
newX += 400;
}
}
// Animate movement to new position
tween(self, {
x: newX,
y: newY
}, {
duration: 800,
easing: tween.easeInOut
});
};
self.update = function () {
// Skip shooting if frozen
if (freezeActive) {
return;
}
self.shootTimer++;
if (self.shootTimer >= self.shootRate) {
self.shootTimer = 0;
// Shoot at player
var dirX = archer.x - self.x;
var dirY = archer.y - self.y;
var distance = Math.sqrt(dirX * dirX + dirY * dirY);
var normalX = dirX / distance;
var normalY = dirY / distance;
// Make boss face the shooting direction
self.rotation = Math.atan2(normalY, normalX);
// Boss shoots 3 arrows at once
for (var i = 0; i < 3; i++) {
var spreadAngle = (i - 1) * 0.15; // Reduced from 0.3 to 0.15 for tighter spread
var finalAngle = Math.atan2(normalY, normalX) + spreadAngle;
var finalNormalX = Math.cos(finalAngle);
var finalNormalY = Math.sin(finalAngle);
var enemyArrow = new EnemyArrow();
enemyArrow.x = self.x;
enemyArrow.y = self.y;
enemyArrow.speedX = finalNormalX * 10;
enemyArrow.speedY = finalNormalY * 10;
enemyArrow.rotation = finalAngle;
enemyArrows.push(enemyArrow);
game.addChild(enemyArrow);
}
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2; // Small enemies have 2 health
self.shootTimer = 0;
self.shootRate = 120 + Math.random() * 60; // Random shooting interval
// Create health display text
self.healthTxt = new Text2(self.health.toString(), {
size: 50,
fill: 0xff0000
});
self.healthTxt.anchor.set(0.5, 1);
self.addChild(self.healthTxt);
self.healthTxt.y = -60;
self.update = function () {
// Enemies don't move, they stay in place and shoot
// Skip shooting if frozen
if (freezeActive) {
return;
}
self.shootTimer++;
if (self.shootTimer >= self.shootRate) {
self.shootTimer = 0;
// Shoot at player
var dirX = archer.x - self.x;
var dirY = archer.y - self.y;
var distance = Math.sqrt(dirX * dirX + dirY * dirY);
var normalX = dirX / distance;
var normalY = dirY / distance;
// Make enemy face the shooting direction
self.rotation = Math.atan2(normalY, normalX);
var enemyArrow = new EnemyArrow();
enemyArrow.x = self.x;
enemyArrow.y = self.y;
enemyArrow.speedX = normalX * 8;
enemyArrow.speedY = normalY * 8;
enemyArrow.rotation = Math.atan2(normalY, normalX);
enemyArrows.push(enemyArrow);
game.addChild(enemyArrow);
}
};
return self;
});
var EnemyArrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('enemyArrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var MiniBoss = Container.expand(function () {
var self = Container.call(this);
var miniBossGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0x800080
});
self.health = 3;
self.shootTimer = 0;
self.shootRate = Math.max(10, 40 - (currentWave - 1) * 3); // Gets faster each wave, minimum 10
// Create health display text
self.healthTxt = new Text2(self.health.toString(), {
size: 60,
fill: 0x800080
});
self.healthTxt.anchor.set(0.5, 1);
self.addChild(self.healthTxt);
self.healthTxt.y = -70;
self.update = function () {
// Skip shooting if frozen
if (freezeActive) {
return;
}
self.shootTimer++;
if (self.shootTimer >= self.shootRate) {
self.shootTimer = 0;
// Shoot at player
var dirX = archer.x - self.x;
var dirY = archer.y - self.y;
var distance = Math.sqrt(dirX * dirX + dirY * dirY);
var normalX = dirX / distance;
var normalY = dirY / distance;
// Make enemy face the shooting direction
self.rotation = Math.atan2(normalY, normalX);
// Shoot 2 arrows at once
for (var i = 0; i < 2; i++) {
var spreadAngle = (i - 0.5) * 0.1; // Reduced from 0.2 to 0.1 for tighter spread
var finalAngle = Math.atan2(normalY, normalX) + spreadAngle;
var finalNormalX = Math.cos(finalAngle);
var finalNormalY = Math.sin(finalAngle);
var enemyArrow = new EnemyArrow();
enemyArrow.x = self.x;
enemyArrow.y = self.y;
enemyArrow.speedX = finalNormalX * 9;
enemyArrow.speedY = finalNormalY * 9;
enemyArrow.rotation = finalAngle;
enemyArrows.push(enemyArrow);
game.addChild(enemyArrow);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var archer = game.addChild(new Archer());
archer.x = 150;
archer.y = 2732 / 2;
var arrows = [];
var enemies = [];
var miniBosses = [];
var enemyArrows = [];
var enemySpawnTimer = 0;
var enemySpawnRate = 120; // frames between spawns
var playerHealth = 10;
var maxEnemies = 1; // Start with 1 enemy, increase over time
var energy = 100;
var energyRegenTimer = 0;
var isShooting = false;
var shootingTimer = 0;
var money = storage.money || 0;
var kills = storage.kills || 0;
var shopVisible = false;
var gamePaused = false;
var energyUpgradeLevel = storage.energyUpgradeLevel || 0;
var speedUpgradeLevel = storage.speedUpgradeLevel || 0;
var damageUpgradeLevel = storage.damageUpgradeLevel || 0;
var healthUpgradeLevel = storage.healthUpgradeLevel || 0;
var rangeUpgradeLevel = storage.rangeUpgradeLevel || 0;
var maxHealth = 10 + healthUpgradeLevel * 2;
var shieldActive = false;
var shieldTimer = 0;
var freezeActive = false;
var freezeTimer = 0;
var explosiveActive = false;
var explosiveTimer = 0;
var doubleMoneyActive = false;
var doubleMoneyTimer = 0;
var moneyTxt = new Text2('Money: 0', {
size: 100,
fill: 0xFFD700
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
moneyTxt.setText('Money: ' + money);
var energyTxt = new Text2('Energy: 100', {
size: 80,
fill: 0x00ff00
});
energyTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(energyTxt);
energyTxt.x = -20;
energyTxt.y = 20;
var healthTxt = new Text2('Health: 10', {
size: 80,
fill: 0xff0000
});
healthTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthTxt);
healthTxt.x = 120; // Avoid the platform menu icon
healthTxt.y = 20;
var autoShootTimer = 0;
var autoBattleActive = false;
// Create hack mode button
var autoBattleButton = new Text2('HACK MODE', {
size: 80,
fill: 0xff0000
});
autoBattleButton.anchor.set(0.5, 1);
LK.gui.bottom.addChild(autoBattleButton);
autoBattleButton.y = -50;
// Button click handler
autoBattleButton.down = function (x, y, obj) {
autoBattleActive = !autoBattleActive;
if (autoBattleActive) {
autoBattleButton.setText('STOP HACK');
autoBattleButton.tint = 0x00ff00; // Green when active
} else {
autoBattleButton.setText('HACK MODE');
autoBattleButton.tint = 0xff0000; // Red when inactive
}
;
};
// Triple shoot variables
var tripleShootActive = false;
var tripleShootTimer = 0;
var boss = null;
var bossHealth = 10;
var bossSpawnScore = Math.floor(Math.random() * 21) + 30; // Random between 30-50 kills
var currentWave = 1;
var bossesKilled = 0;
var bossHealthTxt = new Text2('', {
size: 80,
fill: 0xff0000
});
bossHealthTxt.anchor.set(0.5, 1);
bossHealthTxt.visible = false;
game.addChild(bossHealthTxt);
// Upgrade system variables
var upgradeLevel = 0; // 0=normal, 1=triple, 2=octa, 3=16-arrow, 4=32-arrow, 5=64-arrow
var upgradeNames = ['NORMAL', 'TRIPLE', 'OCTA', '16-ARROW', '32-ARROW', '64-ARROW'];
var upgradeArrowCounts = [1, 3, 8, 16, 32, 64];
// Create cycling upgrade button
var upgradeButton = new Text2('NORMAL', {
size: 50,
fill: 0x00ff00
});
upgradeButton.anchor.set(0.5, 1);
LK.gui.bottom.addChild(upgradeButton);
upgradeButton.y = -250;
// Create reset button
var resetButton = new Text2('RESET', {
size: 60,
fill: 0xff0000
});
resetButton.anchor.set(0.5, 1);
LK.gui.bottom.addChild(resetButton);
resetButton.x = -600;
resetButton.y = -50;
// Cycling button handler
upgradeButton.down = function (x, y, obj) {
upgradeLevel = (upgradeLevel + 1) % upgradeNames.length;
upgradeButton.setText(upgradeNames[upgradeLevel]);
// Update triple shoot active state based on upgrade level
tripleShootActive = upgradeLevel > 0;
};
// Reset button handler
resetButton.down = function (x, y, obj) {
// Reset all game variables to initial state
money = 0;
kills = 0;
playerHealth = 10;
energy = 100;
energyUpgradeLevel = 0;
speedUpgradeLevel = 0;
damageUpgradeLevel = 0;
healthUpgradeLevel = 0;
rangeUpgradeLevel = 0;
maxHealth = 10;
currentWave = 1;
bossesKilled = 0;
bossSpawnScore = 200;
maxEnemies = 1;
enemySpawnRate = 120;
// Reset power-up states
shieldActive = false;
shieldTimer = 0;
freezeActive = false;
freezeTimer = 0;
explosiveActive = false;
explosiveTimer = 0;
doubleMoneyActive = false;
doubleMoneyTimer = 0;
superShieldActive = false;
superShieldTimer = 0;
timeSlowActive = false;
timeSlowTimer = 0;
tripleMoneyActive = false;
tripleMoneyTimer = 0;
// Reset upgrade system
upgradeLevel = 0;
tripleShootActive = false;
// Reset auto battle
autoBattleActive = false;
autoBattleButton.setText('HACK MODE');
autoBattleButton.tint = 0xff0000;
// Clear all game objects
for (var i = arrows.length - 1; i >= 0; i--) {
arrows[i].destroy();
arrows.splice(i, 1);
}
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = miniBosses.length - 1; i >= 0; i--) {
miniBosses[i].destroy();
miniBosses.splice(i, 1);
}
for (var i = enemyArrows.length - 1; i >= 0; i--) {
enemyArrows[i].destroy();
enemyArrows.splice(i, 1);
}
// Clear boss
if (boss) {
boss.destroy();
boss = null;
}
// Remove hacker text if exists
if (game.hackerText) {
game.hackerText.destroy();
game.hackerText = null;
}
// Reset archer appearance
archer.tint = 0xFFFFFF;
archer.x = 150;
archer.y = 2732 / 2;
// Reset all timer displays
shieldTimerTxt.visible = false;
freezeTimerTxt.visible = false;
explosiveTimerTxt.visible = false;
doubleMoneyTimerTxt.visible = false;
superShieldTimerTxt.visible = false;
timeSlowTimerTxt.visible = false;
tripleMoneyTimerTxt.visible = false;
bossHealthTxt.visible = false;
bossCountdownTxt.visible = false;
// Update storage
storage.money = money;
storage.kills = kills;
storage.energyUpgradeLevel = energyUpgradeLevel;
storage.speedUpgradeLevel = speedUpgradeLevel;
storage.damageUpgradeLevel = damageUpgradeLevel;
storage.healthUpgradeLevel = healthUpgradeLevel;
storage.rangeUpgradeLevel = rangeUpgradeLevel;
// Update UI displays
moneyTxt.setText('Money: ' + money);
healthTxt.setText('Health: ' + playerHealth);
energyTxt.setText('Energy: ' + energy);
energyTxt.tint = 0x00ff00;
waveTxt.setText('Wave: ' + currentWave);
upgradeButton.setText('NORMAL');
// Close shop if open
shopVisible = false;
shopContainer.visible = false;
gamePaused = false;
};
// Shop UI elements
var shopContainer = new Container();
var shopBackground = LK.getAsset('shop_bg', {
width: 1400,
height: 2000,
color: 0x444444,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
shopContainer.addChild(shopBackground);
var shopTitle = new Text2('SHOP', {
size: 100,
fill: 0xFFFFFF
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.y = -950;
shopContainer.addChild(shopTitle);
// Health Potion button
var healthPotionBtn = new Text2('Health Potion (Cost: 30)', {
size: 60,
fill: 0xFF69B4
});
healthPotionBtn.anchor.set(0.5, 0.5);
healthPotionBtn.y = -800;
shopContainer.addChild(healthPotionBtn);
// Shield button
var shieldBtn = new Text2('Shield 30sec (Cost: 80)', {
size: 60,
fill: 0x4169E1
});
shieldBtn.anchor.set(0.5, 0.5);
shieldBtn.y = -720;
shopContainer.addChild(shieldBtn);
// Freeze Enemies button
var freezeBtn = new Text2('Freeze 10sec (Cost: 60)', {
size: 60,
fill: 0x00FFFF
});
freezeBtn.anchor.set(0.5, 0.5);
freezeBtn.y = -640;
shopContainer.addChild(freezeBtn);
// Explosive Arrows button
var explosiveBtn = new Text2('Explosive 20sec (Cost: 120)', {
size: 60,
fill: 0xFF4500
});
explosiveBtn.anchor.set(0.5, 0.5);
explosiveBtn.y = -560;
shopContainer.addChild(explosiveBtn);
// Double Money button
var doubleMoneyBtn = new Text2('2x Money 60sec (Cost: 150)', {
size: 60,
fill: 0xFFD700
});
doubleMoneyBtn.anchor.set(0.5, 0.5);
doubleMoneyBtn.y = -480;
shopContainer.addChild(doubleMoneyBtn);
// Energy Upgrade button
var energyUpgradeBtn = new Text2('Energy +10 (Cost: 100)', {
size: 60,
fill: 0x00FF00
});
energyUpgradeBtn.anchor.set(0.5, 0.5);
energyUpgradeBtn.y = -400;
energyUpgradeBtn.x = -100;
shopContainer.addChild(energyUpgradeBtn);
// Energy Upgrade buy button
var energyUpgradeBuyBtn = new Text2('BUY', {
size: 70,
fill: 0x00AA00
});
energyUpgradeBuyBtn.anchor.set(0.5, 0.5);
energyUpgradeBuyBtn.y = -400;
energyUpgradeBuyBtn.x = 200;
shopContainer.addChild(energyUpgradeBuyBtn);
// Speed Upgrade button
var speedUpgradeBtn = new Text2('Speed +1 (Cost: 150)', {
size: 60,
fill: 0x00AAFF
});
speedUpgradeBtn.anchor.set(0.5, 0.5);
speedUpgradeBtn.y = -320;
speedUpgradeBtn.x = -100;
shopContainer.addChild(speedUpgradeBtn);
// Max Energy Upgrade button
// Speed Upgrade buy button
var speedUpgradeBuyBtn = new Text2('BUY', {
size: 70,
fill: 0x0088CC
});
speedUpgradeBuyBtn.anchor.set(0.5, 0.5);
speedUpgradeBuyBtn.y = -320;
speedUpgradeBuyBtn.x = 200;
shopContainer.addChild(speedUpgradeBuyBtn);
var maxEnergyUpgradeBtn = new Text2('Max Energy +20 (Cost: 300)', {
size: 60,
fill: 0x80FF00
});
maxEnergyUpgradeBtn.anchor.set(0.5, 0.5);
maxEnergyUpgradeBtn.y = -240;
maxEnergyUpgradeBtn.x = -100;
shopContainer.addChild(maxEnergyUpgradeBtn);
// Damage Upgrade button
var damageUpgradeBtn = new Text2('Damage +1 (Cost: 200)', {
size: 60,
fill: 0xFF6600
});
damageUpgradeBtn.anchor.set(0.5, 0.5);
damageUpgradeBtn.y = -160;
damageUpgradeBtn.x = -100;
shopContainer.addChild(damageUpgradeBtn);
// Health Upgrade button
// Max Energy Upgrade buy button
var maxEnergyUpgradeBuyBtn = new Text2('BUY', {
size: 70,
fill: 0x66CC00
});
maxEnergyUpgradeBuyBtn.anchor.set(0.5, 0.5);
maxEnergyUpgradeBuyBtn.y = -240;
maxEnergyUpgradeBuyBtn.x = 200;
shopContainer.addChild(maxEnergyUpgradeBuyBtn);
var healthUpgradeBtn = new Text2('Max Health +2 (Cost: 250)', {
size: 60,
fill: 0xFF1493
});
healthUpgradeBtn.anchor.set(0.5, 0.5);
healthUpgradeBtn.y = -80;
healthUpgradeBtn.x = -100;
shopContainer.addChild(healthUpgradeBtn);
// Arrow Range Upgrade button
// Damage Upgrade buy button
var damageUpgradeBuyBtn = new Text2('BUY', {
size: 70,
fill: 0xCC4400
});
damageUpgradeBuyBtn.anchor.set(0.5, 0.5);
damageUpgradeBuyBtn.y = -160;
damageUpgradeBuyBtn.x = 200;
shopContainer.addChild(damageUpgradeBuyBtn);
// Health Upgrade buy button
var healthUpgradeBuyBtn = new Text2('BUY', {
size: 70,
fill: 0xCC1077
});
healthUpgradeBuyBtn.anchor.set(0.5, 0.5);
healthUpgradeBuyBtn.y = -80;
healthUpgradeBuyBtn.x = 200;
shopContainer.addChild(healthUpgradeBuyBtn);
var rangeUpgradeBtn = new Text2('Arrow Range +20% (Cost: 180)', {
size: 60,
fill: 0x9932CC
});
rangeUpgradeBtn.anchor.set(0.5, 0.5);
rangeUpgradeBtn.y = 0;
rangeUpgradeBtn.x = -100;
shopContainer.addChild(rangeUpgradeBtn);
// Range Upgrade buy button
var rangeUpgradeBuyBtn = new Text2('BUY', {
size: 70,
fill: 0x7722AA
});
rangeUpgradeBuyBtn.anchor.set(0.5, 0.5);
rangeUpgradeBuyBtn.y = 0;
rangeUpgradeBuyBtn.x = 200;
shopContainer.addChild(rangeUpgradeBuyBtn);
// Close shop button
var closeShopBtn = new Text2('CLOSE', {
size: 70,
fill: 0xFF0000
});
closeShopBtn.anchor.set(0.5, 0.5);
closeShopBtn.y = 120;
shopContainer.addChild(closeShopBtn);
shopContainer.x = 2048 / 2;
shopContainer.y = 2732 / 2;
shopContainer.visible = false;
// Create shop button
var shopButton = new Text2('SHOP', {
size: 60,
fill: 0xFFD700
});
shopButton.anchor.set(0.5, 1);
LK.gui.bottom.addChild(shopButton);
shopButton.x = -300;
shopButton.y = -50;
// Removed navigation button - all items now in main shop
// Removed advanced shop variables - all items now in main shop
// All shop items now in main shop - removed advanced shop container
// Advanced shop power-up variables
var superShieldActive = false;
var superShieldTimer = 0;
var timeSlowActive = false;
var timeSlowTimer = 0;
var tripleMoneyActive = false;
var tripleMoneyTimer = 0;
// Timer display texts for power-ups
var shieldTimerTxt = new Text2('', {
size: 60,
fill: 0x4169E1
});
shieldTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(shieldTimerTxt);
shieldTimerTxt.x = 120;
shieldTimerTxt.y = 120;
shieldTimerTxt.visible = false;
var freezeTimerTxt = new Text2('', {
size: 60,
fill: 0x00FFFF
});
freezeTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(freezeTimerTxt);
freezeTimerTxt.x = 120;
freezeTimerTxt.y = 180;
freezeTimerTxt.visible = false;
var explosiveTimerTxt = new Text2('', {
size: 60,
fill: 0xFF4500
});
explosiveTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(explosiveTimerTxt);
explosiveTimerTxt.x = 120;
explosiveTimerTxt.y = 240;
explosiveTimerTxt.visible = false;
var doubleMoneyTimerTxt = new Text2('', {
size: 60,
fill: 0xFFD700
});
doubleMoneyTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(doubleMoneyTimerTxt);
doubleMoneyTimerTxt.x = 120;
doubleMoneyTimerTxt.y = 300;
doubleMoneyTimerTxt.visible = false;
var superShieldTimerTxt = new Text2('', {
size: 60,
fill: 0x8000FF
});
superShieldTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(superShieldTimerTxt);
superShieldTimerTxt.x = 120;
superShieldTimerTxt.y = 360;
superShieldTimerTxt.visible = false;
var timeSlowTimerTxt = new Text2('', {
size: 60,
fill: 0x80FF80
});
timeSlowTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(timeSlowTimerTxt);
timeSlowTimerTxt.x = 120;
timeSlowTimerTxt.y = 420;
timeSlowTimerTxt.visible = false;
var tripleMoneyTimerTxt = new Text2('', {
size: 60,
fill: 0xFFFF00
});
tripleMoneyTimerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(tripleMoneyTimerTxt);
tripleMoneyTimerTxt.x = 120;
tripleMoneyTimerTxt.y = 480;
tripleMoneyTimerTxt.visible = false;
// Boss countdown timer display
var bossCountdownTxt = new Text2('', {
size: 80,
fill: 0xff8800
});
bossCountdownTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(bossCountdownTxt);
bossCountdownTxt.y = 120;
// Wave display
var waveTxt = new Text2('Wave: 1', {
size: 90,
fill: 0x00ff88
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
waveTxt.y = 200;
// Shop button handler
shopButton.down = function (x, y, obj) {
shopVisible = true;
shopContainer.visible = true;
// Update upgrade button costs
energyUpgradeBtn.setText('Energy +10 (Cost: ' + (100 + energyUpgradeLevel * 20) + ')');
speedUpgradeBtn.setText('Speed +1 (Cost: ' + (150 + speedUpgradeLevel * 30) + ')');
maxEnergyUpgradeBtn.setText('Max Energy +20 (Cost: ' + (300 + energyUpgradeLevel * 50) + ')');
damageUpgradeBtn.setText('Damage +1 (Cost: ' + (200 + damageUpgradeLevel * 40) + ')');
healthUpgradeBtn.setText('Max Health +2 (Cost: ' + (250 + healthUpgradeLevel * 50) + ')');
rangeUpgradeBtn.setText('Arrow Range +20% (Cost: ' + (180 + rangeUpgradeLevel * 35) + ')');
// Pause the game when shop opens
gamePaused = true;
// Clear all enemies when shop opens
for (var e = enemies.length - 1; e >= 0; e--) {
enemies[e].destroy();
enemies.splice(e, 1);
}
// Clear all mini bosses when shop opens
for (var mb = miniBosses.length - 1; mb >= 0; mb--) {
miniBosses[mb].destroy();
miniBosses.splice(mb, 1);
}
// Clear all enemy arrows when shop opens
for (var a = enemyArrows.length - 1; a >= 0; a--) {
enemyArrows[a].destroy();
enemyArrows.splice(a, 1);
}
// Clear boss when shop opens
if (boss) {
boss.destroy();
boss = null;
}
};
// Removed navigation handler - all items now in main shop
// Add shop event handlers
healthPotionBtn.down = function (x, y, obj) {
if (money >= 30) {
money -= 30;
playerHealth += 3;
if (playerHealth > maxHealth) playerHealth = maxHealth;
storage.money = money;
moneyTxt.setText('Money: ' + money);
healthTxt.setText('Health: ' + playerHealth);
}
};
shieldBtn.down = function (x, y, obj) {
if (money >= 80 && !shieldActive) {
money -= 80;
shieldActive = true;
shieldTimer = 1800; // 30 seconds at 60 FPS
storage.money = money;
moneyTxt.setText('Money: ' + money);
archer.tint = 0x4169E1; // Blue tint for shield
}
};
freezeBtn.down = function (x, y, obj) {
if (money >= 60 && !freezeActive) {
money -= 60;
freezeActive = true;
freezeTimer = 600; // 10 seconds at 60 FPS
storage.money = money;
moneyTxt.setText('Money: ' + money);
}
};
explosiveBtn.down = function (x, y, obj) {
if (money >= 120 && !explosiveActive) {
money -= 120;
explosiveActive = true;
explosiveTimer = 1200; // 20 seconds at 60 FPS
storage.money = money;
moneyTxt.setText('Money: ' + money);
}
;
};
doubleMoneyBtn.down = function (x, y, obj) {
if (money >= 150 && !doubleMoneyActive) {
money -= 150;
doubleMoneyActive = true;
doubleMoneyTimer = 3600; // 60 seconds at 60 FPS
storage.money = money;
moneyTxt.setText('Money: ' + money);
}
;
};
energyUpgradeBuyBtn.down = function (x, y, obj) {
if (money >= 100 + energyUpgradeLevel * 20) {
var cost = 100 + energyUpgradeLevel * 20;
money -= cost;
energyUpgradeLevel++;
energy += 10; // Give immediate energy boost
var maxEnergy = 100 + energyUpgradeLevel * 10;
if (energy > maxEnergy) energy = maxEnergy;
storage.money = money;
storage.energyUpgradeLevel = energyUpgradeLevel;
moneyTxt.setText('Money: ' + money);
energyTxt.setText('Energy: ' + energy);
energyUpgradeBtn.setText('Energy +10 (Cost: ' + (100 + energyUpgradeLevel * 20) + ')');
}
};
// Speed upgrade handler
speedUpgradeBuyBtn.down = function (x, y, obj) {
var cost = 150 + speedUpgradeLevel * 30;
if (money >= cost) {
money -= cost;
speedUpgradeLevel++;
storage.money = money;
storage.speedUpgradeLevel = speedUpgradeLevel;
moneyTxt.setText('Money: ' + money);
speedUpgradeBtn.setText('Speed +1 (Cost: ' + (150 + speedUpgradeLevel * 30) + ')');
}
};
// Max energy upgrade handler
maxEnergyUpgradeBuyBtn.down = function (x, y, obj) {
var cost = 300 + energyUpgradeLevel * 50;
if (money >= cost) {
money -= cost;
energyUpgradeLevel += 2;
energy += 20; // Give immediate energy boost
var maxEnergy = 100 + energyUpgradeLevel * 10;
if (energy > maxEnergy) energy = maxEnergy;
storage.money = money;
storage.energyUpgradeLevel = energyUpgradeLevel;
moneyTxt.setText('Money: ' + money);
energyTxt.setText('Energy: ' + energy);
maxEnergyUpgradeBtn.setText('Max Energy +20 (Cost: ' + (300 + energyUpgradeLevel * 50) + ')');
}
};
// Damage upgrade handler
damageUpgradeBuyBtn.down = function (x, y, obj) {
var cost = 200 + damageUpgradeLevel * 40;
if (money >= cost) {
money -= cost;
damageUpgradeLevel++;
storage.money = money;
storage.damageUpgradeLevel = damageUpgradeLevel;
moneyTxt.setText('Money: ' + money);
damageUpgradeBtn.setText('Damage +1 (Cost: ' + (200 + damageUpgradeLevel * 40) + ')');
}
};
// Health upgrade handler
healthUpgradeBuyBtn.down = function (x, y, obj) {
var cost = 250 + healthUpgradeLevel * 50;
if (money >= cost) {
money -= cost;
healthUpgradeLevel++;
maxHealth = 10 + healthUpgradeLevel * 2;
playerHealth += 2; // Give immediate health boost
if (playerHealth > maxHealth) playerHealth = maxHealth;
storage.money = money;
storage.healthUpgradeLevel = healthUpgradeLevel;
moneyTxt.setText('Money: ' + money);
healthTxt.setText('Health: ' + playerHealth);
healthUpgradeBtn.setText('Max Health +2 (Cost: ' + (250 + healthUpgradeLevel * 50) + ')');
}
};
// Range upgrade handler
rangeUpgradeBuyBtn.down = function (x, y, obj) {
var cost = 180 + rangeUpgradeLevel * 35;
if (money >= cost) {
money -= cost;
rangeUpgradeLevel++;
storage.money = money;
storage.rangeUpgradeLevel = rangeUpgradeLevel;
moneyTxt.setText('Money: ' + money);
rangeUpgradeBtn.setText('Arrow Range +20% (Cost: ' + (180 + rangeUpgradeLevel * 35) + ')');
}
};
closeShopBtn.down = function (x, y, obj) {
shopVisible = false;
shopContainer.visible = false;
// Resume the game when shop closes
gamePaused = false;
// Increase difficulty slightly each time shop closes
if (maxEnemies < 8) {
maxEnemies++;
}
if (enemySpawnRate > 20) {
enemySpawnRate -= 2;
}
};
// Removed advanced shop event handlers - items moved to main shop
game.addChild(shopContainer);
// Manual shooting - touch screen to shoot
game.down = function (x, y, obj) {
// Only allow manual shooting when hack mode is not active
if (!autoBattleActive && energy > 0) {
// Convert touch position to game coordinates
// Check if obj and obj.parent exist before calling toGlobal
if (obj && obj.parent && obj.parent.toGlobal) {
var gamePos = game.toLocal(obj.parent.toGlobal({
x: x,
y: y
}));
shootArrowAtTarget(gamePos.x, gamePos.y);
} else {
// Fallback: use x, y directly as they should already be in the correct coordinate system
shootArrowAtTarget(x, y);
}
}
};
function shootArrowAtTarget(targetX, targetY) {
// Check if player has enough energy
if (energy <= 0) {
return;
}
// Calculate direction from archer to target point
var dirX = targetX - archer.x;
var dirY = targetY - archer.y;
var distance = Math.sqrt(dirX * dirX + dirY * dirY);
// Normalize direction
var normalX = dirX / distance;
var normalY = dirY / distance;
// Calculate base angle for arrow direction
var baseAngle = Math.atan2(normalY, normalX);
// Make archer face the shooting direction
archer.rotation = baseAngle;
// Fire arrows based on upgrade level
var arrowCount = upgradeArrowCounts[upgradeLevel];
var energyCost = upgradeLevel === 0 ? 2 : upgradeLevel === 1 ? 6 : upgradeLevel === 2 ? 12 : upgradeLevel === 3 ? 20 : upgradeLevel === 4 ? 35 : 50; // Normal: 2, Triple: 6, Octa: 12, 16-Arrow: 20, 32-Arrow: 35, 64-Arrow: 50
// Check if we have enough energy for the shot type
if (energy < energyCost) {
return;
}
for (var i = 0; i < arrowCount; i++) {
// Add spread based on upgrade level
var spreadAngle = 0;
if (upgradeLevel === 1) {
// Triple shot
spreadAngle = (i - 1) * 0.2; // -0.2, 0, 0.2 radians spread
} else if (upgradeLevel === 2) {
// Octa shot
spreadAngle = (i - 3.5) * 0.15; // Spread 8 arrows in fan pattern
} else if (upgradeLevel === 3) {
// 16-arrow shot
spreadAngle = (i - 7.5) * 0.12; // Spread 16 arrows in wide fan pattern
} else if (upgradeLevel === 4) {
// 32-arrow shot
spreadAngle = (i - 15.5) * 0.10; // Spread 32 arrows in very wide fan pattern
} else if (upgradeLevel === 5) {
// 64-arrow shot
spreadAngle = (i - 31.5) * 0.08; // Spread 64 arrows in extremely wide fan pattern
}
var finalAngle = baseAngle + spreadAngle;
var finalNormalX = Math.cos(finalAngle);
var finalNormalY = Math.sin(finalAngle);
// Create arrow
var newArrow = new Arrow();
newArrow.x = archer.x;
newArrow.y = archer.y;
var arrowSpeed = 15 + speedUpgradeLevel * 3;
newArrow.speedX = finalNormalX * arrowSpeed;
newArrow.speedY = finalNormalY * arrowSpeed;
// Rotate arrow to face direction
newArrow.rotation = finalAngle;
arrows.push(newArrow);
game.addChild(newArrow);
}
LK.getSound('shoot').play();
// Decrease energy
energy -= energyCost;
// Set shooting state
isShooting = true;
shootingTimer = 0;
// Update energy display
energyTxt.setText('Energy: ' + energy);
// Change color based on energy level
if (energy <= 20) {
energyTxt.tint = 0xff0000; // Red when low
} else if (energy <= 50) {
energyTxt.tint = 0xffff00; // Yellow when medium
} else {
energyTxt.tint = 0x00ff00; // Green when high
}
}
game.update = function () {
// Skip all game logic when game is paused (shop is open)
if (gamePaused) {
return;
}
// Update power-up timers
if (shieldActive) {
shieldTimer--;
var seconds = Math.ceil(shieldTimer / 60);
shieldTimerTxt.setText('Shield: ' + seconds + 's');
shieldTimerTxt.visible = true;
if (shieldTimer <= 0) {
shieldActive = false;
shieldTimerTxt.visible = false;
if (!superShieldActive) {
archer.tint = 0xFFFFFF; // Reset archer color only if super shield not active
}
}
}
if (superShieldActive) {
superShieldTimer--;
var seconds = Math.ceil(superShieldTimer / 60);
superShieldTimerTxt.setText('Super Shield: ' + seconds + 's');
superShieldTimerTxt.visible = true;
if (superShieldTimer <= 0) {
superShieldActive = false;
superShieldTimerTxt.visible = false;
if (!shieldActive) {
archer.tint = 0xFFFFFF; // Reset archer color only if regular shield not active
}
}
}
if (timeSlowActive) {
timeSlowTimer--;
var seconds = Math.ceil(timeSlowTimer / 60);
timeSlowTimerTxt.setText('Time Slow: ' + seconds + 's');
timeSlowTimerTxt.visible = true;
if (timeSlowTimer <= 0) {
timeSlowActive = false;
timeSlowTimerTxt.visible = false;
}
}
if (tripleMoneyActive) {
tripleMoneyTimer--;
var seconds = Math.ceil(tripleMoneyTimer / 60);
tripleMoneyTimerTxt.setText('3x Money: ' + seconds + 's');
tripleMoneyTimerTxt.visible = true;
if (tripleMoneyTimer <= 0) {
tripleMoneyActive = false;
tripleMoneyTimerTxt.visible = false;
}
}
if (freezeActive) {
freezeTimer--;
var seconds = Math.ceil(freezeTimer / 60);
freezeTimerTxt.setText('Freeze: ' + seconds + 's');
freezeTimerTxt.visible = true;
if (freezeTimer <= 0) {
freezeActive = false;
freezeTimerTxt.visible = false;
}
}
if (explosiveActive) {
explosiveTimer--;
var seconds = Math.ceil(explosiveTimer / 60);
explosiveTimerTxt.setText('Explosive: ' + seconds + 's');
explosiveTimerTxt.visible = true;
if (explosiveTimer <= 0) {
explosiveActive = false;
explosiveTimerTxt.visible = false;
}
}
if (doubleMoneyActive) {
doubleMoneyTimer--;
var seconds = Math.ceil(doubleMoneyTimer / 60);
doubleMoneyTimerTxt.setText('2x Money: ' + seconds + 's');
doubleMoneyTimerTxt.visible = true;
if (doubleMoneyTimer <= 0) {
doubleMoneyActive = false;
doubleMoneyTimerTxt.visible = false;
}
}
// Automatic shooting logic - only when hack mode is active
if (autoBattleActive) {
autoShootTimer++;
if (autoShootTimer >= 15) {
// Shoot every 0.25 seconds (faster rate for hack mode)
autoShootTimer = 0;
// Shoot at boss first if present, then mini bosses, then regular enemies
var targets = [];
if (boss) {
targets.push(boss);
}
for (var m = 0; m < miniBosses.length; m++) {
if (miniBosses[m]) {
targets.push(miniBosses[m]);
}
}
for (var e = 0; e < enemies.length; e++) {
if (enemies[e]) {
targets.push(enemies[e]);
}
}
for (var t = 0; t < targets.length; t++) {
var target = targets[t];
// Calculate direction from archer to target
var dirX = target.x - archer.x;
var dirY = target.y - archer.y;
var distance = Math.sqrt(dirX * dirX + dirY * dirY);
// Normalize direction
var normalX = dirX / distance;
var normalY = dirY / distance;
// Make archer face the shooting direction
archer.rotation = Math.atan2(normalY, normalX);
// Create arrow without energy cost
var newArrow = new Arrow();
newArrow.x = archer.x;
newArrow.y = archer.y;
newArrow.speedX = normalX * 15;
newArrow.speedY = normalY * 15;
// Rotate arrow to face direction
newArrow.rotation = Math.atan2(normalY, normalX);
arrows.push(newArrow);
game.addChild(newArrow);
}
// Play shoot sound if we shot any arrows
if (targets.length > 0) {
LK.getSound('shoot').play();
}
}
}
// Update shooting timer
if (isShooting) {
shootingTimer++;
if (shootingTimer >= 30) {
// Stop shooting state after 0.5 seconds
isShooting = false;
}
}
// Update energy regeneration only when not shooting (every 60 frames = 1 second at 60 FPS)
if (!isShooting) {
energyRegenTimer++;
if (energyRegenTimer >= 60) {
energyRegenTimer = 0;
var maxEnergy = 100 + energyUpgradeLevel * 10;
if (energy < maxEnergy) {
energy += 1;
// Update energy display
energyTxt.setText('Energy: ' + energy);
// Change color based on energy level
if (energy <= 20) {
energyTxt.tint = 0xff0000; // Red when low
} else if (energy <= 50) {
energyTxt.tint = 0xffff00; // Yellow when medium
} else {
energyTxt.tint = 0x00ff00; // Green when high
}
}
}
} else {
energyRegenTimer = 0; // Reset regen timer when shooting
}
// Spawn enemies randomly on screen when needed (only when no boss is active)
if (!boss && enemies.length + miniBosses.length < maxEnemies) {
enemySpawnTimer++;
var currentSpawnRate = timeSlowActive ? enemySpawnRate * 2 : enemySpawnRate;
if (enemySpawnTimer >= currentSpawnRate) {
enemySpawnTimer = 0;
// 30% chance to spawn mini boss, 70% chance for regular enemy
var spawnMiniBoss = Math.random() < 0.3;
if (spawnMiniBoss && miniBosses.length < 2) {
// Spawn mini boss
var newMiniBoss = new MiniBoss();
// Scale mini boss health with wave
var baseHealth = 3;
var waveHealthBonus = Math.floor((currentWave - 1) / 2);
newMiniBoss.health = baseHealth + waveHealthBonus;
newMiniBoss.healthTxt.setText(newMiniBoss.health.toString());
newMiniBoss.x = Math.random() * (2048 - 200) + 100;
newMiniBoss.y = Math.random() * (2732 - 200) + 100;
// Make sure mini boss doesn't spawn too close to archer
var distToArcher = Math.sqrt(Math.pow(newMiniBoss.x - archer.x, 2) + Math.pow(newMiniBoss.y - archer.y, 2));
if (distToArcher < 200) {
newMiniBoss.x = Math.random() * (2048 - 400) + 200;
if (newMiniBoss.x > archer.x - 200 && newMiniBoss.x < archer.x + 200) {
newMiniBoss.x += 300;
}
}
miniBosses.push(newMiniBoss);
game.addChild(newMiniBoss);
} else {
// Spawn regular enemy
var newEnemy = new Enemy();
// Scale enemy health with wave
var baseHealth = 2;
var waveHealthBonus = Math.floor((currentWave - 1) / 2);
newEnemy.health = baseHealth + waveHealthBonus;
newEnemy.healthTxt.setText(newEnemy.health.toString());
newEnemy.x = Math.random() * (2048 - 200) + 100;
newEnemy.y = Math.random() * (2732 - 200) + 100;
// Make sure enemy doesn't spawn too close to archer
var distToArcher = Math.sqrt(Math.pow(newEnemy.x - archer.x, 2) + Math.pow(newEnemy.y - archer.y, 2));
if (distToArcher < 200) {
// Respawn farther away
newEnemy.x = Math.random() * (2048 - 400) + 200;
if (newEnemy.x > archer.x - 200 && newEnemy.x < archer.x + 200) {
newEnemy.x += 300;
}
}
enemies.push(newEnemy);
game.addChild(newEnemy);
}
}
}
// Update arrows
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Remove arrows that hit walls or go off screen
if (arrow.x >= 2048 || arrow.x <= 0 || arrow.y >= 2732 || arrow.y <= 0) {
arrow.destroy();
arrows.splice(i, 1);
continue;
}
// Check arrow-enemy arrow collisions
var arrowDestroyed = false;
for (var k = enemyArrows.length - 1; k >= 0; k--) {
var enemyArrow = enemyArrows[k];
if (arrow && enemyArrow && arrow.intersects(enemyArrow)) {
// Both arrows destroy each other
arrow.destroy();
arrows.splice(i, 1);
enemyArrow.destroy();
enemyArrows.splice(k, 1);
arrowDestroyed = true;
break;
}
}
// Skip enemy collision check if arrow was destroyed by enemy arrow
if (arrowDestroyed) {
continue;
}
// Check arrow-enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (enemy && arrow && arrow.intersects(enemy)) {
// Hit enemy - reduce health
enemy.health -= 1 + damageUpgradeLevel;
enemy.healthTxt.setText(enemy.health.toString());
LK.getSound('hit').play();
LK.effects.flashObject(enemy, explosiveActive ? 0xFF4500 : 0xff0000, 200);
// Check if enemy is defeated
if (enemy.health <= 0) {
// Give money with bonuses
var moneyGain = tripleMoneyActive ? 15 : doubleMoneyActive ? 10 : 5;
money += moneyGain;
kills++;
storage.money = money;
storage.kills = kills;
moneyTxt.setText('Money: ' + money);
// Explosive arrows destroy nearby enemies
if (explosiveActive) {
for (var k = enemies.length - 1; k >= 0; k--) {
if (k !== j && enemies[k]) {
var dist = Math.sqrt(Math.pow(enemies[k].x - enemy.x, 2) + Math.pow(enemies[k].y - enemy.y, 2));
if (dist < 150) {
// Explosion radius
var bonusGain = tripleMoneyActive ? 15 : doubleMoneyActive ? 10 : 5;
money += bonusGain;
kills++;
storage.money = money;
storage.kills = kills;
LK.effects.flashObject(enemies[k], 0xFF4500, 300);
enemies[k].destroy();
enemies.splice(k, 1);
if (k < j) j--; // Adjust index if we removed an enemy before current one
}
}
}
moneyTxt.setText('Money: ' + money);
}
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
}
// Remove arrow
arrow.destroy();
arrows.splice(i, 1);
break;
}
}
// Check arrow-mini boss collisions
for (var mb = miniBosses.length - 1; mb >= 0; mb--) {
var miniBoss = miniBosses[mb];
if (miniBoss && arrow && arrow.intersects(miniBoss)) {
// Hit mini boss - reduce health
miniBoss.health -= 1 + damageUpgradeLevel;
miniBoss.healthTxt.setText(miniBoss.health.toString());
LK.getSound('hit').play();
LK.effects.flashObject(miniBoss, explosiveActive ? 0xFF4500 : 0x800080, 200);
// Check if mini boss is defeated
if (miniBoss.health <= 0) {
// Give more money for mini boss
var moneyGain = tripleMoneyActive ? 30 : doubleMoneyActive ? 20 : 10;
money += moneyGain;
kills += 3; // Mini boss counts as 3 kills
storage.money = money;
storage.kills = kills;
moneyTxt.setText('Money: ' + money);
// Explosive arrows destroy nearby enemies
if (explosiveActive) {
// Check explosion damage to regular enemies
for (var k = enemies.length - 1; k >= 0; k--) {
if (enemies[k]) {
var dist = Math.sqrt(Math.pow(enemies[k].x - miniBoss.x, 2) + Math.pow(enemies[k].y - miniBoss.y, 2));
if (dist < 150) {
var bonusGain = tripleMoneyActive ? 15 : doubleMoneyActive ? 10 : 5;
money += bonusGain;
kills++;
storage.money = money;
storage.kills = kills;
LK.effects.flashObject(enemies[k], 0xFF4500, 300);
enemies[k].destroy();
enemies.splice(k, 1);
}
}
}
// Check explosion damage to other mini bosses
for (var k = miniBosses.length - 1; k >= 0; k--) {
if (k !== mb && miniBosses[k]) {
var dist = Math.sqrt(Math.pow(miniBosses[k].x - miniBoss.x, 2) + Math.pow(miniBosses[k].y - miniBoss.y, 2));
if (dist < 150) {
miniBosses[k].health--;
miniBosses[k].healthTxt.setText(miniBosses[k].health.toString());
LK.effects.flashObject(miniBosses[k], 0xFF4500, 300);
if (miniBosses[k].health <= 0) {
var bonusGain = tripleMoneyActive ? 30 : doubleMoneyActive ? 20 : 10;
money += bonusGain;
kills += 3;
storage.money = money;
storage.kills = kills;
miniBosses[k].destroy();
miniBosses.splice(k, 1);
if (k < mb) mb--;
}
}
}
}
moneyTxt.setText('Money: ' + money);
}
// Remove mini boss
miniBoss.destroy();
miniBosses.splice(mb, 1);
}
// Remove arrow
arrow.destroy();
arrows.splice(i, 1);
break;
}
}
// Check arrow-boss collision
if (boss && arrow && arrow.intersects(boss)) {
// Hit boss
boss.health--;
LK.getSound('hit').play();
LK.effects.flashObject(boss, 0xff0000, 300);
// Remove arrow
arrow.destroy();
arrows.splice(i, 1);
// Boss moves to new position when hit
boss.moveToNewPosition();
// Check if boss is defeated
if (boss.health <= 0) {
money += 50; // Bonus money for defeating boss
kills += 10; // Count boss as 10 kills
bossesKilled++;
currentWave++;
// Increase difficulty with each wave
maxEnemies = Math.min(10, 1 + Math.floor(currentWave / 2));
enemySpawnRate = Math.max(15, 120 - currentWave * 8);
// Enemies get stronger each wave
if (currentWave >= 3) {
// Starting from wave 3, some enemies have more health
var healthBonus = Math.floor((currentWave - 2) / 2);
// This will be applied when spawning enemies
}
storage.money = money;
storage.kills = kills;
moneyTxt.setText('Money: ' + money);
waveTxt.setText('Wave: ' + currentWave);
boss.destroy();
boss = null;
bossSpawnScore = kills + Math.floor(Math.random() * 21) + 30; // Next boss spawns after random 30-50 more kills
}
break;
}
}
// Update enemy arrows
for (var m = enemyArrows.length - 1; m >= 0; m--) {
var enemyArrow = enemyArrows[m];
// Remove arrows that hit walls or go off screen
if (enemyArrow.x >= 2048 || enemyArrow.x <= 0 || enemyArrow.y >= 2732 || enemyArrow.y <= 0) {
enemyArrow.destroy();
enemyArrows.splice(m, 1);
continue;
}
// Check if enemy arrow hits player
if (enemyArrow.intersects(archer)) {
if (!shieldActive && !superShieldActive) {
playerHealth--;
healthTxt.setText('Health: ' + playerHealth);
LK.getSound('playerHit').play();
LK.effects.flashObject(archer, 0xff0000, 300);
// Check if player is dead
if (playerHealth <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
} else {
// Shield blocks the arrow
var shieldColor = superShieldActive ? 0x8000FF : 0x4169E1;
LK.effects.flashObject(archer, shieldColor, 200);
}
enemyArrow.destroy();
enemyArrows.splice(m, 1);
continue;
}
}
// Check if hack mode is active and score exceeds 200 to show HACKER text
if (autoBattleActive && LK.getScore() > 200) {
// Create red HACKER text if it doesn't exist
if (!game.hackerText) {
game.hackerText = new Text2('HACKER', {
size: 200,
fill: 0xff0000
});
game.hackerText.anchor.set(0.5, 0.5);
game.hackerText.x = 2048 / 2;
game.hackerText.y = 2732 / 2;
game.addChild(game.hackerText);
// Apply pulsing red glow effect
tween(game.hackerText, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game.hackerText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the pulsing effect
if (game.hackerText) {
tween(game.hackerText, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
}
});
}
} else if (game.hackerText) {
// Remove HACKER text if conditions not met
game.hackerText.destroy();
game.hackerText = null;
}
// Update boss health display
if (boss) {
bossHealthTxt.setText('Boss Health: ' + boss.health);
bossHealthTxt.x = boss.x;
bossHealthTxt.y = boss.y - 80;
bossHealthTxt.visible = true;
} else {
bossHealthTxt.visible = false;
}
// Update boss countdown display
if (boss === null) {
var killsUntilBoss = bossSpawnScore - kills;
if (killsUntilBoss > 0) {
bossCountdownTxt.setText('Boss in: ' + killsUntilBoss + ' kills');
bossCountdownTxt.visible = true;
} else {
bossCountdownTxt.visible = false;
}
} else {
bossCountdownTxt.visible = false;
}
// Spawn boss every 20 kills
if (boss === null && kills >= bossSpawnScore) {
// Clear all existing enemies when boss spawns
for (var e = enemies.length - 1; e >= 0; e--) {
enemies[e].destroy();
enemies.splice(e, 1);
}
// Clear all mini bosses when boss spawns
for (var mb = miniBosses.length - 1; mb >= 0; mb--) {
miniBosses[mb].destroy();
miniBosses.splice(mb, 1);
}
boss = new Boss();
boss.x = Math.random() * (2048 - 400) + 200;
boss.y = Math.random() * (2732 - 400) + 200;
// Make sure boss doesn't spawn too close to archer
var distToArcher = Math.sqrt(Math.pow(boss.x - archer.x, 2) + Math.pow(boss.y - archer.y, 2));
if (distToArcher < 300) {
boss.x = Math.random() * (2048 - 600) + 300;
if (boss.x > archer.x - 300 && boss.x < archer.x + 300) {
boss.x += 400;
}
}
// Scale boss health with wave
var baseHealth = 10;
var waveHealthBonus = Math.floor((currentWave - 1) / 3) * 5; // +5 health every 3 waves
boss.health = baseHealth + waveHealthBonus;
game.addChild(boss);
}
// When enemy dies, increase max enemies and spawn rate for difficulty
if (LK.getScore() > 0 && LK.getScore() % 50 === 0) {
if (maxEnemies < 5) {
maxEnemies++;
}
if (enemySpawnRate > 30) {
enemySpawnRate -= 5;
}
}
};