User prompt
When the wave get up. Do hard the game
User prompt
Do not in line . Do like list to do we can read also the money
User prompt
Make line that see icon to buy
User prompt
Add more defence tower button to buy.
User prompt
Add one big but defense tower
User prompt
Add button I cannot see the button to buy tower
User prompt
Add button for buy defence tower
User prompt
Add without money we cannot place defence tower
User prompt
We can see money total on top bottom
User prompt
Make a icon system. When kill zombie we get moneywe can see. Total money.
Code edit (1 edits merged)
Please save this source code
User prompt
Zombie Siege: Tower Wars
Initial prompt
Expanding the Threat: Enemy Bot Towers This addition significantly changes the defensive dynamic. It's no longer just about stopping zombies; you now have to contend with automated enemy defenses that are actively trying to dismantle your base. * Hostile AI Towers: These are automated enemy structures, perhaps built by a rival survivor faction or even by the zombies themselves (mutated, bio-mechanical constructs?). They'll deploy on the map and actively fire upon your main tower, your hero, and even your defensive turrets. * Strategic Targets: Unlike zombies, which are often numerous but individually weaker (though some are tough!), these bot towers would be fewer in number but heavily armed and armored. They become high-priority targets that you need to eliminate quickly to reduce incoming damage to your base. * Varied Bot Tower Types: * Artillery Bots: Long-range but slow-firing, lobbing projectiles that deal area-of-effect damage to your base or a cluster of your towers. * Assault Bots: Closer-range, rapid-fire turrets that focus on shredding individual defensive towers or your hero. * Disruption Bots: Don't deal direct damage, but emit EMPs or jamming signals that temporarily disable your towers, reduce their fire rate, or block your hero's abilities. * Repair Bots (Enemy): These might not attack directly but move around the map, actively repairing damaged enemy bot towers or even buffing nearby zombies. Taking these out first becomes crucial. * Counter-Strategies: * Target Prioritization: Players will need to decide whether to focus fire on the immediate zombie threat or divert resources and hero attention to neutralizing a dangerous enemy bot tower. * Specialized Towers: You might need specific tower types designed to counter these bots, such as EMP emitters to temporarily disable them, or armor-piercing turrets that are less effective against flesh-and-blood zombies but devastating against mechanical foes. * Hero Engagement: The hero unit becomes even more critical here. They could be the primary means to quickly take down bot towers, perhaps through specific "sabotage" abilities or by drawing their fire away from your main defenses. * Placement & Spawning: These bot towers could spawn at fixed locations, or they might occasionally drop in via aerial support or emerge from hidden bunkers. Their appearance could be tied to specific wave milestones or a rising "threat level." Adding these hostile bot towers introduces a fascinating "tower vs. tower" element to the game, demanding more tactical thinking and resource allocation beyond just fending off the zombie hordes. It forces players to be proactive in eliminating threats that aren't just moving along a path but are actively seeking to dismantle their defenses.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BigDefenseTower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, tint: 0xFF4444 }); self.health = 500; self.maxHealth = 500; self.damage = 80; self.range = 450; self.shootCooldown = 0; self.update = function () { var target = self.findNearestEnemy(); if (target && self.shootCooldown <= 0) { self.shootAt(target); self.shootCooldown = 35; // Slightly faster than regular tower } if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.findNearestEnemy = function () { var nearest = null; var minDistance = Infinity; // Check zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = zombie; } } // Check enemy bots for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = bot; } } return nearest; }; self.shootAt = function (target) { var bullet = new BigTowerBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = target.x; bullet.targetY = target.y; bullet.damage = self.damage; bigTowerBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { self.destroy(); var index = bigDefenseTowers.indexOf(self); if (index > -1) { bigDefenseTowers.splice(index, 1); } }; return self; }); var BigTowerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, tint: 0xFF4444 }); self.speed = 10; self.damage = 80; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.explode(); } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = bigTowerBullets.indexOf(self); if (index > -1) { bigTowerBullets.splice(index, 1); } } }; self.explode = function () { // Check for zombie hits for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (self.intersects(zombie)) { zombie.takeDamage(self.damage); break; } } // Check for enemy bot hits for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; if (self.intersects(bot)) { bot.takeDamage(self.damage); break; } } self.destroy(); var index = bigTowerBullets.indexOf(self); if (index > -1) { bigTowerBullets.splice(index, 1); } }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); self.health = 4000; self.maxHealth = 4000; self.speed = 0.8; // Slower than regular zombies self.damage = 100; // High damage self.target = null; self.attackCooldown = 0; self.specialAttackCooldown = 0; self.update = function () { if (!self.target) { self.target = playerBase; } // Move towards target var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 80) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { // Attack target if (self.attackCooldown <= 0) { if (self.target === playerBase) { playerBase.takeDamage(self.damage); } self.attackCooldown = 90; // Slower attack rate } } // Special AOE attack every 5 seconds if (self.specialAttackCooldown <= 0) { self.aoeAttack(); self.specialAttackCooldown = 300; // 5 seconds } if (self.attackCooldown > 0) { self.attackCooldown--; } if (self.specialAttackCooldown > 0) { self.specialAttackCooldown--; } }; self.aoeAttack = function () { // AOE damage to all towers and hero in range var aoeRange = 400; LK.effects.flashObject(self, 0xFFFF00, 500); // Damage hero var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2)); if (distanceToHero < aoeRange) { hero.takeDamage(50); } // Damage all towers in range for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < aoeRange) { tower.takeDamage(80); } } for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < aoeRange) { tower.takeDamage(80); } } for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < aoeRange) { tower.takeDamage(80); } } for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < aoeRange) { tower.takeDamage(80); } } LK.getSound('explosion').play(); }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('explosion').play(); LK.setScore(LK.getScore() + 500); scoreText.setText('Score: ' + LK.getScore()); // Boss gives lots of money var moneyEarned = 200; money += moneyEarned; moneyText.setText('Money: $' + money); var moneyIcon = new MoneyIcon(moneyEarned); moneyIcon.x = self.x; moneyIcon.y = self.y; moneyIcons.push(moneyIcon); game.addChild(moneyIcon); self.destroy(); var index = bosses.indexOf(self); if (index > -1) { bosses.splice(index, 1); } }; return self; }); var BuyBigTowerButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2, tint: 0xFF4444 }); var towerIcon = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, tint: 0xFF4444, y: -15 }); var buttonText = new Text2('Big Tower', { size: 28, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.y = 15; self.addChild(buttonText); var costText = new Text2('R:100 $100', { size: 22, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0.5); costText.y = 35; self.addChild(costText); self.down = function (x, y, obj) { var towerCost = 100; if (resources >= 100 && money >= towerCost) { // Enable big tower placement mode placingBigTower = true; LK.effects.flashObject(self, 0x00FF00, 300); } else { // Flash red if can't afford LK.effects.flashObject(self, 0xFF0000, 300); } }; self.update = function () { var towerCost = 100 + Math.floor(wave / 2) * 15; var resourceCost = 100 + Math.floor(wave / 3) * 20; if (resources >= resourceCost && money >= towerCost) { buttonGraphics.tint = 0xFF2222; // Red when affordable buttonText.setText('Big Tower'); costText.setText('R:' + resourceCost + ' $' + towerCost); } else { buttonGraphics.tint = 0x808080; // Gray when not affordable buttonText.setText('Big Tower'); costText.setText('R:' + resourceCost + ' $' + towerCost); } }; return self; }); var BuyRapidFireTowerButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, tint: 0x00FF00 }); var towerIcon = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, tint: 0x00FF00, y: -15 }); var buttonText = new Text2('Rapid', { size: 28, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.y = 15; self.addChild(buttonText); var costText = new Text2('R:75 $40', { size: 22, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0.5); costText.y = 35; self.addChild(costText); self.down = function (x, y, obj) { var towerCost = 40; if (resources >= 75 && money >= towerCost) { // Enable rapid fire tower placement mode placingRapidFireTower = true; LK.effects.flashObject(self, 0x00FF00, 300); } else { // Flash red if can't afford LK.effects.flashObject(self, 0xFF0000, 300); } }; self.update = function () { var towerCost = 40; if (resources >= 75 && money >= towerCost) { buttonGraphics.tint = 0x00AA00; // Green when affordable buttonText.setText('Rapid'); costText.setText('R:75 $40'); } else { buttonGraphics.tint = 0x808080; // Gray when not affordable buttonText.setText('Rapid'); costText.setText('R:75 $40'); } }; return self; }); var BuySniperTowerButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, tint: 0x0088FF }); var towerIcon = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, tint: 0x0088FF, y: -15 }); var buttonText = new Text2('Sniper', { size: 26, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.y = 15; self.addChild(buttonText); var costText = new Text2('R:125 $75', { size: 20, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0.5); costText.y = 35; self.addChild(costText); self.down = function (x, y, obj) { var towerCost = 75; if (resources >= 125 && money >= towerCost) { // Enable sniper tower placement mode placingSniperTower = true; LK.effects.flashObject(self, 0x00FF00, 300); } else { // Flash red if can't afford LK.effects.flashObject(self, 0xFF0000, 300); } }; self.update = function () { var towerCost = 75; if (resources >= 125 && money >= towerCost) { buttonGraphics.tint = 0x0066CC; // Blue when affordable buttonText.setText('Sniper'); costText.setText('R:125 $75'); } else { buttonGraphics.tint = 0x808080; // Gray when not affordable buttonText.setText('Sniper'); costText.setText('R:125 $75'); } }; return self; }); var BuyTowerButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5 }); var towerIcon = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4, y: -15 }); var buttonText = new Text2('Tower', { size: 32, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.y = 15; self.addChild(buttonText); var costText = new Text2('R:50 $25', { size: 24, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0.5); costText.y = 35; self.addChild(costText); self.down = function (x, y, obj) { var towerCost = 25; if (resources >= 50 && money >= towerCost) { // Enable tower placement mode placingTower = true; LK.effects.flashObject(self, 0x00FF00, 300); } else { // Flash red if can't afford LK.effects.flashObject(self, 0xFF0000, 300); } }; self.update = function () { var towerCost = 25 + Math.floor(wave / 2) * 5; var resourceCost = 50 + Math.floor(wave / 3) * 10; if (resources >= resourceCost && money >= towerCost) { buttonGraphics.tint = 0x4CAF50; // Green when affordable buttonText.setText('Tower'); costText.setText('R:' + resourceCost + ' $' + towerCost); } else { buttonGraphics.tint = 0x808080; // Gray when not affordable buttonText.setText('Tower'); costText.setText('R:' + resourceCost + ' $' + towerCost); } }; return self; }); var DefenseTower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5 }); self.health = 200; self.maxHealth = 200; self.damage = 30; self.range = 300; self.shootCooldown = 0; self.update = function () { var target = self.findNearestEnemy(); if (target && self.shootCooldown <= 0) { self.shootAt(target); self.shootCooldown = 45; // 0.75 second cooldown } if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.findNearestEnemy = function () { var nearest = null; var minDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = zombie; } } // Check bosses for (var i = 0; i < bosses.length; i++) { var boss = bosses[i]; var distance = Math.sqrt(Math.pow(boss.x - self.x, 2) + Math.pow(boss.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = boss; } } return nearest; }; self.shootAt = function (target) { var bullet = new TowerBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = target.x; bullet.targetY = target.y; bullet.damage = self.damage; towerBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { self.destroy(); var index = defenseTowers.indexOf(self); if (index > -1) { defenseTowers.splice(index, 1); } }; return self; }); var EnemyBot = Container.expand(function (botType) { var self = Container.call(this); var botGraphics = self.attachAsset(botType, { anchorX: 0.5, anchorY: 0.5 }); self.botType = botType; // Scale bot stats based on current wave var healthMultiplier = 1 + (wave - 1) * 0.25; // 25% more health per wave var damageMultiplier = 1 + (wave - 1) * 0.15; // 15% more damage per wave self.health = Math.floor(150 * healthMultiplier); self.maxHealth = Math.floor(150 * healthMultiplier); self.damage = Math.floor(25 * damageMultiplier); self.range = 350; self.shootCooldown = 0; // Set specific properties based on bot type if (botType === 'artilleryBot') { self.damage = 60; self.range = 400; self.shootCooldown = 90; // Slower but more powerful } else if (botType === 'assaultBot') { self.damage = 20; self.range = 250; self.shootCooldown = 20; // Faster firing } else if (botType === 'disruptionBot') { self.damage = 15; self.range = 300; self.shootCooldown = 120; // Special ability cooldown } else if (botType === 'repairBot') { self.damage = 0; self.range = 200; self.shootCooldown = 180; // Repair cooldown } self.update = function () { var target = self.findTarget(); if (target) { // Move towards target if not in range var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.range) { // Move towards target var speed = 1.5; // Bot movement speed self.x += dx / distance * speed; self.y += dy / distance * speed; } } else { // No target in range, move towards player base var dx = playerBase.x - self.x; var dy = playerBase.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 80) { // Don't get too close to base var speed = 1.2; // Slightly slower when moving to base self.x += dx / distance * speed; self.y += dy / distance * speed; } } if (target && self.shootCooldown <= 0) { if (self.botType === 'repairBot') { self.repairAllies(); } else { self.shootAt(target); } self.shootCooldown = self.getBaseCooldown(); } if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.findTarget = function () { var targets = []; // Add player base as target var distanceToBase = Math.sqrt(Math.pow(playerBase.x - self.x, 2) + Math.pow(playerBase.y - self.y, 2)); if (distanceToBase < self.range) { targets.push({ target: playerBase, distance: distanceToBase }); } // Add hero as target var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2)); if (distanceToHero < self.range) { targets.push({ target: hero, distance: distanceToHero }); } // Add defense towers as targets for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < self.range) { targets.push({ target: tower, distance: distance }); } } // Add big defense towers as targets for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < self.range) { targets.push({ target: tower, distance: distance }); } } // Add rapid fire towers as targets for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < self.range) { targets.push({ target: tower, distance: distance }); } } // Add sniper towers as targets for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < self.range) { targets.push({ target: tower, distance: distance }); } } // Return nearest target if (targets.length > 0) { targets.sort(function (a, b) { return a.distance - b.distance; }); return targets[0].target; } return null; }; self.shootAt = function (target) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = target.x; bullet.targetY = target.y; bullet.damage = self.damage; bullet.isAOE = self.botType === 'artilleryBot'; enemyBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.repairAllies = function () { for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; if (bot !== self) { var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2)); if (distance < self.range) { bot.health = Math.min(bot.health + 30, bot.maxHealth); LK.effects.flashObject(bot, 0x00ff00, 300); } } } }; self.getBaseCooldown = function () { if (self.botType === 'artilleryBot') return 90; if (self.botType === 'assaultBot') return 20; if (self.botType === 'disruptionBot') return 120; if (self.botType === 'repairBot') return 180; return 60; }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('explosion').play(); LK.setScore(LK.getScore() + 25); scoreText.setText('Score: ' + LK.getScore()); // Add money and spawn money icon var moneyEarned = 15; money += moneyEarned; moneyText.setText('Money: $' + money); var moneyIcon = new MoneyIcon(moneyEarned); moneyIcon.x = self.x; moneyIcon.y = self.y; moneyIcons.push(moneyIcon); game.addChild(moneyIcon); self.destroy(); var index = enemyBots.indexOf(self); if (index > -1) { enemyBots.splice(index, 1); } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.damage = 25; self.targetX = 0; self.targetY = 0; self.isAOE = false; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.explode(); } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = enemyBullets.indexOf(self); if (index > -1) { enemyBullets.splice(index, 1); } } }; self.explode = function () { if (self.isAOE) { // AOE damage var explosion = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, alpha: 0.7 }); game.addChild(explosion); tween(explosion, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 500, onFinish: function onFinish() { explosion.destroy(); } }); // Damage everything in range var explosionRange = 150; if (self.intersects(playerBase)) { playerBase.takeDamage(self.damage); } if (self.intersects(hero)) { hero.takeDamage(self.damage); } for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < explosionRange) { tower.takeDamage(self.damage); } } for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < explosionRange) { tower.takeDamage(self.damage); } } for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < explosionRange) { tower.takeDamage(self.damage); } } for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < explosionRange) { tower.takeDamage(self.damage); } } LK.getSound('explosion').play(); } else { // Single target damage if (self.intersects(playerBase)) { playerBase.takeDamage(self.damage); } else if (self.intersects(hero)) { hero.takeDamage(self.damage); } else { for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; if (self.intersects(tower)) { tower.takeDamage(self.damage); break; } } for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; if (self.intersects(tower)) { tower.takeDamage(self.damage); break; } } for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; if (self.intersects(tower)) { tower.takeDamage(self.damage); break; } } for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; if (self.intersects(tower)) { tower.takeDamage(self.damage); break; } } } } self.destroy(); var index = enemyBullets.indexOf(self); if (index > -1) { enemyBullets.splice(index, 1); } }; return self; }); var Hero = Container.expand(function () { var self = Container.call(this); var heroGraphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.health = 300; self.maxHealth = 300; self.speed = 3; self.damage = 40; self.shootCooldown = 0; self.targetX = self.x; self.targetY = self.y; // Special abilities for boss waves self.specialAttackCooldown = 0; self.shieldCooldown = 0; self.isShielded = false; self.shieldDuration = 0; self.update = function () { // Only move and attack if alive if (self.health > 0) { // Move towards target position var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Auto-attack nearest enemy var nearestEnemy = self.findNearestEnemy(); if (nearestEnemy && self.shootCooldown <= 0) { self.shootAt(nearestEnemy); self.shootCooldown = 30; // 0.5 second cooldown } // Special abilities during boss waves (wave 9+) if (wave >= 9) { // Special attack - shoots multiple bullets in a spread if (self.specialAttackCooldown <= 0) { self.specialAttack(); self.specialAttackCooldown = 300; // 5 seconds } // Shield ability - temporary damage immunity if (self.shieldCooldown <= 0 && !self.isShielded) { self.activateShield(); self.shieldCooldown = 600; // 10 seconds } } else { // Reset special abilities when not in boss waves self.specialAttackCooldown = 0; self.shieldCooldown = 0; self.isShielded = false; self.shieldDuration = 0; self.alpha = 1.0; // Ensure normal opacity } } if (self.shootCooldown > 0) { self.shootCooldown--; } // Update special ability cooldowns if (self.specialAttackCooldown > 0) { self.specialAttackCooldown--; } if (self.shieldCooldown > 0) { self.shieldCooldown--; } if (self.isShielded) { self.shieldDuration--; if (self.shieldDuration <= 0) { self.isShielded = false; self.alpha = 1.0; // Return to normal opacity } } // Update health display var healthStatus = self.isShielded ? ' (SHIELDED)' : ''; heroHealthText.setText('Hero Health: ' + Math.max(0, self.health) + '/' + self.maxHealth + healthStatus); }; self.findNearestEnemy = function () { var nearest = null; var minDistance = Infinity; // Check zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2)); if (distance < minDistance && distance < 400) { minDistance = distance; nearest = zombie; } } // Check enemy bots for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2)); if (distance < minDistance && distance < 400) { minDistance = distance; nearest = bot; } } // Check bosses for (var i = 0; i < bosses.length; i++) { var boss = bosses[i]; var distance = Math.sqrt(Math.pow(boss.x - self.x, 2) + Math.pow(boss.y - self.y, 2)); if (distance < minDistance && distance < 400) { minDistance = distance; nearest = boss; } } return nearest; }; self.shootAt = function (target) { var bullet = new HeroBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = target.x; bullet.targetY = target.y; bullet.damage = self.damage; heroBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.specialAttack = function () { // Fire 5 bullets in a spread pattern var nearestEnemy = self.findNearestEnemy(); if (nearestEnemy) { for (var i = 0; i < 5; i++) { var bullet = new HeroBullet(); bullet.x = self.x; bullet.y = self.y; // Calculate spread angle var angleOffset = (i - 2) * 0.3; // Spread bullets in a fan var dx = nearestEnemy.x - self.x; var dy = nearestEnemy.y - self.y; var angle = Math.atan2(dy, dx) + angleOffset; var distance = 400; // Target distance bullet.targetX = self.x + Math.cos(angle) * distance; bullet.targetY = self.y + Math.sin(angle) * distance; bullet.damage = self.damage * 1.5; // Increased damage for special attack heroBullets.push(bullet); game.addChild(bullet); } LK.getSound('shoot').play(); LK.effects.flashObject(self, 0xFFFF00, 500); // Yellow flash for special attack } }; self.activateShield = function () { self.isShielded = true; self.shieldDuration = 180; // 3 seconds of shield self.alpha = 0.7; // Make hero semi-transparent to show shield LK.effects.flashObject(self, 0x00FFFF, 300); // Cyan flash for shield activation }; self.moveTo = function (x, y) { if (self.health > 0) { self.targetX = x; self.targetY = y; } }; self.takeDamage = function (amount) { // Shield blocks damage during boss waves if (self.isShielded) { LK.effects.flashObject(self, 0x00FFFF, 200); // Cyan flash when shielded return; // No damage taken while shielded } self.health -= amount; // Prevent hero health from going below 1 - hero cannot die if (self.health < 1) { self.health = 1; } LK.effects.flashObject(self, 0xff0000, 300); // Remove death condition - hero can no longer die }; self.die = function () { // Hero becomes translucent and stops moving when dead self.alpha = 0.3; self.targetX = self.x; self.targetY = self.y; heroHealthText.setText('Hero Health: 0/' + self.maxHealth + ' (DEAD)'); // Attack player base when hero dies playerBase.takeDamage(self.damage * 2); // Double damage when hero dies }; return self; }); var HeroBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('heroBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.damage = 40; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.explode(); } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = heroBullets.indexOf(self); if (index > -1) { heroBullets.splice(index, 1); } } }; self.explode = function () { // Check for zombie hits for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (self.intersects(zombie)) { zombie.takeDamage(self.damage); self.destroy(); var index = heroBullets.indexOf(self); if (index > -1) { heroBullets.splice(index, 1); } return; } } // Check for enemy bot hits for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; if (self.intersects(bot)) { bot.takeDamage(self.damage); self.destroy(); var index = heroBullets.indexOf(self); if (index > -1) { heroBullets.splice(index, 1); } return; } } // Check for boss hits for (var i = 0; i < bosses.length; i++) { var boss = bosses[i]; if (self.intersects(boss)) { boss.takeDamage(self.damage); self.destroy(); var index = heroBullets.indexOf(self); if (index > -1) { heroBullets.splice(index, 1); } return; } } self.destroy(); var index = heroBullets.indexOf(self); if (index > -1) { heroBullets.splice(index, 1); } }; return self; }); var LeaderboardScreen = Container.expand(function () { var self = Container.call(this); var background = LK.getAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 8, tint: 0x000000, alpha: 0.9 }); self.addChild(background); var titleText = new Text2('LEADERBOARD', { size: 80, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.y = -300; self.addChild(titleText); var currentScoreText = new Text2('Your Score: 0', { size: 50, fill: 0x00FF00 }); currentScoreText.anchor.set(0.5, 0.5); currentScoreText.y = -200; self.addChild(currentScoreText); var positionText = new Text2('Your Position: #1', { size: 45, fill: 0xFFFFFF }); positionText.anchor.set(0.5, 0.5); positionText.y = -150; self.addChild(positionText); var scoresText = new Text2('', { size: 35, fill: 0xFFFFFF }); scoresText.anchor.set(0.5, 0.5); scoresText.y = 50; self.addChild(scoresText); var closeText = new Text2('Tap to close', { size: 40, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeText.y = 250; self.addChild(closeText); self.visible = false; self.down = function (x, y, obj) { self.visible = false; }; self.updateLeaderboard = function () { var currentScore = LK.getScore(); currentScoreText.setText('Your Score: ' + currentScore); // Get stored high scores or initialize empty array var highScores = storage.highScores || []; // Add current score to the list var allScores = highScores.slice(); allScores.push(currentScore); // Sort scores in descending order allScores.sort(function (a, b) { return b - a; }); // Keep only top 10 scores allScores = allScores.slice(0, 10); // Find player's position var playerPosition = 1; for (var i = 0; i < allScores.length; i++) { if (allScores[i] === currentScore) { playerPosition = i + 1; break; } } positionText.setText('Your Position: #' + playerPosition); // Display top scores var scoresDisplay = 'TOP SCORES:\n'; for (var i = 0; i < Math.min(5, allScores.length); i++) { var highlight = allScores[i] === currentScore ? ' <- YOU' : ''; scoresDisplay += '#' + (i + 1) + ': ' + allScores[i] + highlight + '\n'; } scoresText.setText(scoresDisplay); // Save high scores back to storage (without current score) storage.highScores = highScores; }; return self; }); var MoneyIcon = Container.expand(function (amount) { var self = Container.call(this); var moneyGraphics = self.attachAsset('money', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); var moneyText = new Text2('+$' + amount, { size: 30, fill: 0xFFD700 }); moneyText.anchor.set(0.5, 0.5); moneyText.x = 30; self.addChild(moneyText); self.lifeTime = 120; // 2 seconds at 60fps self.floatSpeed = -2; self.update = function () { self.y += self.floatSpeed; self.alpha -= 0.02; self.lifeTime--; if (self.lifeTime <= 0 || self.alpha <= 0) { self.destroy(); var index = moneyIcons.indexOf(self); if (index > -1) { moneyIcons.splice(index, 1); } } }; return self; }); var MoneyScreen = Container.expand(function () { var self = Container.call(this); var background = LK.getAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 6, tint: 0x000000, alpha: 0.8 }); self.addChild(background); var titleText = new Text2('Money Status', { size: 80, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.y = -150; self.addChild(titleText); var moneyIcon = self.attachAsset('money', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, y: -50 }); var currentMoneyText = new Text2('$' + money, { size: 120, fill: 0xFFD700 }); currentMoneyText.anchor.set(0.5, 0.5); currentMoneyText.y = 50; self.addChild(currentMoneyText); var closeText = new Text2('Tap to close', { size: 40, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeText.y = 150; self.addChild(closeText); self.visible = false; self.down = function (x, y, obj) { self.visible = false; }; self.update = function () { if (self.visible) { currentMoneyText.setText('$' + money); } }; return self; }); var PlayerBase = Container.expand(function () { var self = Container.call(this); var baseGraphics = self.attachAsset('playerBase', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3000; self.maxHealth = 3000; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 300); healthText.setText('Base Health: ' + self.health + '/' + self.maxHealth); if (self.health <= 0) { gameOver = true; // Save high score before showing game over screen var currentScore = LK.getScore(); var highScores = storage.highScores || []; highScores.push(currentScore); highScores.sort(function (a, b) { return b - a; }); storage.highScores = highScores.slice(0, 10); // Keep top 10 LK.showGameOver(); } }; return self; }); var RapidFireBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, tint: 0x00FF00 }); self.speed = 12; self.damage = 15; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.explode(); } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = rapidFireBullets.indexOf(self); if (index > -1) { rapidFireBullets.splice(index, 1); } } }; self.explode = function () { // Check for zombie hits for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (self.intersects(zombie)) { zombie.takeDamage(self.damage); break; } } // Check for enemy bot hits for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; if (self.intersects(bot)) { bot.takeDamage(self.damage); break; } } self.destroy(); var index = rapidFireBullets.indexOf(self); if (index > -1) { rapidFireBullets.splice(index, 1); } }; return self; }); var RapidFireTower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, tint: 0x00FF00 }); self.health = 150; self.maxHealth = 150; self.damage = 15; self.range = 250; self.shootCooldown = 0; self.update = function () { var target = self.findNearestEnemy(); if (target && self.shootCooldown <= 0) { self.shootAt(target); self.shootCooldown = 15; // Very fast firing } if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.findNearestEnemy = function () { var nearest = null; var minDistance = Infinity; // Check zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = zombie; } } // Check enemy bots for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = bot; } } return nearest; }; self.shootAt = function (target) { var bullet = new RapidFireBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = target.x; bullet.targetY = target.y; bullet.damage = self.damage; rapidFireBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { self.destroy(); var index = rapidFireTowers.indexOf(self); if (index > -1) { rapidFireTowers.splice(index, 1); } }; return self; }); var ReviveButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.0, tint: 0xFF6666 }); var heroIcon = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, x: -80, y: -15, tint: 0xFFFFFF }); var buttonText = new Text2('Revive Hero', { size: 50, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.y = -10; self.addChild(buttonText); var costText = new Text2('Cost: $50', { size: 35, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0.5); costText.y = 30; self.addChild(costText); var moneyIcon = self.attachAsset('money', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, x: -30, y: 30 }); self.visible = false; self.down = function (x, y, obj) { // Revive hero if dead and have enough money if (hero.health <= 0 && money >= 50) { // Revive hero hero.health = hero.maxHealth; hero.alpha = 1.0; // Make hero fully visible again money -= 50; moneyText.setText('Money: $' + money); // Flash green to show successful revive LK.effects.flashObject(self, 0x00FF00, 300); // Hide revive button after use self.visible = false; } else { // Flash red if can't revive LK.effects.flashObject(self, 0xFF0000, 300); } }; self.update = function () { // Show revive button when hero is dead and has enough money if (hero.health <= 0 && money >= 50) { self.visible = true; } else { self.visible = false; } }; return self; }); var SniperBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.8, scaleY: 1.8, tint: 0x0088FF }); self.speed = 15; self.damage = 120; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.explode(); } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = sniperBullets.indexOf(self); if (index > -1) { sniperBullets.splice(index, 1); } } }; self.explode = function () { // Check for zombie hits for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (self.intersects(zombie)) { zombie.takeDamage(self.damage); break; } } // Check for enemy bot hits for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; if (self.intersects(bot)) { bot.takeDamage(self.damage); break; } } self.destroy(); var index = sniperBullets.indexOf(self); if (index > -1) { sniperBullets.splice(index, 1); } }; return self; }); var SniperTower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('defenseTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2, tint: 0x0088FF }); self.health = 250; self.maxHealth = 250; self.damage = 120; self.range = 600; self.shootCooldown = 0; self.update = function () { var target = self.findNearestEnemy(); if (target && self.shootCooldown <= 0) { self.shootAt(target); self.shootCooldown = 80; // Slow but powerful } if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.findNearestEnemy = function () { var nearest = null; var minDistance = Infinity; // Check zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = zombie; } } // Check enemy bots for (var i = 0; i < enemyBots.length; i++) { var bot = enemyBots[i]; var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2)); if (distance < minDistance && distance < self.range) { minDistance = distance; nearest = bot; } } return nearest; }; self.shootAt = function (target) { var bullet = new SniperBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = target.x; bullet.targetY = target.y; bullet.damage = self.damage; sniperBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { self.destroy(); var index = sniperTowers.indexOf(self); if (index > -1) { sniperTowers.splice(index, 1); } }; return self; }); var StartWaveButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 1.5, tint: 0x00FF00 }); var buttonText = new Text2('Start Wave ' + (wave + 1), { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.visible = false; self.down = function (x, y, obj) { if (self.visible) { // Start next wave wave++; zombiesSpawned = 0; zombiesPerWave += 3 + Math.floor(wave / 3); waveText.setText('Wave: ' + wave); resources += Math.max(15, 35 - wave); resourceText.setText('Resources: ' + resources); self.visible = false; waveInProgress = true; LK.effects.flashObject(self, 0x00FF00, 300); } }; self.update = function () { if (self.visible) { buttonText.setText('Start Wave ' + wave); } }; return self; }); var TowerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 30; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.speed) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.explode(); } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = towerBullets.indexOf(self); if (index > -1) { towerBullets.splice(index, 1); } } }; self.explode = function () { // Check for zombie hits for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (self.intersects(zombie)) { zombie.takeDamage(self.damage); break; } } // Check for boss hits for (var i = 0; i < bosses.length; i++) { var boss = bosses[i]; if (self.intersects(boss)) { boss.takeDamage(self.damage); break; } } self.destroy(); var index = towerBullets.indexOf(self); if (index > -1) { towerBullets.splice(index, 1); } }; return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); // Scale health and damage based on current wave var healthMultiplier = 1 + (wave - 1) * 0.3; // 30% more health per wave var damageMultiplier = 1 + (wave - 1) * 0.2; // 20% more damage per wave var speedMultiplier = 1 + (wave - 1) * 0.1; // 10% faster per wave self.health = Math.floor(100 * healthMultiplier); self.maxHealth = Math.floor(100 * healthMultiplier); self.speed = Math.min(3, 1 * speedMultiplier); // Cap speed at 3 self.damage = Math.floor(20 * damageMultiplier); self.target = null; self.attackCooldown = 0; self.update = function () { // Find nearest target (hero, towers, or base) var target = self.findNearestTarget(); if (target) { self.target = target; } if (!self.target) { self.target = playerBase; } // Move towards target var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 50) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { // Attack target if (self.attackCooldown <= 0) { if (self.target === playerBase) { playerBase.takeDamage(self.damage); } else if (self.target === hero) { hero.takeDamage(self.damage); } else if (self.target.takeDamage) { // Attack tower self.target.takeDamage(self.damage); } self.attackCooldown = 60; // 1 second cooldown } } if (self.attackCooldown > 0) { self.attackCooldown--; } }; self.findNearestTarget = function () { var targets = []; var attackRange = 400; // Range to look for targets // Add hero as target if in range and alive if (hero.health > 0) { var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2)); if (distanceToHero < attackRange) { targets.push({ target: hero, distance: distanceToHero }); } } // Add defense towers as targets for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < attackRange) { targets.push({ target: tower, distance: distance }); } } // Add big defense towers as targets for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < attackRange) { targets.push({ target: tower, distance: distance }); } } // Add rapid fire towers as targets for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < attackRange) { targets.push({ target: tower, distance: distance }); } } // Add sniper towers as targets for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2)); if (distance < attackRange) { targets.push({ target: tower, distance: distance }); } } // Add player base as target var distanceToBase = Math.sqrt(Math.pow(playerBase.x - self.x, 2) + Math.pow(playerBase.y - self.y, 2)); if (distanceToBase < attackRange) { targets.push({ target: playerBase, distance: distanceToBase }); } // Return nearest target if (targets.length > 0) { targets.sort(function (a, b) { return a.distance - b.distance; }); return targets[0].target; } return null; }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); LK.setScore(LK.getScore() + 10); scoreText.setText('Score: ' + LK.getScore()); // Add money and spawn money icon var moneyEarned = 5; money += moneyEarned; moneyText.setText('Money: $' + money); var moneyIcon = new MoneyIcon(moneyEarned); moneyIcon.x = self.x; moneyIcon.y = self.y; moneyIcons.push(moneyIcon); game.addChild(moneyIcon); self.destroy(); var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2a2a2a }); /**** * Game Code ****/ // Game state variables var gameOver = false; var wave = 1; var zombiesSpawned = 0; var zombiesPerWave = 5; var spawnTimer = 0; var botSpawnTimer = 0; var resources = 100; var money = 0; var placingTower = false; var placingBigTower = false; var placingRapidFireTower = false; var placingSniperTower = false; var waveInProgress = true; // Game objects arrays var zombies = []; var enemyBots = []; var bosses = []; var defenseTowers = []; var bigDefenseTowers = []; var rapidFireTowers = []; var sniperTowers = []; var towerBullets = []; var bigTowerBullets = []; var rapidFireBullets = []; var sniperBullets = []; var heroBullets = []; var enemyBullets = []; var moneyIcons = []; // Create player base var playerBase = new PlayerBase(); playerBase.x = 1024; playerBase.y = 2400; game.addChild(playerBase); // Create hero var hero = new Hero(); hero.x = 1024; hero.y = 2200; game.addChild(hero); // Create UI elements var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.topRight.addChild(scoreText); var healthText = new Text2('Base Health: 3000/3000', { size: 50, fill: 0xFFFFFF }); healthText.anchor.set(0, 0); healthText.x = -400; LK.gui.topRight.addChild(healthText); var waveText = new Text2('Wave: 1', { size: 55, fill: 0xFFFF00 }); waveText.anchor.set(0.5, 0); LK.gui.top.addChild(waveText); var resourceText = new Text2('Resources: 100', { size: 45, fill: 0x00FF00 }); resourceText.anchor.set(0, 0); LK.gui.bottomLeft.addChild(resourceText); var moneyText = new Text2('Money: $0', { size: 45, fill: 0xFFD700 }); moneyText.anchor.set(0, 0); moneyText.y = 120; moneyText.down = function (x, y, obj) { moneyScreen.visible = true; }; LK.gui.topLeft.addChild(moneyText); var heroHealthText = new Text2('Hero Health: 300/300', { size: 50, fill: 0xFF6666 }); heroHealthText.anchor.set(0, 0); heroHealthText.y = 180; LK.gui.topLeft.addChild(heroHealthText); // Create buy tower button var buyTowerButton = new BuyTowerButton(); buyTowerButton.x = 120; buyTowerButton.y = -120; LK.gui.bottomLeft.addChild(buyTowerButton); // Create buy big tower button var buyBigTowerButton = new BuyBigTowerButton(); buyBigTowerButton.x = 280; buyBigTowerButton.y = -120; LK.gui.bottomLeft.addChild(buyBigTowerButton); // Create buy rapid fire tower button var buyRapidFireTowerButton = new BuyRapidFireTowerButton(); buyRapidFireTowerButton.x = 440; buyRapidFireTowerButton.y = -120; LK.gui.bottomLeft.addChild(buyRapidFireTowerButton); // Create buy sniper tower button var buySniperTowerButton = new BuySniperTowerButton(); buySniperTowerButton.x = 600; buySniperTowerButton.y = -120; LK.gui.bottomLeft.addChild(buySniperTowerButton); // Create start wave button var startWaveButton = new StartWaveButton(); startWaveButton.x = 0; startWaveButton.y = -200; LK.gui.center.addChild(startWaveButton); // Create money screen var moneyScreen = new MoneyScreen(); moneyScreen.x = 0; moneyScreen.y = 0; LK.gui.center.addChild(moneyScreen); // Create revive button var reviveButton = new ReviveButton(); reviveButton.x = 0; reviveButton.y = 100; LK.gui.center.addChild(reviveButton); // Create leaderboard screen var leaderboardScreen = new LeaderboardScreen(); leaderboardScreen.x = 0; leaderboardScreen.y = 0; LK.gui.center.addChild(leaderboardScreen); // Create leaderboard button var leaderboardButton = new Text2('LEADERBOARD', { size: 40, fill: 0xFFD700 }); leaderboardButton.anchor.set(0.5, 0); leaderboardButton.y = 300; leaderboardButton.down = function (x, y, obj) { leaderboardScreen.updateLeaderboard(); leaderboardScreen.visible = true; }; LK.gui.topLeft.addChild(leaderboardButton); // Game control functions function spawnZombie() { var zombie = new Zombie(); // Spawn from random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // Top zombie.x = Math.random() * 2048; zombie.y = 0; } else if (edge === 1) { // Right zombie.x = 2048; zombie.y = Math.random() * 2732; } else if (edge === 2) { // Bottom zombie.x = Math.random() * 2048; zombie.y = 2732; } else { // Left zombie.x = 0; zombie.y = Math.random() * 2732; } zombies.push(zombie); game.addChild(zombie); zombiesSpawned++; } function spawnEnemyBot() { var botTypes = ['artilleryBot', 'assaultBot', 'disruptionBot', 'repairBot']; var randomType = botTypes[Math.floor(Math.random() * botTypes.length)]; var bot = new EnemyBot(randomType); bot.x = Math.random() * 1800 + 124; bot.y = Math.random() * 1000 + 200; enemyBots.push(bot); game.addChild(bot); } function buildDefenseTower(x, y) { var towerCost = 25 + Math.floor(wave / 2) * 5; // Increase cost every 2 waves var resourceCost = 50 + Math.floor(wave / 3) * 10; // Increase resource cost every 3 waves if (resources >= resourceCost && money >= towerCost) { var tower = new DefenseTower(); tower.x = x; tower.y = y; defenseTowers.push(tower); game.addChild(tower); resources -= resourceCost; money -= towerCost; resourceText.setText('Resources: ' + resources); moneyText.setText('Money: $' + money); } } function buildBigDefenseTower(x, y) { var towerCost = 100 + Math.floor(wave / 2) * 15; // Increase cost every 2 waves var resourceCost = 100 + Math.floor(wave / 3) * 20; // Increase resource cost every 3 waves if (resources >= resourceCost && money >= towerCost) { var tower = new BigDefenseTower(); tower.x = x; tower.y = y; bigDefenseTowers.push(tower); game.addChild(tower); resources -= resourceCost; money -= towerCost; resourceText.setText('Resources: ' + resources); moneyText.setText('Money: $' + money); } } function buildRapidFireTower(x, y) { var towerCost = 40; // Money cost for rapid fire tower if (resources >= 75 && money >= towerCost) { var tower = new RapidFireTower(); tower.x = x; tower.y = y; rapidFireTowers.push(tower); game.addChild(tower); resources -= 75; money -= towerCost; resourceText.setText('Resources: ' + resources); moneyText.setText('Money: $' + money); } } function buildSniperTower(x, y) { var towerCost = 75; // Money cost for sniper tower if (resources >= 125 && money >= towerCost) { var tower = new SniperTower(); tower.x = x; tower.y = y; sniperTowers.push(tower); game.addChild(tower); resources -= 125; money -= towerCost; resourceText.setText('Resources: ' + resources); moneyText.setText('Money: $' + money); } } function spawnBoss() { var boss = new Boss(); // Spawn boss from top center boss.x = 1024; boss.y = 0; bosses.push(boss); game.addChild(boss); } // Event handlers game.down = function (x, y, obj) { if (placingTower) { // Tower placement mode var canBuild = true; var minDistance = 120; // Check distance from other towers for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } // Check distance from big towers for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } // Check distance from base var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2)); if (distanceToBase < 150) { canBuild = false; } // Check distance from hero var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2)); if (distanceToHero < 100) { canBuild = false; } if (canBuild && y < 2300) { // Don't build too close to base area buildDefenseTower(x, y); placingTower = false; // Exit placement mode after building } } else if (placingBigTower) { // Big tower placement mode var canBuild = true; var minDistance = 150; // Check distance from regular towers for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } // Check distance from other big towers for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } // Check distance from base var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2)); if (distanceToBase < 200) { canBuild = false; } // Check distance from hero var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2)); if (distanceToHero < 120) { canBuild = false; } if (canBuild && y < 2300) { // Don't build too close to base area buildBigDefenseTower(x, y); placingBigTower = false; // Exit placement mode after building } } else if (placingRapidFireTower) { // Rapid fire tower placement mode var canBuild = true; var minDistance = 100; // Check distance from all towers for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2)); if (distanceToBase < 120) { canBuild = false; } var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2)); if (distanceToHero < 80) { canBuild = false; } if (canBuild && y < 2300) { buildRapidFireTower(x, y); placingRapidFireTower = false; } } else if (placingSniperTower) { // Sniper tower placement mode var canBuild = true; var minDistance = 140; // Check distance from all towers for (var i = 0; i < defenseTowers.length; i++) { var tower = defenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } for (var i = 0; i < bigDefenseTowers.length; i++) { var tower = bigDefenseTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } for (var i = 0; i < rapidFireTowers.length; i++) { var tower = rapidFireTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } for (var i = 0; i < sniperTowers.length; i++) { var tower = sniperTowers[i]; var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2)); if (distance < minDistance) { canBuild = false; break; } } var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2)); if (distanceToBase < 180) { canBuild = false; } var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2)); if (distanceToHero < 100) { canBuild = false; } if (canBuild && y < 2300) { buildSniperTower(x, y); placingSniperTower = false; } } else { // Normal mode - move hero (only if alive) if (hero.health > 0) { hero.moveTo(x, y); } } }; // Start background music LK.playMusic('Zombiewarmuic'); // Main game loop game.update = function () { if (gameOver) return; // Resource generation if (LK.ticks % 180 === 0) { // Every 3 seconds resources += 10; resourceText.setText('Resources: ' + resources); } // Zombie spawning - faster spawn rate at higher waves (only if wave is in progress) if (waveInProgress && zombiesSpawned < zombiesPerWave) { spawnTimer++; var zombieSpawnInterval = Math.max(60, 120 - (wave - 1) * 8); // Faster spawning each wave, minimum 1 second if (spawnTimer >= zombieSpawnInterval) { spawnZombie(); spawnTimer = 0; } } // Enemy bot spawning - faster spawn rate at higher waves (only if wave is in progress) if (waveInProgress) { botSpawnTimer++; var botSpawnInterval = Math.max(300, 600 - (wave - 1) * 30); // Faster spawning each wave, minimum 5 seconds if (botSpawnTimer >= botSpawnInterval) { spawnEnemyBot(); // Spawn additional bots at higher waves if (wave >= 5 && Math.random() < 0.3) { spawnEnemyBot(); // 30% chance for second bot } if (wave >= 8 && Math.random() < 0.2) { spawnEnemyBot(); // 20% chance for third bot } botSpawnTimer = 0; } } // Check for wave completion if (waveInProgress && zombiesSpawned >= zombiesPerWave && zombies.length === 0) { // Wave completed - check if it's time for boss if (wave === 9) { // After wave 9, spawn boss spawnBoss(); waveText.setText('BOSS WAVE!'); } else { // Regular wave completed - show start button for next wave waveInProgress = false; startWaveButton.visible = true; } } // Win condition - boss must be defeated if (wave >= 9 && zombies.length === 0 && enemyBots.length === 0 && bosses.length === 0) { // Save high score before showing win screen var currentScore = LK.getScore(); var highScores = storage.highScores || []; highScores.push(currentScore); highScores.sort(function (a, b) { return b - a; }); storage.highScores = highScores.slice(0, 10); // Keep top 10 LK.showYouWin(); } // Update all bullets for (var i = towerBullets.length - 1; i >= 0; i--) { var bullet = towerBullets[i]; if (bullet.destroyed) { towerBullets.splice(i, 1); } } for (var i = bigTowerBullets.length - 1; i >= 0; i--) { var bullet = bigTowerBullets[i]; if (bullet.destroyed) { bigTowerBullets.splice(i, 1); } } for (var i = rapidFireBullets.length - 1; i >= 0; i--) { var bullet = rapidFireBullets[i]; if (bullet.destroyed) { rapidFireBullets.splice(i, 1); } } for (var i = sniperBullets.length - 1; i >= 0; i--) { var bullet = sniperBullets[i]; if (bullet.destroyed) { sniperBullets.splice(i, 1); } } for (var i = heroBullets.length - 1; i >= 0; i--) { var bullet = heroBullets[i]; if (bullet.destroyed) { heroBullets.splice(i, 1); } } for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.destroyed) { enemyBullets.splice(i, 1); } } // Update money icons for (var i = moneyIcons.length - 1; i >= 0; i--) { var icon = moneyIcons[i]; if (icon.destroyed) { moneyIcons.splice(i, 1); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BigDefenseTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFF4444
});
self.health = 500;
self.maxHealth = 500;
self.damage = 80;
self.range = 450;
self.shootCooldown = 0;
self.update = function () {
var target = self.findNearestEnemy();
if (target && self.shootCooldown <= 0) {
self.shootAt(target);
self.shootCooldown = 35; // Slightly faster than regular tower
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.findNearestEnemy = function () {
var nearest = null;
var minDistance = Infinity;
// Check zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = zombie;
}
}
// Check enemy bots
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = bot;
}
}
return nearest;
};
self.shootAt = function (target) {
var bullet = new BigTowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
bigTowerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
self.destroy();
var index = bigDefenseTowers.indexOf(self);
if (index > -1) {
bigDefenseTowers.splice(index, 1);
}
};
return self;
});
var BigTowerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFF4444
});
self.speed = 10;
self.damage = 80;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.explode();
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
var index = bigTowerBullets.indexOf(self);
if (index > -1) {
bigTowerBullets.splice(index, 1);
}
}
};
self.explode = function () {
// Check for zombie hits
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (self.intersects(zombie)) {
zombie.takeDamage(self.damage);
break;
}
}
// Check for enemy bot hits
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
if (self.intersects(bot)) {
bot.takeDamage(self.damage);
break;
}
}
self.destroy();
var index = bigTowerBullets.indexOf(self);
if (index > -1) {
bigTowerBullets.splice(index, 1);
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
self.health = 4000;
self.maxHealth = 4000;
self.speed = 0.8; // Slower than regular zombies
self.damage = 100; // High damage
self.target = null;
self.attackCooldown = 0;
self.specialAttackCooldown = 0;
self.update = function () {
if (!self.target) {
self.target = playerBase;
}
// Move towards target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 80) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Attack target
if (self.attackCooldown <= 0) {
if (self.target === playerBase) {
playerBase.takeDamage(self.damage);
}
self.attackCooldown = 90; // Slower attack rate
}
}
// Special AOE attack every 5 seconds
if (self.specialAttackCooldown <= 0) {
self.aoeAttack();
self.specialAttackCooldown = 300; // 5 seconds
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (self.specialAttackCooldown > 0) {
self.specialAttackCooldown--;
}
};
self.aoeAttack = function () {
// AOE damage to all towers and hero in range
var aoeRange = 400;
LK.effects.flashObject(self, 0xFFFF00, 500);
// Damage hero
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
if (distanceToHero < aoeRange) {
hero.takeDamage(50);
}
// Damage all towers in range
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < aoeRange) {
tower.takeDamage(80);
}
}
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < aoeRange) {
tower.takeDamage(80);
}
}
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < aoeRange) {
tower.takeDamage(80);
}
}
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < aoeRange) {
tower.takeDamage(80);
}
}
LK.getSound('explosion').play();
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('explosion').play();
LK.setScore(LK.getScore() + 500);
scoreText.setText('Score: ' + LK.getScore());
// Boss gives lots of money
var moneyEarned = 200;
money += moneyEarned;
moneyText.setText('Money: $' + money);
var moneyIcon = new MoneyIcon(moneyEarned);
moneyIcon.x = self.x;
moneyIcon.y = self.y;
moneyIcons.push(moneyIcon);
game.addChild(moneyIcon);
self.destroy();
var index = bosses.indexOf(self);
if (index > -1) {
bosses.splice(index, 1);
}
};
return self;
});
var BuyBigTowerButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFF4444
});
var towerIcon = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
tint: 0xFF4444,
y: -15
});
var buttonText = new Text2('Big Tower', {
size: 28,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = 15;
self.addChild(buttonText);
var costText = new Text2('R:100 $100', {
size: 22,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 35;
self.addChild(costText);
self.down = function (x, y, obj) {
var towerCost = 100;
if (resources >= 100 && money >= towerCost) {
// Enable big tower placement mode
placingBigTower = true;
LK.effects.flashObject(self, 0x00FF00, 300);
} else {
// Flash red if can't afford
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.update = function () {
var towerCost = 100 + Math.floor(wave / 2) * 15;
var resourceCost = 100 + Math.floor(wave / 3) * 20;
if (resources >= resourceCost && money >= towerCost) {
buttonGraphics.tint = 0xFF2222; // Red when affordable
buttonText.setText('Big Tower');
costText.setText('R:' + resourceCost + ' $' + towerCost);
} else {
buttonGraphics.tint = 0x808080; // Gray when not affordable
buttonText.setText('Big Tower');
costText.setText('R:' + resourceCost + ' $' + towerCost);
}
};
return self;
});
var BuyRapidFireTowerButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
tint: 0x00FF00
});
var towerIcon = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
tint: 0x00FF00,
y: -15
});
var buttonText = new Text2('Rapid', {
size: 28,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = 15;
self.addChild(buttonText);
var costText = new Text2('R:75 $40', {
size: 22,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 35;
self.addChild(costText);
self.down = function (x, y, obj) {
var towerCost = 40;
if (resources >= 75 && money >= towerCost) {
// Enable rapid fire tower placement mode
placingRapidFireTower = true;
LK.effects.flashObject(self, 0x00FF00, 300);
} else {
// Flash red if can't afford
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.update = function () {
var towerCost = 40;
if (resources >= 75 && money >= towerCost) {
buttonGraphics.tint = 0x00AA00; // Green when affordable
buttonText.setText('Rapid');
costText.setText('R:75 $40');
} else {
buttonGraphics.tint = 0x808080; // Gray when not affordable
buttonText.setText('Rapid');
costText.setText('R:75 $40');
}
};
return self;
});
var BuySniperTowerButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
tint: 0x0088FF
});
var towerIcon = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0x0088FF,
y: -15
});
var buttonText = new Text2('Sniper', {
size: 26,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = 15;
self.addChild(buttonText);
var costText = new Text2('R:125 $75', {
size: 20,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 35;
self.addChild(costText);
self.down = function (x, y, obj) {
var towerCost = 75;
if (resources >= 125 && money >= towerCost) {
// Enable sniper tower placement mode
placingSniperTower = true;
LK.effects.flashObject(self, 0x00FF00, 300);
} else {
// Flash red if can't afford
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.update = function () {
var towerCost = 75;
if (resources >= 125 && money >= towerCost) {
buttonGraphics.tint = 0x0066CC; // Blue when affordable
buttonText.setText('Sniper');
costText.setText('R:125 $75');
} else {
buttonGraphics.tint = 0x808080; // Gray when not affordable
buttonText.setText('Sniper');
costText.setText('R:125 $75');
}
};
return self;
});
var BuyTowerButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5
});
var towerIcon = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4,
y: -15
});
var buttonText = new Text2('Tower', {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = 15;
self.addChild(buttonText);
var costText = new Text2('R:50 $25', {
size: 24,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 35;
self.addChild(costText);
self.down = function (x, y, obj) {
var towerCost = 25;
if (resources >= 50 && money >= towerCost) {
// Enable tower placement mode
placingTower = true;
LK.effects.flashObject(self, 0x00FF00, 300);
} else {
// Flash red if can't afford
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.update = function () {
var towerCost = 25 + Math.floor(wave / 2) * 5;
var resourceCost = 50 + Math.floor(wave / 3) * 10;
if (resources >= resourceCost && money >= towerCost) {
buttonGraphics.tint = 0x4CAF50; // Green when affordable
buttonText.setText('Tower');
costText.setText('R:' + resourceCost + ' $' + towerCost);
} else {
buttonGraphics.tint = 0x808080; // Gray when not affordable
buttonText.setText('Tower');
costText.setText('R:' + resourceCost + ' $' + towerCost);
}
};
return self;
});
var DefenseTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 200;
self.maxHealth = 200;
self.damage = 30;
self.range = 300;
self.shootCooldown = 0;
self.update = function () {
var target = self.findNearestEnemy();
if (target && self.shootCooldown <= 0) {
self.shootAt(target);
self.shootCooldown = 45; // 0.75 second cooldown
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.findNearestEnemy = function () {
var nearest = null;
var minDistance = Infinity;
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = zombie;
}
}
// Check bosses
for (var i = 0; i < bosses.length; i++) {
var boss = bosses[i];
var distance = Math.sqrt(Math.pow(boss.x - self.x, 2) + Math.pow(boss.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = boss;
}
}
return nearest;
};
self.shootAt = function (target) {
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
towerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
self.destroy();
var index = defenseTowers.indexOf(self);
if (index > -1) {
defenseTowers.splice(index, 1);
}
};
return self;
});
var EnemyBot = Container.expand(function (botType) {
var self = Container.call(this);
var botGraphics = self.attachAsset(botType, {
anchorX: 0.5,
anchorY: 0.5
});
self.botType = botType;
// Scale bot stats based on current wave
var healthMultiplier = 1 + (wave - 1) * 0.25; // 25% more health per wave
var damageMultiplier = 1 + (wave - 1) * 0.15; // 15% more damage per wave
self.health = Math.floor(150 * healthMultiplier);
self.maxHealth = Math.floor(150 * healthMultiplier);
self.damage = Math.floor(25 * damageMultiplier);
self.range = 350;
self.shootCooldown = 0;
// Set specific properties based on bot type
if (botType === 'artilleryBot') {
self.damage = 60;
self.range = 400;
self.shootCooldown = 90; // Slower but more powerful
} else if (botType === 'assaultBot') {
self.damage = 20;
self.range = 250;
self.shootCooldown = 20; // Faster firing
} else if (botType === 'disruptionBot') {
self.damage = 15;
self.range = 300;
self.shootCooldown = 120; // Special ability cooldown
} else if (botType === 'repairBot') {
self.damage = 0;
self.range = 200;
self.shootCooldown = 180; // Repair cooldown
}
self.update = function () {
var target = self.findTarget();
if (target) {
// Move towards target if not in range
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.range) {
// Move towards target
var speed = 1.5; // Bot movement speed
self.x += dx / distance * speed;
self.y += dy / distance * speed;
}
} else {
// No target in range, move towards player base
var dx = playerBase.x - self.x;
var dy = playerBase.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 80) {
// Don't get too close to base
var speed = 1.2; // Slightly slower when moving to base
self.x += dx / distance * speed;
self.y += dy / distance * speed;
}
}
if (target && self.shootCooldown <= 0) {
if (self.botType === 'repairBot') {
self.repairAllies();
} else {
self.shootAt(target);
}
self.shootCooldown = self.getBaseCooldown();
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.findTarget = function () {
var targets = [];
// Add player base as target
var distanceToBase = Math.sqrt(Math.pow(playerBase.x - self.x, 2) + Math.pow(playerBase.y - self.y, 2));
if (distanceToBase < self.range) {
targets.push({
target: playerBase,
distance: distanceToBase
});
}
// Add hero as target
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
if (distanceToHero < self.range) {
targets.push({
target: hero,
distance: distanceToHero
});
}
// Add defense towers as targets
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < self.range) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add big defense towers as targets
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < self.range) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add rapid fire towers as targets
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < self.range) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add sniper towers as targets
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < self.range) {
targets.push({
target: tower,
distance: distance
});
}
}
// Return nearest target
if (targets.length > 0) {
targets.sort(function (a, b) {
return a.distance - b.distance;
});
return targets[0].target;
}
return null;
};
self.shootAt = function (target) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
bullet.isAOE = self.botType === 'artilleryBot';
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.repairAllies = function () {
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
if (bot !== self) {
var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2));
if (distance < self.range) {
bot.health = Math.min(bot.health + 30, bot.maxHealth);
LK.effects.flashObject(bot, 0x00ff00, 300);
}
}
}
};
self.getBaseCooldown = function () {
if (self.botType === 'artilleryBot') return 90;
if (self.botType === 'assaultBot') return 20;
if (self.botType === 'disruptionBot') return 120;
if (self.botType === 'repairBot') return 180;
return 60;
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('explosion').play();
LK.setScore(LK.getScore() + 25);
scoreText.setText('Score: ' + LK.getScore());
// Add money and spawn money icon
var moneyEarned = 15;
money += moneyEarned;
moneyText.setText('Money: $' + money);
var moneyIcon = new MoneyIcon(moneyEarned);
moneyIcon.x = self.x;
moneyIcon.y = self.y;
moneyIcons.push(moneyIcon);
game.addChild(moneyIcon);
self.destroy();
var index = enemyBots.indexOf(self);
if (index > -1) {
enemyBots.splice(index, 1);
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 25;
self.targetX = 0;
self.targetY = 0;
self.isAOE = false;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.explode();
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
var index = enemyBullets.indexOf(self);
if (index > -1) {
enemyBullets.splice(index, 1);
}
}
};
self.explode = function () {
if (self.isAOE) {
// AOE damage
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
alpha: 0.7
});
game.addChild(explosion);
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Damage everything in range
var explosionRange = 150;
if (self.intersects(playerBase)) {
playerBase.takeDamage(self.damage);
}
if (self.intersects(hero)) {
hero.takeDamage(self.damage);
}
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < explosionRange) {
tower.takeDamage(self.damage);
}
}
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < explosionRange) {
tower.takeDamage(self.damage);
}
}
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < explosionRange) {
tower.takeDamage(self.damage);
}
}
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < explosionRange) {
tower.takeDamage(self.damage);
}
}
LK.getSound('explosion').play();
} else {
// Single target damage
if (self.intersects(playerBase)) {
playerBase.takeDamage(self.damage);
} else if (self.intersects(hero)) {
hero.takeDamage(self.damage);
} else {
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
if (self.intersects(tower)) {
tower.takeDamage(self.damage);
break;
}
}
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
if (self.intersects(tower)) {
tower.takeDamage(self.damage);
break;
}
}
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
if (self.intersects(tower)) {
tower.takeDamage(self.damage);
break;
}
}
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
if (self.intersects(tower)) {
tower.takeDamage(self.damage);
break;
}
}
}
}
self.destroy();
var index = enemyBullets.indexOf(self);
if (index > -1) {
enemyBullets.splice(index, 1);
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 300;
self.maxHealth = 300;
self.speed = 3;
self.damage = 40;
self.shootCooldown = 0;
self.targetX = self.x;
self.targetY = self.y;
// Special abilities for boss waves
self.specialAttackCooldown = 0;
self.shieldCooldown = 0;
self.isShielded = false;
self.shieldDuration = 0;
self.update = function () {
// Only move and attack if alive
if (self.health > 0) {
// Move towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Auto-attack nearest enemy
var nearestEnemy = self.findNearestEnemy();
if (nearestEnemy && self.shootCooldown <= 0) {
self.shootAt(nearestEnemy);
self.shootCooldown = 30; // 0.5 second cooldown
}
// Special abilities during boss waves (wave 9+)
if (wave >= 9) {
// Special attack - shoots multiple bullets in a spread
if (self.specialAttackCooldown <= 0) {
self.specialAttack();
self.specialAttackCooldown = 300; // 5 seconds
}
// Shield ability - temporary damage immunity
if (self.shieldCooldown <= 0 && !self.isShielded) {
self.activateShield();
self.shieldCooldown = 600; // 10 seconds
}
} else {
// Reset special abilities when not in boss waves
self.specialAttackCooldown = 0;
self.shieldCooldown = 0;
self.isShielded = false;
self.shieldDuration = 0;
self.alpha = 1.0; // Ensure normal opacity
}
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
// Update special ability cooldowns
if (self.specialAttackCooldown > 0) {
self.specialAttackCooldown--;
}
if (self.shieldCooldown > 0) {
self.shieldCooldown--;
}
if (self.isShielded) {
self.shieldDuration--;
if (self.shieldDuration <= 0) {
self.isShielded = false;
self.alpha = 1.0; // Return to normal opacity
}
}
// Update health display
var healthStatus = self.isShielded ? ' (SHIELDED)' : '';
heroHealthText.setText('Hero Health: ' + Math.max(0, self.health) + '/' + self.maxHealth + healthStatus);
};
self.findNearestEnemy = function () {
var nearest = null;
var minDistance = Infinity;
// Check zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2));
if (distance < minDistance && distance < 400) {
minDistance = distance;
nearest = zombie;
}
}
// Check enemy bots
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2));
if (distance < minDistance && distance < 400) {
minDistance = distance;
nearest = bot;
}
}
// Check bosses
for (var i = 0; i < bosses.length; i++) {
var boss = bosses[i];
var distance = Math.sqrt(Math.pow(boss.x - self.x, 2) + Math.pow(boss.y - self.y, 2));
if (distance < minDistance && distance < 400) {
minDistance = distance;
nearest = boss;
}
}
return nearest;
};
self.shootAt = function (target) {
var bullet = new HeroBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
heroBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.specialAttack = function () {
// Fire 5 bullets in a spread pattern
var nearestEnemy = self.findNearestEnemy();
if (nearestEnemy) {
for (var i = 0; i < 5; i++) {
var bullet = new HeroBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate spread angle
var angleOffset = (i - 2) * 0.3; // Spread bullets in a fan
var dx = nearestEnemy.x - self.x;
var dy = nearestEnemy.y - self.y;
var angle = Math.atan2(dy, dx) + angleOffset;
var distance = 400; // Target distance
bullet.targetX = self.x + Math.cos(angle) * distance;
bullet.targetY = self.y + Math.sin(angle) * distance;
bullet.damage = self.damage * 1.5; // Increased damage for special attack
heroBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
LK.effects.flashObject(self, 0xFFFF00, 500); // Yellow flash for special attack
}
};
self.activateShield = function () {
self.isShielded = true;
self.shieldDuration = 180; // 3 seconds of shield
self.alpha = 0.7; // Make hero semi-transparent to show shield
LK.effects.flashObject(self, 0x00FFFF, 300); // Cyan flash for shield activation
};
self.moveTo = function (x, y) {
if (self.health > 0) {
self.targetX = x;
self.targetY = y;
}
};
self.takeDamage = function (amount) {
// Shield blocks damage during boss waves
if (self.isShielded) {
LK.effects.flashObject(self, 0x00FFFF, 200); // Cyan flash when shielded
return; // No damage taken while shielded
}
self.health -= amount;
// Prevent hero health from going below 1 - hero cannot die
if (self.health < 1) {
self.health = 1;
}
LK.effects.flashObject(self, 0xff0000, 300);
// Remove death condition - hero can no longer die
};
self.die = function () {
// Hero becomes translucent and stops moving when dead
self.alpha = 0.3;
self.targetX = self.x;
self.targetY = self.y;
heroHealthText.setText('Hero Health: 0/' + self.maxHealth + ' (DEAD)');
// Attack player base when hero dies
playerBase.takeDamage(self.damage * 2); // Double damage when hero dies
};
return self;
});
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.damage = 40;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.explode();
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
var index = heroBullets.indexOf(self);
if (index > -1) {
heroBullets.splice(index, 1);
}
}
};
self.explode = function () {
// Check for zombie hits
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (self.intersects(zombie)) {
zombie.takeDamage(self.damage);
self.destroy();
var index = heroBullets.indexOf(self);
if (index > -1) {
heroBullets.splice(index, 1);
}
return;
}
}
// Check for enemy bot hits
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
if (self.intersects(bot)) {
bot.takeDamage(self.damage);
self.destroy();
var index = heroBullets.indexOf(self);
if (index > -1) {
heroBullets.splice(index, 1);
}
return;
}
}
// Check for boss hits
for (var i = 0; i < bosses.length; i++) {
var boss = bosses[i];
if (self.intersects(boss)) {
boss.takeDamage(self.damage);
self.destroy();
var index = heroBullets.indexOf(self);
if (index > -1) {
heroBullets.splice(index, 1);
}
return;
}
}
self.destroy();
var index = heroBullets.indexOf(self);
if (index > -1) {
heroBullets.splice(index, 1);
}
};
return self;
});
var LeaderboardScreen = Container.expand(function () {
var self = Container.call(this);
var background = LK.getAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 8,
tint: 0x000000,
alpha: 0.9
});
self.addChild(background);
var titleText = new Text2('LEADERBOARD', {
size: 80,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -300;
self.addChild(titleText);
var currentScoreText = new Text2('Your Score: 0', {
size: 50,
fill: 0x00FF00
});
currentScoreText.anchor.set(0.5, 0.5);
currentScoreText.y = -200;
self.addChild(currentScoreText);
var positionText = new Text2('Your Position: #1', {
size: 45,
fill: 0xFFFFFF
});
positionText.anchor.set(0.5, 0.5);
positionText.y = -150;
self.addChild(positionText);
var scoresText = new Text2('', {
size: 35,
fill: 0xFFFFFF
});
scoresText.anchor.set(0.5, 0.5);
scoresText.y = 50;
self.addChild(scoresText);
var closeText = new Text2('Tap to close', {
size: 40,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeText.y = 250;
self.addChild(closeText);
self.visible = false;
self.down = function (x, y, obj) {
self.visible = false;
};
self.updateLeaderboard = function () {
var currentScore = LK.getScore();
currentScoreText.setText('Your Score: ' + currentScore);
// Get stored high scores or initialize empty array
var highScores = storage.highScores || [];
// Add current score to the list
var allScores = highScores.slice();
allScores.push(currentScore);
// Sort scores in descending order
allScores.sort(function (a, b) {
return b - a;
});
// Keep only top 10 scores
allScores = allScores.slice(0, 10);
// Find player's position
var playerPosition = 1;
for (var i = 0; i < allScores.length; i++) {
if (allScores[i] === currentScore) {
playerPosition = i + 1;
break;
}
}
positionText.setText('Your Position: #' + playerPosition);
// Display top scores
var scoresDisplay = 'TOP SCORES:\n';
for (var i = 0; i < Math.min(5, allScores.length); i++) {
var highlight = allScores[i] === currentScore ? ' <- YOU' : '';
scoresDisplay += '#' + (i + 1) + ': ' + allScores[i] + highlight + '\n';
}
scoresText.setText(scoresDisplay);
// Save high scores back to storage (without current score)
storage.highScores = highScores;
};
return self;
});
var MoneyIcon = Container.expand(function (amount) {
var self = Container.call(this);
var moneyGraphics = self.attachAsset('money', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
var moneyText = new Text2('+$' + amount, {
size: 30,
fill: 0xFFD700
});
moneyText.anchor.set(0.5, 0.5);
moneyText.x = 30;
self.addChild(moneyText);
self.lifeTime = 120; // 2 seconds at 60fps
self.floatSpeed = -2;
self.update = function () {
self.y += self.floatSpeed;
self.alpha -= 0.02;
self.lifeTime--;
if (self.lifeTime <= 0 || self.alpha <= 0) {
self.destroy();
var index = moneyIcons.indexOf(self);
if (index > -1) {
moneyIcons.splice(index, 1);
}
}
};
return self;
});
var MoneyScreen = Container.expand(function () {
var self = Container.call(this);
var background = LK.getAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 6,
tint: 0x000000,
alpha: 0.8
});
self.addChild(background);
var titleText = new Text2('Money Status', {
size: 80,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -150;
self.addChild(titleText);
var moneyIcon = self.attachAsset('money', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3,
y: -50
});
var currentMoneyText = new Text2('$' + money, {
size: 120,
fill: 0xFFD700
});
currentMoneyText.anchor.set(0.5, 0.5);
currentMoneyText.y = 50;
self.addChild(currentMoneyText);
var closeText = new Text2('Tap to close', {
size: 40,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeText.y = 150;
self.addChild(closeText);
self.visible = false;
self.down = function (x, y, obj) {
self.visible = false;
};
self.update = function () {
if (self.visible) {
currentMoneyText.setText('$' + money);
}
};
return self;
});
var PlayerBase = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('playerBase', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3000;
self.maxHealth = 3000;
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 300);
healthText.setText('Base Health: ' + self.health + '/' + self.maxHealth);
if (self.health <= 0) {
gameOver = true;
// Save high score before showing game over screen
var currentScore = LK.getScore();
var highScores = storage.highScores || [];
highScores.push(currentScore);
highScores.sort(function (a, b) {
return b - a;
});
storage.highScores = highScores.slice(0, 10); // Keep top 10
LK.showGameOver();
}
};
return self;
});
var RapidFireBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
tint: 0x00FF00
});
self.speed = 12;
self.damage = 15;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.explode();
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
var index = rapidFireBullets.indexOf(self);
if (index > -1) {
rapidFireBullets.splice(index, 1);
}
}
};
self.explode = function () {
// Check for zombie hits
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (self.intersects(zombie)) {
zombie.takeDamage(self.damage);
break;
}
}
// Check for enemy bot hits
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
if (self.intersects(bot)) {
bot.takeDamage(self.damage);
break;
}
}
self.destroy();
var index = rapidFireBullets.indexOf(self);
if (index > -1) {
rapidFireBullets.splice(index, 1);
}
};
return self;
});
var RapidFireTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x00FF00
});
self.health = 150;
self.maxHealth = 150;
self.damage = 15;
self.range = 250;
self.shootCooldown = 0;
self.update = function () {
var target = self.findNearestEnemy();
if (target && self.shootCooldown <= 0) {
self.shootAt(target);
self.shootCooldown = 15; // Very fast firing
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.findNearestEnemy = function () {
var nearest = null;
var minDistance = Infinity;
// Check zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = zombie;
}
}
// Check enemy bots
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = bot;
}
}
return nearest;
};
self.shootAt = function (target) {
var bullet = new RapidFireBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
rapidFireBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
self.destroy();
var index = rapidFireTowers.indexOf(self);
if (index > -1) {
rapidFireTowers.splice(index, 1);
}
};
return self;
});
var ReviveButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.0,
tint: 0xFF6666
});
var heroIcon = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: -80,
y: -15,
tint: 0xFFFFFF
});
var buttonText = new Text2('Revive Hero', {
size: 50,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = -10;
self.addChild(buttonText);
var costText = new Text2('Cost: $50', {
size: 35,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 30;
self.addChild(costText);
var moneyIcon = self.attachAsset('money', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: -30,
y: 30
});
self.visible = false;
self.down = function (x, y, obj) {
// Revive hero if dead and have enough money
if (hero.health <= 0 && money >= 50) {
// Revive hero
hero.health = hero.maxHealth;
hero.alpha = 1.0; // Make hero fully visible again
money -= 50;
moneyText.setText('Money: $' + money);
// Flash green to show successful revive
LK.effects.flashObject(self, 0x00FF00, 300);
// Hide revive button after use
self.visible = false;
} else {
// Flash red if can't revive
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.update = function () {
// Show revive button when hero is dead and has enough money
if (hero.health <= 0 && money >= 50) {
self.visible = true;
} else {
self.visible = false;
}
};
return self;
});
var SniperBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8,
tint: 0x0088FF
});
self.speed = 15;
self.damage = 120;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.explode();
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
var index = sniperBullets.indexOf(self);
if (index > -1) {
sniperBullets.splice(index, 1);
}
}
};
self.explode = function () {
// Check for zombie hits
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (self.intersects(zombie)) {
zombie.takeDamage(self.damage);
break;
}
}
// Check for enemy bot hits
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
if (self.intersects(bot)) {
bot.takeDamage(self.damage);
break;
}
}
self.destroy();
var index = sniperBullets.indexOf(self);
if (index > -1) {
sniperBullets.splice(index, 1);
}
};
return self;
});
var SniperTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('defenseTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0x0088FF
});
self.health = 250;
self.maxHealth = 250;
self.damage = 120;
self.range = 600;
self.shootCooldown = 0;
self.update = function () {
var target = self.findNearestEnemy();
if (target && self.shootCooldown <= 0) {
self.shootAt(target);
self.shootCooldown = 80; // Slow but powerful
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.findNearestEnemy = function () {
var nearest = null;
var minDistance = Infinity;
// Check zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = zombie;
}
}
// Check enemy bots
for (var i = 0; i < enemyBots.length; i++) {
var bot = enemyBots[i];
var distance = Math.sqrt(Math.pow(bot.x - self.x, 2) + Math.pow(bot.y - self.y, 2));
if (distance < minDistance && distance < self.range) {
minDistance = distance;
nearest = bot;
}
}
return nearest;
};
self.shootAt = function (target) {
var bullet = new SniperBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = target.x;
bullet.targetY = target.y;
bullet.damage = self.damage;
sniperBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
self.destroy();
var index = sniperTowers.indexOf(self);
if (index > -1) {
sniperTowers.splice(index, 1);
}
};
return self;
});
var StartWaveButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5,
tint: 0x00FF00
});
var buttonText = new Text2('Start Wave ' + (wave + 1), {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.visible = false;
self.down = function (x, y, obj) {
if (self.visible) {
// Start next wave
wave++;
zombiesSpawned = 0;
zombiesPerWave += 3 + Math.floor(wave / 3);
waveText.setText('Wave: ' + wave);
resources += Math.max(15, 35 - wave);
resourceText.setText('Resources: ' + resources);
self.visible = false;
waveInProgress = true;
LK.effects.flashObject(self, 0x00FF00, 300);
}
};
self.update = function () {
if (self.visible) {
buttonText.setText('Start Wave ' + wave);
}
};
return self;
});
var TowerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 30;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.speed) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.explode();
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
var index = towerBullets.indexOf(self);
if (index > -1) {
towerBullets.splice(index, 1);
}
}
};
self.explode = function () {
// Check for zombie hits
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (self.intersects(zombie)) {
zombie.takeDamage(self.damage);
break;
}
}
// Check for boss hits
for (var i = 0; i < bosses.length; i++) {
var boss = bosses[i];
if (self.intersects(boss)) {
boss.takeDamage(self.damage);
break;
}
}
self.destroy();
var index = towerBullets.indexOf(self);
if (index > -1) {
towerBullets.splice(index, 1);
}
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale health and damage based on current wave
var healthMultiplier = 1 + (wave - 1) * 0.3; // 30% more health per wave
var damageMultiplier = 1 + (wave - 1) * 0.2; // 20% more damage per wave
var speedMultiplier = 1 + (wave - 1) * 0.1; // 10% faster per wave
self.health = Math.floor(100 * healthMultiplier);
self.maxHealth = Math.floor(100 * healthMultiplier);
self.speed = Math.min(3, 1 * speedMultiplier); // Cap speed at 3
self.damage = Math.floor(20 * damageMultiplier);
self.target = null;
self.attackCooldown = 0;
self.update = function () {
// Find nearest target (hero, towers, or base)
var target = self.findNearestTarget();
if (target) {
self.target = target;
}
if (!self.target) {
self.target = playerBase;
}
// Move towards target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 50) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Attack target
if (self.attackCooldown <= 0) {
if (self.target === playerBase) {
playerBase.takeDamage(self.damage);
} else if (self.target === hero) {
hero.takeDamage(self.damage);
} else if (self.target.takeDamage) {
// Attack tower
self.target.takeDamage(self.damage);
}
self.attackCooldown = 60; // 1 second cooldown
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
self.findNearestTarget = function () {
var targets = [];
var attackRange = 400; // Range to look for targets
// Add hero as target if in range and alive
if (hero.health > 0) {
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
if (distanceToHero < attackRange) {
targets.push({
target: hero,
distance: distanceToHero
});
}
}
// Add defense towers as targets
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < attackRange) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add big defense towers as targets
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < attackRange) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add rapid fire towers as targets
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < attackRange) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add sniper towers as targets
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance < attackRange) {
targets.push({
target: tower,
distance: distance
});
}
}
// Add player base as target
var distanceToBase = Math.sqrt(Math.pow(playerBase.x - self.x, 2) + Math.pow(playerBase.y - self.y, 2));
if (distanceToBase < attackRange) {
targets.push({
target: playerBase,
distance: distanceToBase
});
}
// Return nearest target
if (targets.length > 0) {
targets.sort(function (a, b) {
return a.distance - b.distance;
});
return targets[0].target;
}
return null;
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('zombieHit').play();
LK.setScore(LK.getScore() + 10);
scoreText.setText('Score: ' + LK.getScore());
// Add money and spawn money icon
var moneyEarned = 5;
money += moneyEarned;
moneyText.setText('Money: $' + money);
var moneyIcon = new MoneyIcon(moneyEarned);
moneyIcon.x = self.x;
moneyIcon.y = self.y;
moneyIcons.push(moneyIcon);
game.addChild(moneyIcon);
self.destroy();
var index = zombies.indexOf(self);
if (index > -1) {
zombies.splice(index, 1);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2a2a2a
});
/****
* Game Code
****/
// Game state variables
var gameOver = false;
var wave = 1;
var zombiesSpawned = 0;
var zombiesPerWave = 5;
var spawnTimer = 0;
var botSpawnTimer = 0;
var resources = 100;
var money = 0;
var placingTower = false;
var placingBigTower = false;
var placingRapidFireTower = false;
var placingSniperTower = false;
var waveInProgress = true;
// Game objects arrays
var zombies = [];
var enemyBots = [];
var bosses = [];
var defenseTowers = [];
var bigDefenseTowers = [];
var rapidFireTowers = [];
var sniperTowers = [];
var towerBullets = [];
var bigTowerBullets = [];
var rapidFireBullets = [];
var sniperBullets = [];
var heroBullets = [];
var enemyBullets = [];
var moneyIcons = [];
// Create player base
var playerBase = new PlayerBase();
playerBase.x = 1024;
playerBase.y = 2400;
game.addChild(playerBase);
// Create hero
var hero = new Hero();
hero.x = 1024;
hero.y = 2200;
game.addChild(hero);
// Create UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreText);
var healthText = new Text2('Base Health: 3000/3000', {
size: 50,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
healthText.x = -400;
LK.gui.topRight.addChild(healthText);
var waveText = new Text2('Wave: 1', {
size: 55,
fill: 0xFFFF00
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var resourceText = new Text2('Resources: 100', {
size: 45,
fill: 0x00FF00
});
resourceText.anchor.set(0, 0);
LK.gui.bottomLeft.addChild(resourceText);
var moneyText = new Text2('Money: $0', {
size: 45,
fill: 0xFFD700
});
moneyText.anchor.set(0, 0);
moneyText.y = 120;
moneyText.down = function (x, y, obj) {
moneyScreen.visible = true;
};
LK.gui.topLeft.addChild(moneyText);
var heroHealthText = new Text2('Hero Health: 300/300', {
size: 50,
fill: 0xFF6666
});
heroHealthText.anchor.set(0, 0);
heroHealthText.y = 180;
LK.gui.topLeft.addChild(heroHealthText);
// Create buy tower button
var buyTowerButton = new BuyTowerButton();
buyTowerButton.x = 120;
buyTowerButton.y = -120;
LK.gui.bottomLeft.addChild(buyTowerButton);
// Create buy big tower button
var buyBigTowerButton = new BuyBigTowerButton();
buyBigTowerButton.x = 280;
buyBigTowerButton.y = -120;
LK.gui.bottomLeft.addChild(buyBigTowerButton);
// Create buy rapid fire tower button
var buyRapidFireTowerButton = new BuyRapidFireTowerButton();
buyRapidFireTowerButton.x = 440;
buyRapidFireTowerButton.y = -120;
LK.gui.bottomLeft.addChild(buyRapidFireTowerButton);
// Create buy sniper tower button
var buySniperTowerButton = new BuySniperTowerButton();
buySniperTowerButton.x = 600;
buySniperTowerButton.y = -120;
LK.gui.bottomLeft.addChild(buySniperTowerButton);
// Create start wave button
var startWaveButton = new StartWaveButton();
startWaveButton.x = 0;
startWaveButton.y = -200;
LK.gui.center.addChild(startWaveButton);
// Create money screen
var moneyScreen = new MoneyScreen();
moneyScreen.x = 0;
moneyScreen.y = 0;
LK.gui.center.addChild(moneyScreen);
// Create revive button
var reviveButton = new ReviveButton();
reviveButton.x = 0;
reviveButton.y = 100;
LK.gui.center.addChild(reviveButton);
// Create leaderboard screen
var leaderboardScreen = new LeaderboardScreen();
leaderboardScreen.x = 0;
leaderboardScreen.y = 0;
LK.gui.center.addChild(leaderboardScreen);
// Create leaderboard button
var leaderboardButton = new Text2('LEADERBOARD', {
size: 40,
fill: 0xFFD700
});
leaderboardButton.anchor.set(0.5, 0);
leaderboardButton.y = 300;
leaderboardButton.down = function (x, y, obj) {
leaderboardScreen.updateLeaderboard();
leaderboardScreen.visible = true;
};
LK.gui.topLeft.addChild(leaderboardButton);
// Game control functions
function spawnZombie() {
var zombie = new Zombie();
// Spawn from random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// Top
zombie.x = Math.random() * 2048;
zombie.y = 0;
} else if (edge === 1) {
// Right
zombie.x = 2048;
zombie.y = Math.random() * 2732;
} else if (edge === 2) {
// Bottom
zombie.x = Math.random() * 2048;
zombie.y = 2732;
} else {
// Left
zombie.x = 0;
zombie.y = Math.random() * 2732;
}
zombies.push(zombie);
game.addChild(zombie);
zombiesSpawned++;
}
function spawnEnemyBot() {
var botTypes = ['artilleryBot', 'assaultBot', 'disruptionBot', 'repairBot'];
var randomType = botTypes[Math.floor(Math.random() * botTypes.length)];
var bot = new EnemyBot(randomType);
bot.x = Math.random() * 1800 + 124;
bot.y = Math.random() * 1000 + 200;
enemyBots.push(bot);
game.addChild(bot);
}
function buildDefenseTower(x, y) {
var towerCost = 25 + Math.floor(wave / 2) * 5; // Increase cost every 2 waves
var resourceCost = 50 + Math.floor(wave / 3) * 10; // Increase resource cost every 3 waves
if (resources >= resourceCost && money >= towerCost) {
var tower = new DefenseTower();
tower.x = x;
tower.y = y;
defenseTowers.push(tower);
game.addChild(tower);
resources -= resourceCost;
money -= towerCost;
resourceText.setText('Resources: ' + resources);
moneyText.setText('Money: $' + money);
}
}
function buildBigDefenseTower(x, y) {
var towerCost = 100 + Math.floor(wave / 2) * 15; // Increase cost every 2 waves
var resourceCost = 100 + Math.floor(wave / 3) * 20; // Increase resource cost every 3 waves
if (resources >= resourceCost && money >= towerCost) {
var tower = new BigDefenseTower();
tower.x = x;
tower.y = y;
bigDefenseTowers.push(tower);
game.addChild(tower);
resources -= resourceCost;
money -= towerCost;
resourceText.setText('Resources: ' + resources);
moneyText.setText('Money: $' + money);
}
}
function buildRapidFireTower(x, y) {
var towerCost = 40; // Money cost for rapid fire tower
if (resources >= 75 && money >= towerCost) {
var tower = new RapidFireTower();
tower.x = x;
tower.y = y;
rapidFireTowers.push(tower);
game.addChild(tower);
resources -= 75;
money -= towerCost;
resourceText.setText('Resources: ' + resources);
moneyText.setText('Money: $' + money);
}
}
function buildSniperTower(x, y) {
var towerCost = 75; // Money cost for sniper tower
if (resources >= 125 && money >= towerCost) {
var tower = new SniperTower();
tower.x = x;
tower.y = y;
sniperTowers.push(tower);
game.addChild(tower);
resources -= 125;
money -= towerCost;
resourceText.setText('Resources: ' + resources);
moneyText.setText('Money: $' + money);
}
}
function spawnBoss() {
var boss = new Boss();
// Spawn boss from top center
boss.x = 1024;
boss.y = 0;
bosses.push(boss);
game.addChild(boss);
}
// Event handlers
game.down = function (x, y, obj) {
if (placingTower) {
// Tower placement mode
var canBuild = true;
var minDistance = 120;
// Check distance from other towers
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
// Check distance from big towers
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
// Check distance from base
var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2));
if (distanceToBase < 150) {
canBuild = false;
}
// Check distance from hero
var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2));
if (distanceToHero < 100) {
canBuild = false;
}
if (canBuild && y < 2300) {
// Don't build too close to base area
buildDefenseTower(x, y);
placingTower = false; // Exit placement mode after building
}
} else if (placingBigTower) {
// Big tower placement mode
var canBuild = true;
var minDistance = 150;
// Check distance from regular towers
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
// Check distance from other big towers
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
// Check distance from base
var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2));
if (distanceToBase < 200) {
canBuild = false;
}
// Check distance from hero
var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2));
if (distanceToHero < 120) {
canBuild = false;
}
if (canBuild && y < 2300) {
// Don't build too close to base area
buildBigDefenseTower(x, y);
placingBigTower = false; // Exit placement mode after building
}
} else if (placingRapidFireTower) {
// Rapid fire tower placement mode
var canBuild = true;
var minDistance = 100;
// Check distance from all towers
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2));
if (distanceToBase < 120) {
canBuild = false;
}
var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2));
if (distanceToHero < 80) {
canBuild = false;
}
if (canBuild && y < 2300) {
buildRapidFireTower(x, y);
placingRapidFireTower = false;
}
} else if (placingSniperTower) {
// Sniper tower placement mode
var canBuild = true;
var minDistance = 140;
// Check distance from all towers
for (var i = 0; i < defenseTowers.length; i++) {
var tower = defenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
for (var i = 0; i < bigDefenseTowers.length; i++) {
var tower = bigDefenseTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
for (var i = 0; i < rapidFireTowers.length; i++) {
var tower = rapidFireTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
for (var i = 0; i < sniperTowers.length; i++) {
var tower = sniperTowers[i];
var distance = Math.sqrt(Math.pow(tower.x - x, 2) + Math.pow(tower.y - y, 2));
if (distance < minDistance) {
canBuild = false;
break;
}
}
var distanceToBase = Math.sqrt(Math.pow(playerBase.x - x, 2) + Math.pow(playerBase.y - y, 2));
if (distanceToBase < 180) {
canBuild = false;
}
var distanceToHero = Math.sqrt(Math.pow(hero.x - x, 2) + Math.pow(hero.y - y, 2));
if (distanceToHero < 100) {
canBuild = false;
}
if (canBuild && y < 2300) {
buildSniperTower(x, y);
placingSniperTower = false;
}
} else {
// Normal mode - move hero (only if alive)
if (hero.health > 0) {
hero.moveTo(x, y);
}
}
};
// Start background music
LK.playMusic('Zombiewarmuic');
// Main game loop
game.update = function () {
if (gameOver) return;
// Resource generation
if (LK.ticks % 180 === 0) {
// Every 3 seconds
resources += 10;
resourceText.setText('Resources: ' + resources);
}
// Zombie spawning - faster spawn rate at higher waves (only if wave is in progress)
if (waveInProgress && zombiesSpawned < zombiesPerWave) {
spawnTimer++;
var zombieSpawnInterval = Math.max(60, 120 - (wave - 1) * 8); // Faster spawning each wave, minimum 1 second
if (spawnTimer >= zombieSpawnInterval) {
spawnZombie();
spawnTimer = 0;
}
}
// Enemy bot spawning - faster spawn rate at higher waves (only if wave is in progress)
if (waveInProgress) {
botSpawnTimer++;
var botSpawnInterval = Math.max(300, 600 - (wave - 1) * 30); // Faster spawning each wave, minimum 5 seconds
if (botSpawnTimer >= botSpawnInterval) {
spawnEnemyBot();
// Spawn additional bots at higher waves
if (wave >= 5 && Math.random() < 0.3) {
spawnEnemyBot(); // 30% chance for second bot
}
if (wave >= 8 && Math.random() < 0.2) {
spawnEnemyBot(); // 20% chance for third bot
}
botSpawnTimer = 0;
}
}
// Check for wave completion
if (waveInProgress && zombiesSpawned >= zombiesPerWave && zombies.length === 0) {
// Wave completed - check if it's time for boss
if (wave === 9) {
// After wave 9, spawn boss
spawnBoss();
waveText.setText('BOSS WAVE!');
} else {
// Regular wave completed - show start button for next wave
waveInProgress = false;
startWaveButton.visible = true;
}
}
// Win condition - boss must be defeated
if (wave >= 9 && zombies.length === 0 && enemyBots.length === 0 && bosses.length === 0) {
// Save high score before showing win screen
var currentScore = LK.getScore();
var highScores = storage.highScores || [];
highScores.push(currentScore);
highScores.sort(function (a, b) {
return b - a;
});
storage.highScores = highScores.slice(0, 10); // Keep top 10
LK.showYouWin();
}
// Update all bullets
for (var i = towerBullets.length - 1; i >= 0; i--) {
var bullet = towerBullets[i];
if (bullet.destroyed) {
towerBullets.splice(i, 1);
}
}
for (var i = bigTowerBullets.length - 1; i >= 0; i--) {
var bullet = bigTowerBullets[i];
if (bullet.destroyed) {
bigTowerBullets.splice(i, 1);
}
}
for (var i = rapidFireBullets.length - 1; i >= 0; i--) {
var bullet = rapidFireBullets[i];
if (bullet.destroyed) {
rapidFireBullets.splice(i, 1);
}
}
for (var i = sniperBullets.length - 1; i >= 0; i--) {
var bullet = sniperBullets[i];
if (bullet.destroyed) {
sniperBullets.splice(i, 1);
}
}
for (var i = heroBullets.length - 1; i >= 0; i--) {
var bullet = heroBullets[i];
if (bullet.destroyed) {
heroBullets.splice(i, 1);
}
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.destroyed) {
enemyBullets.splice(i, 1);
}
}
// Update money icons
for (var i = moneyIcons.length - 1; i >= 0; i--) {
var icon = moneyIcons[i];
if (icon.destroyed) {
moneyIcons.splice(i, 1);
}
}
};
bullet. 2d. High contrast. No shadows
zombie. 2d. High contrast. No shadows
playerBase. In-Game asset. 2d. High contrast. No shadows
hero. In-Game asset. 2d. High contrast. No shadows
artilleryBot. In-Game asset. 2d. High contrast. No shadows
defenseTower. In-Game asset. 2d. High contrast. No shadows
enemyBullet. In-Game asset. 2d. High contrast. No shadows
assaultBot. In-Game asset. 2d. High contrast. No shadows
repairBot. In-Game asset. 2d. High contrast. No shadows
explosion. In-Game asset. 2d. High contrast. No shadows
disruptionBot. In-Game asset. 2d. High contrast. No shadows
heroBullet. In-Game asset. 2d. High contrast. No shadows
Coin. In-Game asset. 2d. High contrast. No shadows
buyButton. In-Game asset. 2d. High contrast. No shadows
Zombie boss. In-Game asset. 2d. High contrast. No shadows
Start button. In-Game asset. 2d. High contrast. No shadows