User prompt
Ace que las topas cesiten menos
User prompt
Menos zombies
User prompt
Crea más zombies
User prompt
Pone más zombies
User prompt
Pone los botones más separados
User prompt
Pone los botones mucho más separados
User prompt
Pone los botones más separados
User prompt
Ace que los botones no se toquen
User prompt
Ace que las filas sean más largas
User prompt
Ace que los botones sean más chiquitos
User prompt
Pone todos los botones en filas
User prompt
Pone más tropas ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pone en la pausa todadas las tropas con lo que acen
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Assassin = Container.expand(function () { var self = Container.call(this); var assassinGraphics = self.attachAsset('assassin', { anchorX: 0.5, anchorY: 0.5 }); assassinGraphics.tint = 0x2F4F4F; // Dark slate gray tint for assassins self.range = 80; // Short range self.attackCooldown = 0; self.attackRate = 180; // Slow but deadly attacks self.speed = 1.5; // Fast movement self.patrolTarget = null; self.mode = 'patrol'; self.isStealthed = false; self.stealthTimer = 0; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Stealth mechanics if (self.isStealthed) { self.stealthTimer--; if (self.stealthTimer <= 0) { self.isStealthed = false; assassinGraphics.alpha = 1.0; } } // Decrease attack cooldown if (self.attackCooldown > 0) { self.attackCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.attackCooldown === 0) { self.mode = 'combat'; self.assassinate(nearestZombie); self.attackCooldown = self.attackRate; } else { self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.assassinate = function (target) { // Enter stealth after attack self.isStealthed = true; self.stealthTimer = 120; // 2 seconds of stealth assassinGraphics.alpha = 0.3; // Deal massive damage var damage = 8; if (self.isDamageWeakened) { damage = damage * 0.5; } target.takeDamage(damage); // Visual effect LK.effects.flashObject(self, 0x2F4F4F, 300); LK.effects.flashObject(target, 0xFF0000, 500); LK.getSound('shoot').play(); }; self.setNewPatrolTarget = function () { var angle = Math.random() * Math.PI * 2; var radius = 150 + Math.random() * 250; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Barrier = Container.expand(function () { var self = Container.call(this); var barrierGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); barrierGraphics.tint = 0x8B4513; // Brown tint for barriers self.health = 100; // Very high resistance self.maxHealth = 100; self.lastIntersecting = {}; self.update = function () { // Check collision with zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var zombieId = zombies.indexOf(zombie); // Initialize last intersecting state if not exists if (self.lastIntersecting[zombieId] === undefined) { self.lastIntersecting[zombieId] = false; } var currentIntersecting = self.intersects(zombie); // Check if zombie just started intersecting if (!self.lastIntersecting[zombieId] && currentIntersecting) { // Damage zombie zombie.takeDamage(); // Take damage to barrier self.health -= 5; // Update barrier appearance based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { barrierGraphics.tint = 0x8B4513; // Brown } else if (healthPercent > 0.4) { barrierGraphics.tint = 0xFF8C00; // Orange } else { barrierGraphics.tint = 0xFF0000; // Red } // Destroy barrier if health reaches 0 if (self.health <= 0) { self.destroy(); var index = barriers.indexOf(self); if (index > -1) { barriers.splice(index, 1); } return; } } // Update last intersecting state self.lastIntersecting[zombieId] = currentIntersecting; } }; return self; }); var Bomb = Container.expand(function () { var self = Container.call(this); var bombGraphics = self.attachAsset('bomb', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.target = null; self.exploded = false; self.update = function () { if (self.exploded) return; if (!self.target || zombies.indexOf(self.target) === -1) { self.explode(); return; } // Move toward 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 < 15) { // Hit target area self.explode(); } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; self.explode = function () { if (self.exploded) return; self.exploded = true; // Play explosion sound LK.getSound('bombExplode').play(); // Damage all zombies in explosion radius var explosionRadius = 80; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= explosionRadius) { var damage = 1; // Check if any bomber that could have fired this bomb is weakened for (var j = 0; j < bombers.length; j++) { var bomber = bombers[j]; if (bomber.isDamageWeakened) { damage = 0.5; // Reduced damage break; } } zombie.takeDamage(damage); zombie.takeDamage(damage); // Bombs do double damage } } // Create explosion effect LK.effects.flashObject(self, 0xff4444, 200); // Remove bomb self.destroy(); var index = bombs.indexOf(self); if (index > -1) { bombs.splice(index, 1); } }; return self; }); var Bomber = Container.expand(function () { var self = Container.call(this); var bomberGraphics = self.attachAsset('bomber', { anchorX: 0.5, anchorY: 0.5 }); bomberGraphics.tint = 0xff6600; // Orange tint for bombers self.range = 180; self.shootCooldown = 0; self.shootRate = 90; // slower than soldiers (more frames between shots) self.speed = 0.6; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.shootRate = self.originalShootRate; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Decrease shoot cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.shootCooldown === 0) { // Combat mode - launch bomb at zombie self.mode = 'combat'; self.launchBomb(nearestZombie); self.shootCooldown = self.shootRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.launchBomb = function (target) { var bomb = new Bomb(); bomb.x = self.x; bomb.y = self.y; bomb.target = target; bombs.push(bomb); game.addChild(bomb); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 250 + Math.random() * 350; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var BoosterZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('boosterZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0xFFD700; // Gold tint for booster zombies self.speed = 0.9; self.health = 20; self.maxHealth = 20; self.targetX = cityCenter.x; self.targetY = cityCenter.y; self.boostTimer = 0; self.boostRate = 180; // Boost zombies every 3 seconds (180 frames) self.boostRadius = 120; // Radius to boost other zombies // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0xFFD700 }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0xFFD700 }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0xFFD700; // Gold } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF8C00; // Orange } else { zombieGraphics.tint = 0xFF0000; // Red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Boost nearby zombies periodically self.boostTimer++; if (self.boostTimer >= self.boostRate) { self.boostNearbyZombies(); self.boostTimer = 0; } }; self.boostNearbyZombies = function () { for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (zombie === self) continue; // Don't boost self var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.boostRadius) { // Increase zombie speed by 30% zombie.speed *= 1.3; // Visual effect when boosting LK.effects.flashObject(zombie, 0xFFD700, 300); } } // Visual effect when boosting others LK.effects.flashObject(self, 0xFFD700, 500); }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 12; // Moderate points for killing booster zombies updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.target = null; self.update = function () { if (!self.target || zombies.indexOf(self.target) === -1) { self.destroy(); var index = bullets.indexOf(self); if (index > -1) { bullets.splice(index, 1); } return; } // Move toward 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 < 10) { // Hit target with reduced damage if weakened var damage = 1; // Check if any tower that could have fired this bullet is weakened for (var i = 0; i < towers.length; i++) { var tower = towers[i]; if (tower.isDamageWeakened) { damage = 0.5; // Reduced damage break; } } // Check if any soldier that could have fired this bullet is weakened for (var i = 0; i < soldiers.length; i++) { var soldier = soldiers[i]; if (soldier.isDamageWeakened) { damage = 0.5; // Reduced damage break; } } self.target.takeDamage(damage); self.destroy(); var index = bullets.indexOf(self); if (index > -1) { bullets.splice(index, 1); } } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; return self; }); var Burner = Container.expand(function () { var self = Container.call(this); var burnerGraphics = self.attachAsset('burner', { anchorX: 0.5, anchorY: 0.5 }); burnerGraphics.tint = 0xFF4500; // Orange red tint for burners self.range = 120; self.explodeRange = 999999; // Global burn effect self.speed = 1.0; self.patrolTarget = null; self.mode = 'patrol'; self.hasExploded = false; self.explodeTimer = 0; self.explodeDelay = 60; // 1 second delay before explosion self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && !self.hasExploded) { // Start explosion sequence self.mode = 'exploding'; self.hasExploded = true; self.explodeTimer = self.explodeDelay; // Visual indication of incoming explosion tween(burnerGraphics, { tint: 0xFF0000, scaleX: 1.5, scaleY: 1.5 }, { duration: 1000, easing: tween.easeOut }); LK.effects.flashObject(self, 0xFF4500, 200); } else if (!self.hasExploded) { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } // Handle explosion countdown if (self.hasExploded) { self.explodeTimer--; if (self.explodeTimer <= 0) { self.explode(); } } }; self.explode = function () { // Burn ALL zombies - deal continuous damage over time for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; // Skip immune zombies if (zombie.isImmune) continue; // Mark zombie as burning zombie.isBurning = true; zombie.burnTimer = 300; // Burn for 5 seconds (300 frames at 60fps) zombie.burnDamageTimer = 0; // Initialize burn damage timer // Visual effect when burning tween(zombie, { tint: 0xFF4500 }, { duration: 300, easing: tween.easeOut }); LK.effects.flashObject(zombie, 0xFF4500, 300); } // Global burn visual effect LK.effects.flashScreen(0xFF4500, 500); LK.getSound('bombExplode').play(); // Remove burner self.destroy(); var index = burners.indexOf(self); if (index > -1) { burners.splice(index, 1); } }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 180 + Math.random() * 270; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Catcher = Container.expand(function () { var self = Container.call(this); var catcherGraphics = self.attachAsset('catcher', { anchorX: 0.5, anchorY: 0.5 }); catcherGraphics.tint = 0x00BFFF; // Deep sky blue tint for catchers self.range = 140; self.freezeCooldown = 0; self.freezeRate = 120; // Freeze every 2 seconds (120 frames) self.speed = 0.9; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Decrease freeze cooldown if (self.freezeCooldown > 0) { self.freezeCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance && !zombie.isFrozen) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.freezeCooldown === 0) { // Combat mode - freeze zombie self.mode = 'combat'; self.freezeZombie(nearestZombie); self.freezeCooldown = self.freezeRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.freezeZombie = function (zombie) { if (zombie.isFrozen || zombie.isImmune || zombie.cannotBeFrozen) return; // Mark zombie as frozen zombie.isFrozen = true; zombie.frozenTimer = 180; // Freeze for 3 seconds (180 frames) zombie.originalSpeed = zombie.speed; zombie.speed = 0; // Stop movement // Visual effect when freezing LK.getSound('freeze').play(); tween(zombie, { tint: 0x87CEEB }, { duration: 300, easing: tween.easeOut }); LK.effects.flashObject(zombie, 0x00BFFF, 300); LK.effects.flashObject(self, 0x00BFFF, 200); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var EliteSniper = Container.expand(function () { var self = Container.call(this); var sniperGraphics = self.attachAsset('eliteSniper', { anchorX: 0.5, anchorY: 0.5 }); sniperGraphics.tint = 0x8B0000; // Dark red tint for elite snipers self.range = 500; // Very long range self.shootCooldown = 0; self.shootRate = 120; // Slow but powerful shots self.speed = 0.6; // Slow movement self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.shootRate = self.originalShootRate; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Decrease shoot cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.shootCooldown === 0) { // Combat mode - snipe zombie self.mode = 'combat'; self.snipe(nearestZombie); self.shootCooldown = self.shootRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.snipe = function (target) { // Instant hit with high damage var damage = 5; // Very high damage if (self.isDamageWeakened) { damage = damage * 0.5; // Reduced damage } target.takeDamage(damage); // Visual effect tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeOut }); } }); LK.getSound('shoot').play(); LK.effects.flashObject(self, 0x8B0000, 300); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 250 + Math.random() * 350; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Engineer = Container.expand(function () { var self = Container.call(this); var engineerGraphics = self.attachAsset('engineer', { anchorX: 0.5, anchorY: 0.5 }); engineerGraphics.tint = 0xFFD700; // Gold tint for engineers self.range = 100; self.buildCooldown = 0; self.buildRate = 240; // Build every 4 seconds self.speed = 0.7; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Decrease build cooldown if (self.buildCooldown > 0) { self.buildCooldown--; } // Repair nearby barriers and towers if (self.buildCooldown === 0) { self.repairNearbyStructures(); self.buildCooldown = self.buildRate; } // Patrol behavior self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); }; self.repairNearbyStructures = function () { var repairedAny = false; // Repair barriers for (var i = 0; i < barriers.length; i++) { var barrier = barriers[i]; if (barrier.health >= barrier.maxHealth) continue; var dx = barrier.x - self.x; var dy = barrier.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { barrier.health = Math.min(barrier.maxHealth, barrier.health + 25); LK.effects.flashObject(barrier, 0xFFD700, 300); repairedAny = true; } } // Repair heavy tanks for (var i = 0; i < heavyTanks.length; i++) { var tank = heavyTanks[i]; if (tank.health >= tank.maxHealth) continue; var dx = tank.x - self.x; var dy = tank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { tank.health = Math.min(tank.maxHealth, tank.health + 20); LK.effects.flashObject(tank, 0xFFD700, 300); repairedAny = true; } } if (repairedAny) { LK.effects.flashObject(self, 0xFFD700, 500); } }; self.setNewPatrolTarget = function () { var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Exploder = Container.expand(function () { var self = Container.call(this); var exploderGraphics = self.attachAsset('exploder', { anchorX: 0.5, anchorY: 0.5 }); exploderGraphics.tint = 0xff6600; // Orange-red tint for exploders self.range = 100; self.explodeRange = 120; // Range for explosion damage self.speed = 1.2; self.patrolTarget = null; self.mode = 'patrol'; self.hasExploded = false; self.explodeTimer = 0; self.explodeDelay = 60; // 1 second delay before explosion self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && !self.hasExploded) { // Start explosion sequence self.mode = 'exploding'; self.hasExploded = true; self.explodeTimer = self.explodeDelay; // Visual indication of incoming explosion tween(exploderGraphics, { tint: 0xff0000, scaleX: 1.3, scaleY: 1.3 }, { duration: 1000, easing: tween.easeOut }); LK.effects.flashObject(self, 0xff6600, 200); } else if (!self.hasExploded) { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } // Handle explosion countdown if (self.hasExploded) { self.explodeTimer--; if (self.explodeTimer <= 0) { self.explode(); } } }; self.explode = function () { // Damage all zombies in explosion radius for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.explodeRange) { zombie.takeDamage(3); // High explosion damage } } // Create fire tile at explosion location var fireTile = new FireTile(); fireTile.x = self.x; fireTile.y = self.y; fireTiles.push(fireTile); game.addChild(fireTile); // Explosion visual effect LK.effects.flashScreen(0xff4400, 300); LK.getSound('bombExplode').play(); // Remove exploder self.destroy(); var index = exploders.indexOf(self); if (index > -1) { exploders.splice(index, 1); } }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 150 + Math.random() * 250; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var FastBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); bulletGraphics.tint = 0xff9900; // Orange tint for fast bullets self.speed = 10; self.target = null; self.damage = 0.5; // Low damage self.update = function () { if (!self.target || zombies.indexOf(self.target) === -1) { self.destroy(); var index = fastBullets.indexOf(self); if (index > -1) { fastBullets.splice(index, 1); } return; } // Move toward 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 < 10) { // Hit target with reduced damage var damage = self.damage; // Check if any gunner that could have fired this bullet is weakened for (var i = 0; i < gunners.length; i++) { var gunner = gunners[i]; if (gunner.isDamageWeakened) { damage = damage * 0.5; // Reduced damage break; } } self.target.takeDamage(damage); self.destroy(); var index = fastBullets.indexOf(self); if (index > -1) { fastBullets.splice(index, 1); } } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; return self; }); var FireTile = Container.expand(function () { var self = Container.call(this); var fireGraphics = self.attachAsset('fireTile', { anchorX: 0.5, anchorY: 0.5 }); fireGraphics.alpha = 0.8; self.duration = 600; // Fire lasts for 10 seconds (600 frames) self.damageTimer = 0; self.damageRate = 30; // Deal damage every 0.5 seconds (30 frames) self.lastIntersecting = {}; self.update = function () { // Decrease duration self.duration--; if (self.duration <= 0) { self.destroy(); var index = fireTiles.indexOf(self); if (index > -1) { fireTiles.splice(index, 1); } return; } // Fade out over time var fadePercent = self.duration / 600; fireGraphics.alpha = 0.8 * fadePercent; // Damage timer self.damageTimer++; if (self.damageTimer >= self.damageRate) { self.damageTimer = 0; // Check collision with zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var zombieId = zombies.indexOf(zombie); // Initialize last intersecting state if not exists if (self.lastIntersecting[zombieId] === undefined) { self.lastIntersecting[zombieId] = false; } var currentIntersecting = self.intersects(zombie); // Deal damage if zombie is on fire tile if (currentIntersecting) { zombie.takeDamage(0.5); // Fire deals moderate damage // Visual effect when burning LK.effects.flashObject(zombie, 0xff4400, 200); } // Update last intersecting state self.lastIntersecting[zombieId] = currentIntersecting; } } // Flickering fire effect if (LK.ticks % 10 === 0) { tween(fireGraphics, { scaleX: 0.9 + Math.random() * 0.2, scaleY: 0.9 + Math.random() * 0.2 }, { duration: 200, easing: tween.easeOut }); } }; return self; }); var Flamethrower = Container.expand(function () { var self = Container.call(this); var flamethrowerGraphics = self.attachAsset('flamethrower', { anchorX: 0.5, anchorY: 0.5 }); flamethrowerGraphics.tint = 0xFF6600; // Orange tint for flamethrowers self.range = 140; self.burnCooldown = 0; self.burnRate = 60; // Burn every 1 second (60 frames) self.speed = 0.8; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.burnRate = self.originalBurnRate; } } // Decrease burn cooldown if (self.burnCooldown > 0) { self.burnCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance && !zombie.isBurning) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.burnCooldown === 0) { // Combat mode - burn zombie self.mode = 'combat'; self.burnZombie(nearestZombie); self.burnCooldown = self.burnRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.burnZombie = function (zombie) { if (zombie.isBurning || zombie.isImmune) return; // Mark zombie as burning zombie.isBurning = true; zombie.burnTimer = 300; // Burn for 5 seconds (300 frames) zombie.burnDamageTimer = 0; // Initialize burn damage timer // Visual effect when burning tween(zombie, { tint: 0xFF4500 }, { duration: 300, easing: tween.easeOut }); LK.effects.flashObject(zombie, 0xFF6600, 300); LK.effects.flashObject(self, 0xFF6600, 200); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Freezer = Container.expand(function () { var self = Container.call(this); var freezerGraphics = self.attachAsset('freezer', { anchorX: 0.5, anchorY: 0.5 }); freezerGraphics.tint = 0x00FFFF; // Cyan tint for freezers self.range = 120; self.explodeRange = 999999; // Global freeze effect self.speed = 1.0; self.patrolTarget = null; self.mode = 'patrol'; self.hasExploded = false; self.explodeTimer = 0; self.explodeDelay = 60; // 1 second delay before explosion self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && !self.hasExploded) { // Start explosion sequence self.mode = 'exploding'; self.hasExploded = true; self.explodeTimer = self.explodeDelay; // Visual indication of incoming explosion tween(freezerGraphics, { tint: 0x00FFFF, scaleX: 1.5, scaleY: 1.5 }, { duration: 1000, easing: tween.easeOut }); LK.effects.flashObject(self, 0x00FFFF, 200); } else if (!self.hasExploded) { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } // Handle explosion countdown if (self.hasExploded) { self.explodeTimer--; if (self.explodeTimer <= 0) { self.explode(); } } }; self.explode = function () { // Freeze ALL zombies for 6.8 seconds (408 frames at 60fps) for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; // Skip immune zombies and speedy zombies if (zombie.isImmune || zombie.cannotBeFrozen) continue; // Mark zombie as frozen zombie.isFrozen = true; zombie.frozenTimer = 408; // 6.8 seconds at 60fps if (!zombie.originalSpeed) { zombie.originalSpeed = zombie.speed; } zombie.speed = 0; // Stop movement // Visual effect when freezing tween(zombie, { tint: 0x87CEEB }, { duration: 300, easing: tween.easeOut }); LK.effects.flashObject(zombie, 0x00FFFF, 300); } // Global freeze visual effect LK.effects.flashScreen(0x00FFFF, 500); LK.getSound('freeze').play(); // Remove freezer self.destroy(); var index = freezers.indexOf(self); if (index > -1) { freezers.splice(index, 1); } }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 180 + Math.random() * 270; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var FreezerTroop = Container.expand(function () { var self = Container.call(this); var freezerTroopGraphics = self.attachAsset('freezerTroop', { anchorX: 0.5, anchorY: 0.5 }); freezerTroopGraphics.tint = 0x87CEEB; // Sky blue tint for freezer troops self.range = 160; // Breathing range self.freezeCooldown = 0; self.freezeRate = 30; // Continuous freezing every 0.5 seconds self.speed = 1.0; self.patrolTarget = null; self.mode = 'patrol'; self.breathingScale = 1.0; self.breathingDirection = 1; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Breathing animation self.breathingScale += self.breathingDirection * 0.01; if (self.breathingScale >= 1.1) { self.breathingDirection = -1; } else if (self.breathingScale <= 0.9) { self.breathingDirection = 1; } freezerTroopGraphics.scaleX = self.breathingScale; freezerTroopGraphics.scaleY = self.breathingScale; // Decrease freeze cooldown if (self.freezeCooldown > 0) { self.freezeCooldown--; } // Continuous freezing with breathing if (self.freezeCooldown === 0) { self.freezeZombiesWithBreathing(); self.freezeCooldown = self.freezeRate; } // Patrol behavior self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); }; self.freezeZombiesWithBreathing = function () { var frozenAny = false; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && !zombie.isFrozen && !zombie.isImmune && !zombie.cannotBeFrozen) { // Freeze zombie with breathing zombie.isFrozen = true; zombie.frozenTimer = 120; // Freeze for 2 seconds zombie.originalSpeed = zombie.speed; zombie.speed = 0; // Stop movement // Visual effect when freezing tween(zombie, { tint: 0x87CEEB }, { duration: 300, easing: tween.easeOut }); LK.effects.flashObject(zombie, 0x87CEEB, 300); frozenAny = true; } } // Visual breathing effect when freezing if (frozenAny) { LK.getSound('freeze').play(); tween(freezerTroopGraphics, { tint: 0x00FFFF }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(freezerTroopGraphics, { tint: 0x87CEEB }, { duration: 200, easing: tween.easeOut }); } }); } }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Gunner = Container.expand(function () { var self = Container.call(this); var gunnerGraphics = self.attachAsset('gunner', { anchorX: 0.5, anchorY: 0.5 }); gunnerGraphics.tint = 0xffa500; // Orange tint for gunners self.range = 100; self.shootCooldown = 0; self.shootRate = 8; // Very fast shooting (much faster than soldiers) self.speed = 1.0; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.shootRate = self.originalShootRate; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Decrease shoot cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.shootCooldown === 0) { // Combat mode - shoot at zombie self.mode = 'combat'; self.shoot(nearestZombie); self.shootCooldown = self.shootRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.shoot = function (target) { var bullet = new FastBullet(); bullet.x = self.x; bullet.y = self.y; bullet.target = target; fastBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 180 + Math.random() * 280; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var HeavyTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('heavyTank', { anchorX: 0.5, anchorY: 0.5 }); tankGraphics.tint = 0x556B2F; // Dark olive green tint for heavy tanks self.range = 200; self.shootCooldown = 0; self.shootRate = 90; // Moderate shooting rate self.speed = 0.4; // Very slow movement self.patrolTarget = null; self.mode = 'patrol'; self.health = 150; // Very high health self.maxHealth = 150; self.armor = 0.5; // 50% damage reduction // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.shootRate = self.originalShootRate; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Decrease shoot cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.shootCooldown === 0) { // Combat mode - shoot at zombie self.mode = 'combat'; self.shoot(nearestZombie); self.shootCooldown = self.shootRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } // Update health bar var healthPercent = self.health / self.maxHealth; healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.shoot = function (target) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.target = target; bullet.damage = 2; // Higher damage bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; // Apply armor reduction damage = damage * self.armor; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { // Remove from array var index = heavyTanks.indexOf(self); if (index > -1) { heavyTanks.splice(index, 1); } self.destroy(); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var ImmunityZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('immunityZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0x9932CC; // Dark orchid tint for immunity zombies self.speed = 0.7; self.health = 28; self.maxHealth = 28; self.targetX = cityCenter.x; self.targetY = cityCenter.y; self.immunityTimer = 0; self.immunityRate = 60; // Provide immunity every 1 second (60 frames) self.immunityRadius = 200; // Radius to provide immunity to other zombies // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0x9932CC }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0x9932CC }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0x9932CC; // Dark orchid } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF8C00; // Orange } else { zombieGraphics.tint = 0xFF0000; // Red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Provide immunity to nearby zombies periodically self.immunityTimer++; if (self.immunityTimer >= self.immunityRate) { self.grantImmunityToNearbyZombies(); self.immunityTimer = 0; } }; self.grantImmunityToNearbyZombies = function () { for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (zombie === self) continue; // Don't grant immunity to self var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.immunityRadius) { // Grant immunity - clear any freeze or burn effects if (zombie.isFrozen) { zombie.isFrozen = false; zombie.frozenTimer = 0; if (zombie.originalSpeed) { zombie.speed = zombie.originalSpeed; } } if (zombie.isBurning) { zombie.isBurning = false; zombie.burnTimer = 0; zombie.burnDamageTimer = 0; } // Mark zombie as immune for a period zombie.isImmune = true; zombie.immunityTimer = 300; // Immune for 5 seconds (300 frames) // Visual effect when granting immunity LK.effects.flashObject(zombie, 0x9932CC, 300); } } // Visual effect when granting immunity to others LK.effects.flashObject(self, 0x9932CC, 500); }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 15; // Moderate points for killing immunity zombies updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var LaserTurret = Container.expand(function () { var self = Container.call(this); var turretGraphics = self.attachAsset('laserTurret', { anchorX: 0.5, anchorY: 0.5 }); turretGraphics.tint = 0x00FF00; // Green tint for laser turrets self.range = 250; self.currentTarget = null; self.laserBeam = null; self.damageTimer = 0; self.damageRate = 30; // Deal damage every 0.5 seconds self.update = function () { // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && nearestZombie !== self.currentTarget) { // Switch target self.currentTarget = nearestZombie; self.createLaserBeam(); } else if (!nearestZombie && self.currentTarget) { // No target, stop laser self.currentTarget = null; self.removeLaserBeam(); } // Update laser beam and deal damage if (self.currentTarget && self.laserBeam) { self.updateLaserBeam(); self.damageTimer++; if (self.damageTimer >= self.damageRate) { var damage = 2; // Continuous damage if (self.isDamageWeakened) { damage = damage * 0.5; // Reduced damage } self.currentTarget.takeDamage(damage); self.damageTimer = 0; } } }; self.createLaserBeam = function () { if (self.laserBeam) { self.laserBeam.destroy(); } self.laserBeam = self.attachAsset('laserBeam', { anchorX: 0, anchorY: 0.5 }); self.laserBeam.alpha = 0.8; }; self.updateLaserBeam = function () { if (!self.laserBeam || !self.currentTarget) return; var dx = self.currentTarget.x - self.x; var dy = self.currentTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); self.laserBeam.width = distance; self.laserBeam.rotation = Math.atan2(dy, dx); // Flickering effect self.laserBeam.alpha = 0.6 + Math.random() * 0.4; }; self.removeLaserBeam = function () { if (self.laserBeam) { self.laserBeam.destroy(); self.laserBeam = null; } }; return self; }); var Miner = Container.expand(function () { var self = Container.call(this); var minerGraphics = self.attachAsset('miner', { anchorX: 0.5, anchorY: 0.5 }); minerGraphics.tint = 0xffd700; // Gold tint for miners self.moneyTimer = 0; self.moneyRate = 180; // Generate money every 3 seconds (180 frames) self.lastIntersecting = {}; self.update = function () { // Check collision with zombies first for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var zombieId = zombies.indexOf(zombie); // Initialize last intersecting state if not exists if (self.lastIntersecting[zombieId] === undefined) { self.lastIntersecting[zombieId] = false; } var currentIntersecting = self.intersects(zombie); // Check if zombie just started intersecting if (!self.lastIntersecting[zombieId] && currentIntersecting) { // Transform miner into zombie var newZombie = new Zombie(); newZombie.x = self.x; newZombie.y = self.y; zombies.push(newZombie); game.addChild(newZombie); // Remove miner self.destroy(); var minerIndex = miners.indexOf(self); if (minerIndex > -1) { miners.splice(minerIndex, 1); } return; } // Update last intersecting state self.lastIntersecting[zombieId] = currentIntersecting; } self.moneyTimer++; if (self.moneyTimer >= self.moneyRate) { // Generate money gamePoints += 25; updateUI(); // Visual effect when generating money LK.effects.flashObject(self, 0xffd700, 500); self.moneyTimer = 0; } }; return self; }); var Mortar = Container.expand(function () { var self = Container.call(this); var mortarGraphics = self.attachAsset('mortar', { anchorX: 0.5, anchorY: 0.5 }); mortarGraphics.tint = 0x696969; // Dim gray tint for mortars self.range = 400; // Very long range self.shootCooldown = 0; self.shootRate = 180; // Slow but powerful self.update = function () { // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } if (self.shootCooldown > 0) { self.shootCooldown--; return; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie) { self.fireMortar(nearestZombie); self.shootCooldown = self.shootRate; } }; self.fireMortar = function (target) { // Create delayed explosion at target location var explosionX = target.x; var explosionY = target.y; // Visual warning LK.effects.flashObject(target, 0xFF0000, 1000); // Delayed explosion LK.setTimeout(function () { var explosionRadius = 120; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - explosionX; var dy = zombie.y - explosionY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= explosionRadius) { var damage = 4; if (self.isDamageWeakened) { damage = damage * 0.5; } zombie.takeDamage(damage); } } // Explosion effect LK.effects.flashScreen(0xFF4400, 300); LK.getSound('bombExplode').play(); }, 1000); // Recoil effect tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeOut }); } }); }; return self; }); var Rocket = Container.expand(function () { var self = Container.call(this); var rocketGraphics = self.attachAsset('rocket', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.target = null; self.launcher = null; self.exploded = false; self.update = function () { if (self.exploded) return; if (!self.target || zombies.indexOf(self.target) === -1) { self.explode(); return; } // Move toward 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 < 20) { // Hit target area self.explode(); } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; self.explode = function () { if (self.exploded) return; self.exploded = true; // Play explosion sound LK.getSound('bombExplode').play(); // Damage all zombies in explosion radius var explosionRadius = 100; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= explosionRadius) { var damage = 3; // High damage if (self.launcher && self.launcher.isDamageWeakened) { damage = damage * 0.5; // Reduced damage } zombie.takeDamage(damage); } } // Create explosion effect LK.effects.flashObject(self, 0xff4444, 300); // Remove rocket self.destroy(); var index = rockets.indexOf(self); if (index > -1) { rockets.splice(index, 1); } }; return self; }); var RocketLauncher = Container.expand(function () { var self = Container.call(this); var launcherGraphics = self.attachAsset('rocketLauncher', { anchorX: 0.5, anchorY: 0.5 }); launcherGraphics.tint = 0x8B4513; // Brown tint for rocket launchers self.range = 280; self.shootCooldown = 0; self.shootRate = 150; // Slow but powerful self.update = function () { // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } if (self.shootCooldown > 0) { self.shootCooldown--; return; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie) { self.launchRocket(nearestZombie); self.shootCooldown = self.shootRate; } }; self.launchRocket = function (target) { var rocket = new Rocket(); rocket.x = self.x; rocket.y = self.y; rocket.target = target; rocket.launcher = self; rockets.push(rocket); game.addChild(rocket); LK.getSound('shoot').play(); }; return self; }); var ShieldGenerator = Container.expand(function () { var self = Container.call(this); var generatorGraphics = self.attachAsset('shieldGenerator', { anchorX: 0.5, anchorY: 0.5 }); generatorGraphics.tint = 0x00AAFF; // Blue tint for shield generators self.range = 150; self.shieldTimer = 0; self.shieldRate = 120; // Generate shields every 2 seconds self.shields = []; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; } } self.shieldTimer++; if (self.shieldTimer >= self.shieldRate) { self.generateShields(); self.shieldTimer = 0; } // Update existing shields for (var i = self.shields.length - 1; i >= 0; i--) { var shield = self.shields[i]; shield.duration--; if (shield.duration <= 0) { shield.destroy(); self.shields.splice(i, 1); } } }; self.generateShields = function () { // Find nearby friendly units var nearbyUnits = []; // Check soldiers for (var i = 0; i < soldiers.length; i++) { var soldier = soldiers[i]; var dx = soldier.x - self.x; var dy = soldier.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { nearbyUnits.push(soldier); } } // Check gunners for (var i = 0; i < gunners.length; i++) { var gunner = gunners[i]; var dx = gunner.x - self.x; var dy = gunner.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { nearbyUnits.push(gunner); } } // Check heavy tanks for (var i = 0; i < heavyTanks.length; i++) { var tank = heavyTanks[i]; var dx = tank.x - self.x; var dy = tank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { nearbyUnits.push(tank); } } // Generate shields for nearby units for (var i = 0; i < nearbyUnits.length; i++) { var unit = nearbyUnits[i]; if (!unit.hasShield) { var shield = unit.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5 }); shield.alpha = 0.3; shield.duration = 300; // 5 seconds unit.hasShield = true; unit.shieldHealth = 50; self.shields.push(shield); // Visual effect LK.effects.flashObject(unit, 0x00AAFF, 300); } } // Visual effect for generator LK.effects.flashObject(self, 0x00AAFF, 500); }; return self; }); var ShockTrooper = Container.expand(function () { var self = Container.call(this); var shockGraphics = self.attachAsset('shockTrooper', { anchorX: 0.5, anchorY: 0.5 }); shockGraphics.tint = 0x00CED1; // Dark turquoise tint for shock troopers self.range = 160; self.shockCooldown = 0; self.shockRate = 120; // Shock every 2 seconds self.speed = 1.0; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Decrease shock cooldown if (self.shockCooldown > 0) { self.shockCooldown--; } // Find zombies in range for shock attack var zombiesInRange = []; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { zombiesInRange.push(zombie); } } if (zombiesInRange.length > 0 && self.shockCooldown === 0) { self.mode = 'combat'; self.electricShock(zombiesInRange); self.shockCooldown = self.shockRate; } else { self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.electricShock = function (zombiesInRange) { var damage = 2; if (self.isDamageWeakened) { damage = damage * 0.5; } for (var i = 0; i < zombiesInRange.length; i++) { var zombie = zombiesInRange[i]; zombie.takeDamage(damage); // Stun effect - slow zombie temporarily zombie.isStunned = true; zombie.stunnedTimer = 60; // 1 second stun if (!zombie.originalSpeed) { zombie.originalSpeed = zombie.speed; } zombie.speed = zombie.speed * 0.3; // 70% speed reduction // Visual effect tween(zombie, { tint: 0x00CED1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(zombie, { tint: zombie.originalTint || 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); } }); } // Shock visual effect LK.effects.flashObject(self, 0x00CED1, 500); LK.getSound('shoot').play(); }; self.setNewPatrolTarget = function () { var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var Soldier = Container.expand(function () { var self = Container.call(this); var soldierGraphics = self.attachAsset('soldier', { anchorX: 0.5, anchorY: 0.5 }); soldierGraphics.tint = 0x4CAF50; // Green tint for soldiers self.range = 120; self.shootCooldown = 0; self.shootRate = 45; // frames between shots self.speed = 0.8; self.patrolTarget = null; self.mode = 'patrol'; // 'patrol' or 'combat' self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.shootRate = self.originalShootRate; } } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } // Decrease shoot cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie && self.shootCooldown === 0) { // Combat mode - shoot at zombie self.mode = 'combat'; self.shoot(nearestZombie); self.shootCooldown = self.shootRate; } else { // Patrol mode - move around self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); } }; self.shoot = function (target) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.target = target; bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.setNewPatrolTarget = function () { // Set random patrol target around city center var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; // Keep patrol target within bounds self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var SpawnerZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('spawnerZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0x800080; // Purple tint for spawner zombies self.speed = 0.8; self.health = 25; self.maxHealth = 25; self.targetX = cityCenter.x; self.targetY = cityCenter.y; self.spawnTimer = 0; self.spawnRate = 300; // Spawn tank zombie every 5 seconds (300 frames) // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0x800080 }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0x800080 }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0x800080; // Purple } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF4500; // Orange } else { zombieGraphics.tint = 0xFF0000; // Red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Spawn tank zombies periodically self.spawnTimer++; if (self.spawnTimer >= self.spawnRate) { self.spawnTankZombie(); self.spawnTimer = 0; } }; self.spawnTankZombie = function () { var tankZombie = new TankZombie(); // Spawn near the spawner zombie var angle = Math.random() * Math.PI * 2; var radius = 50; tankZombie.x = self.x + Math.cos(angle) * radius; tankZombie.y = self.y + Math.sin(angle) * radius; // Keep within bounds tankZombie.x = Math.max(50, Math.min(1998, tankZombie.x)); tankZombie.y = Math.max(50, Math.min(2682, tankZombie.y)); zombies.push(tankZombie); game.addChild(tankZombie); // Visual effect when spawning LK.effects.flashObject(self, 0x800080, 500); }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 15; // More points than regular zombie, less than tank updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var SpeedyZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('speedyZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0xFF6B35; // Orange tint for speedy zombies self.speed = 2.5; // Very fast self.health = 15; self.maxHealth = 15; self.targetX = cityCenter.x; self.targetY = cityCenter.y; self.cannotBeFrozen = true; // Cannot be frozen // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -40 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -40 }); self.update = function () { // Handle immunity timer if (self.isImmune) { self.immunityTimer--; if (self.immunityTimer <= 0) { self.isImmune = false; } } // Speedy zombies CANNOT be frozen - ignore freeze effects if (self.isFrozen) { self.isFrozen = false; // Immediately clear frozen state self.frozenTimer = 0; self.speed = 2.5; // Maintain high speed } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0xFF6B35 }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center - always fast 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; } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0xFF6B35; // Orange } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF8C00; // Dark orange } else { zombieGraphics.tint = 0xFF0000; // Red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 8; // Moderate points for killing speedy zombies updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var SupportMedic = Container.expand(function () { var self = Container.call(this); var medicGraphics = self.attachAsset('supportMedic', { anchorX: 0.5, anchorY: 0.5 }); medicGraphics.tint = 0x00FF7F; // Spring green tint for support medics self.range = 140; self.healCooldown = 0; self.healRate = 90; // Heal every 1.5 seconds self.speed = 0.9; self.patrolTarget = null; self.mode = 'patrol'; self.update = function () { // Handle weakening effect if (self.isWeakened) { self.weakenTimer--; if (self.weakenTimer <= 0) { self.isWeakened = false; self.speed = self.originalSpeed; } } // Decrease heal cooldown if (self.healCooldown > 0) { self.healCooldown--; } // Heal nearby troops if (self.healCooldown === 0) { self.healNearbyTroops(); self.healCooldown = self.healRate; } // Patrol behavior self.mode = 'patrol'; if (!self.patrolTarget || self.reachedTarget()) { self.setNewPatrolTarget(); } self.moveTowardTarget(); }; self.healNearbyTroops = function () { var healedAny = false; var allTroops = [].concat(soldiers, gunners, bombers, heavyTanks, eliteSnipers); for (var i = 0; i < allTroops.length; i++) { var troop = allTroops[i]; if (!troop.health || troop.health >= troop.maxHealth) continue; var dx = troop.x - self.x; var dy = troop.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { troop.health = Math.min(troop.maxHealth, troop.health + 15); LK.effects.flashObject(troop, 0x00FF7F, 300); healedAny = true; } } if (healedAny) { LK.effects.flashObject(self, 0x00FF7F, 500); } }; self.setNewPatrolTarget = function () { var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 300; self.patrolTarget = { x: cityCenter.x + Math.cos(angle) * radius, y: cityCenter.y + Math.sin(angle) * radius }; self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x)); self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y)); }; self.moveTowardTarget = function () { if (!self.patrolTarget) return; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - 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; } }; self.reachedTarget = function () { if (!self.patrolTarget) return true; var dx = self.patrolTarget.x - self.x; var dy = self.patrolTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 20; }; return self; }); var TankZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('tankZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0x8B0000; // Dark red tint for tank zombies self.speed = 0.6; // Slower than regular zombies self.health = 35; // Much higher health self.maxHealth = 35; self.targetX = cityCenter.x; self.targetY = cityCenter.y; // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0x8B0000 }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0x8B0000 }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0x8B0000; // Dark red } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF4500; // Orange red } else { zombieGraphics.tint = 0xFF0000; // Bright red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; // Default damage is 1 self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 20; // More points for killing tank zombies updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var Tower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); self.range = 150; self.shootCooldown = 0; self.shootRate = 30; // frames between shots self.level = 1; self.update = function () { // Check collision with zombies first for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var zombieId = zombies.indexOf(zombie); // Initialize last intersecting state if not exists if (self.lastIntersecting === undefined) { self.lastIntersecting = {}; } if (self.lastIntersecting[zombieId] === undefined) { self.lastIntersecting[zombieId] = false; } var currentIntersecting = self.intersects(zombie); // Check if zombie just started intersecting if (!self.lastIntersecting[zombieId] && currentIntersecting) { // Zombie breaks tower self.destroy(); var index = towers.indexOf(self); if (index > -1) { towers.splice(index, 1); } return; } // Update last intersecting state self.lastIntersecting[zombieId] = currentIntersecting; } // Handle damage weakening effect if (self.isDamageWeakened) { self.damageWeakenTimer--; if (self.damageWeakenTimer <= 0) { self.isDamageWeakened = false; } } if (self.shootCooldown > 0) { self.shootCooldown--; return; } // Find nearest zombie in range var nearestZombie = null; var nearestDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var dx = zombie.x - self.x; var dy = zombie.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range && distance < nearestDistance) { nearestDistance = distance; nearestZombie = zombie; } } if (nearestZombie) { self.shoot(nearestZombie); self.shootCooldown = self.shootRate; } }; self.shoot = function (target) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; bullet.target = target; bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); }; self.upgrade = function () { if (gamePoints >= self.getUpgradeCost()) { gamePoints -= self.getUpgradeCost(); self.level++; self.range += 20; self.shootRate = Math.max(10, self.shootRate - 5); towerGraphics.tint = 0x2e7d32; // Green tint for upgraded towers updateUI(); } }; self.getUpgradeCost = function () { return self.level * 15; }; return self; }); var Trap = Container.expand(function () { var self = Container.call(this); var trapGraphics = self.attachAsset('trap', { anchorX: 0.5, anchorY: 0.5 }); trapGraphics.tint = 0x8B4513; // Saddle brown tint for traps self.isArmed = true; self.lastIntersecting = {}; trapGraphics.alpha = 0.7; // Slightly transparent self.update = function () { if (!self.isArmed) return; // Check collision with zombies for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var zombieId = zombies.indexOf(zombie); // Initialize last intersecting state if not exists if (self.lastIntersecting[zombieId] === undefined) { self.lastIntersecting[zombieId] = false; } var currentIntersecting = self.intersects(zombie); // Check if zombie just stepped on trap if (!self.lastIntersecting[zombieId] && currentIntersecting) { self.triggerTrap(zombie); return; } // Update last intersecting state self.lastIntersecting[zombieId] = currentIntersecting; } }; self.triggerTrap = function (zombie) { // Trap zombie for 3 seconds zombie.isTrapped = true; zombie.trappedTimer = 180; // 3 seconds if (!zombie.originalSpeed) { zombie.originalSpeed = zombie.speed; } zombie.speed = 0; // Stop movement // Deal damage over time var trapDamage = 0; var trapDamageInterval = LK.setInterval(function () { if (zombie.isTrapped) { zombie.takeDamage(0.5); trapDamage++; if (trapDamage >= 6) { // Stop after 6 ticks LK.clearInterval(trapDamageInterval); } } else { LK.clearInterval(trapDamageInterval); } }, 30); // Visual effects LK.effects.flashObject(zombie, 0x8B4513, 300); LK.effects.flashObject(self, 0xFF0000, 500); // Disarm trap self.isArmed = false; trapGraphics.alpha = 0.3; trapGraphics.tint = 0x696969; // Gray when used // Remove trap after use LK.setTimeout(function () { self.destroy(); var index = traps.indexOf(self); if (index > -1) { traps.splice(index, 1); } }, 3000); }; return self; }); var WeakeningZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('weakeningZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0x4B0082; // Dark purple tint for weakening zombies self.speed = 0.9; self.health = 25; self.maxHealth = 25; self.targetX = cityCenter.x; self.targetY = cityCenter.y; self.weakenTimer = 0; self.weakenRate = 120; // Weaken troops every 2 seconds (120 frames) self.weakenRadius = 180; // Radius to weaken troops // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle immunity timer if (self.isImmune) { self.immunityTimer--; if (self.immunityTimer <= 0) { self.isImmune = false; } } // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0x4B0082 }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0x4B0082 }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0x4B0082; // Dark purple } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF8C00; // Orange } else { zombieGraphics.tint = 0xFF0000; // Red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Weaken nearby troops periodically self.weakenTimer++; if (self.weakenTimer >= self.weakenRate) { self.weakenNearbyTroops(); self.weakenTimer = 0; } }; self.weakenNearbyTroops = function () { // Weaken soldiers - reduce damage for (var i = 0; i < soldiers.length; i++) { var soldier = soldiers[i]; var dx = soldier.x - self.x; var dy = soldier.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark soldier as damage weakened if (!soldier.isDamageWeakened) { soldier.isDamageWeakened = true; // Visual effect when weakening LK.effects.flashObject(soldier, 0x4B0082, 300); } soldier.damageWeakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken gunners - reduce damage for (var i = 0; i < gunners.length; i++) { var gunner = gunners[i]; var dx = gunner.x - self.x; var dy = gunner.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark gunner as damage weakened if (!gunner.isDamageWeakened) { gunner.isDamageWeakened = true; // Visual effect when weakening LK.effects.flashObject(gunner, 0x4B0082, 300); } gunner.damageWeakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken bombers - reduce damage for (var i = 0; i < bombers.length; i++) { var bomber = bombers[i]; var dx = bomber.x - self.x; var dy = bomber.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark bomber as damage weakened if (!bomber.isDamageWeakened) { bomber.isDamageWeakened = true; // Visual effect when weakening LK.effects.flashObject(bomber, 0x4B0082, 300); } bomber.damageWeakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken towers - reduce damage for (var i = 0; i < towers.length; i++) { var tower = towers[i]; var dx = tower.x - self.x; var dy = tower.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark tower as damage weakened if (!tower.isDamageWeakened) { tower.isDamageWeakened = true; // Visual effect when weakening LK.effects.flashObject(tower, 0x4B0082, 300); } tower.damageWeakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Visual effect when weakening others LK.effects.flashObject(self, 0x4B0082, 500); }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 12; // Moderate points for killing weakening zombies updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var WeakerZombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('weakerZombie', { anchorX: 0.5, anchorY: 0.5 }); zombieGraphics.tint = 0x8A2BE2; // Blue violet tint for weaker zombies self.speed = 0.8; self.health = 22; self.maxHealth = 22; self.targetX = cityCenter.x; self.targetY = cityCenter.y; self.weakenTimer = 0; self.weakenRate = 120; // Weaken troops every 2 seconds (120 frames) self.weakenRadius = 150; // Radius to weaken troops // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -50 }); self.update = function () { // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0x8A2BE2 }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0x8A2BE2 }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update visual based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.7) { zombieGraphics.tint = 0x8A2BE2; // Blue violet } else if (healthPercent > 0.4) { zombieGraphics.tint = 0xFF8C00; // Orange } else { zombieGraphics.tint = 0xFF0000; // Red } // Update health bar healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Weaken nearby troops periodically self.weakenTimer++; if (self.weakenTimer >= self.weakenRate) { self.weakenNearbyTroops(); self.weakenTimer = 0; } }; self.weakenNearbyTroops = function () { // Weaken soldiers for (var i = 0; i < soldiers.length; i++) { var soldier = soldiers[i]; var dx = soldier.x - self.x; var dy = soldier.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark soldier as weakened if (!soldier.isWeakened) { soldier.isWeakened = true; soldier.originalShootRate = soldier.shootRate; soldier.shootRate = Math.floor(soldier.shootRate * 1.5); // 50% slower shooting // Visual effect when weakening LK.effects.flashObject(soldier, 0x8A2BE2, 300); } soldier.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken gunners for (var i = 0; i < gunners.length; i++) { var gunner = gunners[i]; var dx = gunner.x - self.x; var dy = gunner.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark gunner as weakened if (!gunner.isWeakened) { gunner.isWeakened = true; gunner.originalShootRate = gunner.shootRate; gunner.shootRate = Math.floor(gunner.shootRate * 1.5); // 50% slower shooting // Visual effect when weakening LK.effects.flashObject(gunner, 0x8A2BE2, 300); } gunner.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken bombers for (var i = 0; i < bombers.length; i++) { var bomber = bombers[i]; var dx = bomber.x - self.x; var dy = bomber.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark bomber as weakened if (!bomber.isWeakened) { bomber.isWeakened = true; bomber.originalShootRate = bomber.shootRate; bomber.shootRate = Math.floor(bomber.shootRate * 1.5); // 50% slower shooting // Visual effect when weakening LK.effects.flashObject(bomber, 0x8A2BE2, 300); } bomber.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken exploders for (var i = 0; i < exploders.length; i++) { var exploder = exploders[i]; var dx = exploder.x - self.x; var dy = exploder.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark exploder as weakened if (!exploder.isWeakened) { exploder.isWeakened = true; exploder.originalSpeed = exploder.speed; exploder.speed = exploder.speed * 0.7; // 30% slower movement // Visual effect when weakening LK.effects.flashObject(exploder, 0x8A2BE2, 300); } exploder.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken freezers for (var i = 0; i < freezers.length; i++) { var freezer = freezers[i]; var dx = freezer.x - self.x; var dy = freezer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark freezer as weakened if (!freezer.isWeakened) { freezer.isWeakened = true; freezer.originalSpeed = freezer.speed; freezer.speed = freezer.speed * 0.7; // 30% slower movement // Visual effect when weakening LK.effects.flashObject(freezer, 0x8A2BE2, 300); } freezer.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken burners for (var i = 0; i < burners.length; i++) { var burner = burners[i]; var dx = burner.x - self.x; var dy = burner.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark burner as weakened if (!burner.isWeakened) { burner.isWeakened = true; burner.originalSpeed = burner.speed; burner.speed = burner.speed * 0.7; // 30% slower movement // Visual effect when weakening LK.effects.flashObject(burner, 0x8A2BE2, 300); } burner.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken flamethrowers for (var i = 0; i < flamethrowers.length; i++) { var flamethrower = flamethrowers[i]; var dx = flamethrower.x - self.x; var dy = flamethrower.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark flamethrower as weakened if (!flamethrower.isWeakened) { flamethrower.isWeakened = true; flamethrower.originalBurnRate = flamethrower.burnRate; flamethrower.burnRate = Math.floor(flamethrower.burnRate * 1.5); // 50% slower burning // Visual effect when weakening LK.effects.flashObject(flamethrower, 0x8A2BE2, 300); } flamethrower.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Weaken freezer troops for (var i = 0; i < freezerTroops.length; i++) { var freezerTroop = freezerTroops[i]; var dx = freezerTroop.x - self.x; var dy = freezerTroop.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.weakenRadius) { // Mark freezer troop as weakened if (!freezerTroop.isWeakened) { freezerTroop.isWeakened = true; freezerTroop.originalSpeed = freezerTroop.speed; freezerTroop.speed = freezerTroop.speed * 0.7; // 30% slower movement // Visual effect when weakening LK.effects.flashObject(freezerTroop, 0x8A2BE2, 300); } freezerTroop.weakenTimer = 600; // Weakened for 10 seconds (600 frames) } } // Visual effect when weakening others LK.effects.flashObject(self, 0x8A2BE2, 500); }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 10; // Moderate points for killing weaker zombies updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1; self.health = 3; self.maxHealth = 3; self.targetX = cityCenter.x; self.targetY = cityCenter.y; // Create health bar var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -40 }); var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5, x: -29, y: -40 }); self.update = function () { // Handle immunity timer if (self.isImmune) { self.immunityTimer--; if (self.immunityTimer <= 0) { self.isImmune = false; } } // Handle stunned state if (self.isStunned) { self.stunnedTimer--; if (self.stunnedTimer <= 0) { self.isStunned = false; self.speed = self.originalSpeed; } } // Handle trapped state if (self.isTrapped) { self.trappedTimer--; if (self.trappedTimer <= 0) { self.isTrapped = false; self.speed = self.originalSpeed; } } // Handle frozen state if (self.isFrozen) { self.frozenTimer--; if (self.frozenTimer <= 0) { self.isFrozen = false; self.speed = self.originalSpeed; tween(zombieGraphics, { tint: 0xFFFFFF }, { duration: 500, easing: tween.easeOut }); } } // Handle burning state if (self.isBurning) { self.burnTimer--; self.burnDamageTimer++; // Deal burn damage every 30 frames (0.5 seconds) if (self.burnDamageTimer >= 30) { self.takeDamage(0.5); // Burn damage self.burnDamageTimer = 0; LK.effects.flashObject(self, 0xFF4500, 100); } if (self.burnTimer <= 0) { self.isBurning = false; tween(zombieGraphics, { tint: 0xFFFFFF }, { duration: 500, easing: tween.easeOut }); } } // Move toward city center (only if not frozen) if (!self.isFrozen) { 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; } } // Update health bar var healthPercent = self.health / self.maxHealth; healthBarFill.width = 58 * healthPercent; if (healthPercent > 0.7) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.takeDamage = function (damage) { if (damage === undefined) damage = 1; // Default damage is 1 self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('zombieHit').play(); gamePoints += 5; updateUI(); // Remove from zombies array var index = zombies.indexOf(self); if (index > -1) { zombies.splice(index, 1); } self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2e2e2e }); /**** * Game Code ****/ // Game variables var towers = []; var zombies = []; var bullets = []; var fastBullets = []; var barriers = []; var soldiers = []; var gunners = []; var bombers = []; var bombs = []; var miners = []; var catchers = []; var exploders = []; var freezers = []; var burners = []; var flamethrowers = []; var freezerTroops = []; var fireTiles = []; var eliteSnipers = []; var heavyTanks = []; var laserTurrets = []; var rocketLaunchers = []; var rockets = []; var shieldGenerators = []; var supportMedics = []; var assassins = []; var engineers = []; var mortars = []; var shockTroopers = []; var traps = []; var gamePoints = 50; var wave = 1; var zombiesSpawned = 0; var zombiesToSpawn = 5; var spawnTimer = 0; var waveComplete = true; var gridSize = 80; var towerCost = 20; var barrierCost = 30; var soldierCost = 40; var gunnerCost = 35; var bomberCost = 60; var minerCost = 35; var catcherCost = 45; var exploderCost = 50; var freezerCost = 70; var burnerCost = 80; var flamethrowerCost = 55; var freezerTroopCost = 50; var eliteSniperCost = 100; var heavyTankCost = 120; var laserTurretCost = 90; var rocketLauncherCost = 110; var shieldGeneratorCost = 80; var supportMedicCost = 65; var assassinCost = 85; var engineerCost = 70; var mortarCost = 130; var shockTrooperCost = 75; var trapCost = 25; // Create city center var cityCenter = game.addChild(LK.getAsset('cityCenter', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 })); // Create UI elements var pointsText = new Text2('Points: 50', { size: 60, fill: 0xFFFFFF }); pointsText.anchor.set(0, 0); LK.gui.topRight.addChild(pointsText); var moneyText = new Text2('Money: 50', { size: 60, fill: 0xffd700 }); moneyText.anchor.set(1, 0); moneyText.x = -20; LK.gui.topRight.addChild(moneyText); var waveText = new Text2('Wave: 1', { size: 60, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); LK.gui.top.addChild(waveText); // Create GUI buttons var towerButton = new Text2('Tower (20)', { size: 45, fill: 0xFFFFFF }); towerButton.anchor.set(0, 1); towerButton.x = 20; towerButton.y = -20; LK.gui.bottomLeft.addChild(towerButton); var barrierButton = new Text2('Barrier (30)', { size: 45, fill: 0xFFFFFF }); barrierButton.anchor.set(0, 1); barrierButton.x = 280; barrierButton.y = -20; LK.gui.bottomLeft.addChild(barrierButton); var soldierButton = new Text2('Soldier (40)', { size: 45, fill: 0xFFFFFF }); soldierButton.anchor.set(0, 1); soldierButton.x = 540; soldierButton.y = -20; LK.gui.bottomLeft.addChild(soldierButton); var gunnerButton = new Text2('Gunner (35)', { size: 45, fill: 0xFFFFFF }); gunnerButton.anchor.set(0, 1); gunnerButton.x = 800; gunnerButton.y = -20; LK.gui.bottomLeft.addChild(gunnerButton); var bomberButton = new Text2('Bomber (60)', { size: 45, fill: 0xFFFFFF }); bomberButton.anchor.set(0, 1); bomberButton.x = 1060; bomberButton.y = -20; LK.gui.bottomLeft.addChild(bomberButton); var minerButton = new Text2('Miner (35)', { size: 45, fill: 0xFFFFFF }); minerButton.anchor.set(0, 1); minerButton.x = 20; minerButton.y = -80; LK.gui.bottomLeft.addChild(minerButton); var catcherButton = new Text2('Catcher (45)', { size: 45, fill: 0xFFFFFF }); catcherButton.anchor.set(0, 1); catcherButton.x = 280; catcherButton.y = -80; LK.gui.bottomLeft.addChild(catcherButton); var exploderButton = new Text2('Exploder (50)', { size: 45, fill: 0xFFFFFF }); exploderButton.anchor.set(0, 1); exploderButton.x = 540; exploderButton.y = -80; LK.gui.bottomLeft.addChild(exploderButton); var freezerButton = new Text2('Freezer (70)', { size: 45, fill: 0xFFFFFF }); freezerButton.anchor.set(0, 1); freezerButton.x = 800; freezerButton.y = -80; LK.gui.bottomLeft.addChild(freezerButton); var burnerButton = new Text2('Burner (80)', { size: 45, fill: 0xFFFFFF }); burnerButton.anchor.set(0, 1); burnerButton.x = 1060; burnerButton.y = -80; LK.gui.bottomLeft.addChild(burnerButton); var flamethrowerButton = new Text2('Flamethrower (55)', { size: 45, fill: 0xFFFFFF }); flamethrowerButton.anchor.set(0, 0); flamethrowerButton.x = 120; flamethrowerButton.y = 20; LK.gui.topLeft.addChild(flamethrowerButton); var freezerTroopButton = new Text2('FreezerTroop (50)', { size: 45, fill: 0xFFFFFF }); freezerTroopButton.anchor.set(0, 0); freezerTroopButton.x = 120; freezerTroopButton.y = 80; LK.gui.topLeft.addChild(freezerTroopButton); var eliteSniperButton = new Text2('EliteSniper (100)', { size: 45, fill: 0xFFFFFF }); eliteSniperButton.anchor.set(0, 0); eliteSniperButton.x = 120; eliteSniperButton.y = 140; LK.gui.topLeft.addChild(eliteSniperButton); var heavyTankButton = new Text2('HeavyTank (120)', { size: 45, fill: 0xFFFFFF }); heavyTankButton.anchor.set(0, 0); heavyTankButton.x = 120; heavyTankButton.y = 200; LK.gui.topLeft.addChild(heavyTankButton); var laserTurretButton = new Text2('LaserTurret (90)', { size: 45, fill: 0xFFFFFF }); laserTurretButton.anchor.set(0, 0); laserTurretButton.x = 120; laserTurretButton.y = 260; LK.gui.topLeft.addChild(laserTurretButton); var rocketLauncherButton = new Text2('RocketLauncher (110)', { size: 45, fill: 0xFFFFFF }); rocketLauncherButton.anchor.set(0, 0); rocketLauncherButton.x = 120; rocketLauncherButton.y = 320; LK.gui.topLeft.addChild(rocketLauncherButton); var shieldGeneratorButton = new Text2('ShieldGenerator (80)', { size: 45, fill: 0xFFFFFF }); shieldGeneratorButton.anchor.set(0, 0); shieldGeneratorButton.x = 120; shieldGeneratorButton.y = 380; LK.gui.topLeft.addChild(shieldGeneratorButton); var supportMedicButton = new Text2('SupportMedic (65)', { size: 45, fill: 0xFFFFFF }); supportMedicButton.anchor.set(0, 0); supportMedicButton.x = 120; supportMedicButton.y = 440; LK.gui.topLeft.addChild(supportMedicButton); var assassinButton = new Text2('Assassin (85)', { size: 45, fill: 0xFFFFFF }); assassinButton.anchor.set(0, 0); assassinButton.x = 120; assassinButton.y = 500; LK.gui.topLeft.addChild(assassinButton); var engineerButton = new Text2('Engineer (70)', { size: 45, fill: 0xFFFFFF }); engineerButton.anchor.set(0, 0); engineerButton.x = 120; engineerButton.y = 560; LK.gui.topLeft.addChild(engineerButton); var mortarButton = new Text2('Mortar (130)', { size: 45, fill: 0xFFFFFF }); mortarButton.anchor.set(0, 0); mortarButton.x = 120; mortarButton.y = 620; LK.gui.topLeft.addChild(mortarButton); var shockTrooperButton = new Text2('ShockTrooper (75)', { size: 45, fill: 0xFFFFFF }); shockTrooperButton.anchor.set(0, 0); shockTrooperButton.x = 120; shockTrooperButton.y = 680; LK.gui.topLeft.addChild(shockTrooperButton); var trapButton = new Text2('Trap (25)', { size: 45, fill: 0xFFFFFF }); trapButton.anchor.set(0, 0); trapButton.x = 120; trapButton.y = 740; LK.gui.topLeft.addChild(trapButton); function updateUI() { pointsText.setText('Points: ' + gamePoints); moneyText.setText('Money: ' + gamePoints); waveText.setText('Wave: ' + wave); } function snapToGrid(value) { return Math.floor(value / gridSize) * gridSize + gridSize / 2; } function canPlaceTower(x, y) { // Check if position is too close to city center var dx = x - cityCenter.x; var dy = y - cityCenter.y; var distanceToCenter = Math.sqrt(dx * dx + dy * dy); if (distanceToCenter < 150) { return false; } // Check if there's already a tower at this position for (var i = 0; i < towers.length; i++) { var tower = towers[i]; if (Math.abs(tower.x - x) < gridSize / 2 && Math.abs(tower.y - y) < gridSize / 2) { return false; } } // Check if there's already a barrier at this position for (var i = 0; i < barriers.length; i++) { var barrier = barriers[i]; if (Math.abs(barrier.x - x) < gridSize / 2 && Math.abs(barrier.y - y) < gridSize / 2) { return false; } } return true; } function placeTower(x, y) { if (gamePoints >= towerCost && canPlaceTower(x, y)) { var tower = new Tower(); tower.x = x; tower.y = y; towers.push(tower); game.addChild(tower); gamePoints -= towerCost; updateUI(); } } function placeBarrier(x, y) { if (gamePoints >= barrierCost && canPlaceTower(x, y)) { var barrier = new Barrier(); barrier.x = x; barrier.y = y; barriers.push(barrier); game.addChild(barrier); gamePoints -= barrierCost; updateUI(); } } function placeSoldier(x, y) { if (gamePoints >= soldierCost) { var soldier = new Soldier(); soldier.x = x; soldier.y = y; soldiers.push(soldier); game.addChild(soldier); gamePoints -= soldierCost; updateUI(); } } function placeGunner(x, y) { if (gamePoints >= gunnerCost) { var gunner = new Gunner(); gunner.x = x; gunner.y = y; gunners.push(gunner); game.addChild(gunner); gamePoints -= gunnerCost; updateUI(); } } function placeBomber(x, y) { if (gamePoints >= bomberCost) { var bomber = new Bomber(); bomber.x = x; bomber.y = y; bombers.push(bomber); game.addChild(bomber); gamePoints -= bomberCost; updateUI(); } } function placeMiner(x, y) { if (gamePoints >= minerCost) { var miner = new Miner(); miner.x = x; miner.y = y; miners.push(miner); game.addChild(miner); gamePoints -= minerCost; updateUI(); } } function placeCatcher(x, y) { if (gamePoints >= catcherCost) { var catcher = new Catcher(); catcher.x = x; catcher.y = y; catchers.push(catcher); game.addChild(catcher); gamePoints -= catcherCost; updateUI(); } } function placeExploder(x, y) { if (gamePoints >= exploderCost) { var exploder = new Exploder(); exploder.x = x; exploder.y = y; exploders.push(exploder); game.addChild(exploder); gamePoints -= exploderCost; updateUI(); } } function placeFreezer(x, y) { if (gamePoints >= freezerCost) { var freezer = new Freezer(); freezer.x = x; freezer.y = y; freezers.push(freezer); game.addChild(freezer); gamePoints -= freezerCost; updateUI(); } } function placeBurner(x, y) { if (gamePoints >= burnerCost) { var burner = new Burner(); burner.x = x; burner.y = y; burners.push(burner); game.addChild(burner); gamePoints -= burnerCost; updateUI(); } } function placeFlamethrower(x, y) { if (gamePoints >= flamethrowerCost) { var flamethrower = new Flamethrower(); flamethrower.x = x; flamethrower.y = y; flamethrowers.push(flamethrower); game.addChild(flamethrower); gamePoints -= flamethrowerCost; updateUI(); } } function placeFreezerTroop(x, y) { if (gamePoints >= freezerTroopCost) { var freezerTroop = new FreezerTroop(); freezerTroop.x = x; freezerTroop.y = y; freezerTroops.push(freezerTroop); game.addChild(freezerTroop); gamePoints -= freezerTroopCost; updateUI(); } } function placeEliteSniper(x, y) { if (gamePoints >= eliteSniperCost) { var eliteSniper = new EliteSniper(); eliteSniper.x = x; eliteSniper.y = y; eliteSnipers.push(eliteSniper); game.addChild(eliteSniper); gamePoints -= eliteSniperCost; updateUI(); } } function placeHeavyTank(x, y) { if (gamePoints >= heavyTankCost) { var heavyTank = new HeavyTank(); heavyTank.x = x; heavyTank.y = y; heavyTanks.push(heavyTank); game.addChild(heavyTank); gamePoints -= heavyTankCost; updateUI(); } } function placeLaserTurret(x, y) { if (gamePoints >= laserTurretCost && canPlaceTower(x, y)) { var laserTurret = new LaserTurret(); laserTurret.x = x; laserTurret.y = y; laserTurrets.push(laserTurret); game.addChild(laserTurret); gamePoints -= laserTurretCost; updateUI(); } } function placeRocketLauncher(x, y) { if (gamePoints >= rocketLauncherCost && canPlaceTower(x, y)) { var rocketLauncher = new RocketLauncher(); rocketLauncher.x = x; rocketLauncher.y = y; rocketLaunchers.push(rocketLauncher); game.addChild(rocketLauncher); gamePoints -= rocketLauncherCost; updateUI(); } } function placeShieldGenerator(x, y) { if (gamePoints >= shieldGeneratorCost && canPlaceTower(x, y)) { var shieldGenerator = new ShieldGenerator(); shieldGenerator.x = x; shieldGenerator.y = y; shieldGenerators.push(shieldGenerator); game.addChild(shieldGenerator); gamePoints -= shieldGeneratorCost; updateUI(); } } function placeSupportMedic(x, y) { if (gamePoints >= supportMedicCost) { var supportMedic = new SupportMedic(); supportMedic.x = x; supportMedic.y = y; supportMedics.push(supportMedic); game.addChild(supportMedic); gamePoints -= supportMedicCost; updateUI(); } } function placeAssassin(x, y) { if (gamePoints >= assassinCost) { var assassin = new Assassin(); assassin.x = x; assassin.y = y; assassins.push(assassin); game.addChild(assassin); gamePoints -= assassinCost; updateUI(); } } function placeEngineer(x, y) { if (gamePoints >= engineerCost) { var engineer = new Engineer(); engineer.x = x; engineer.y = y; engineers.push(engineer); game.addChild(engineer); gamePoints -= engineerCost; updateUI(); } } function placeMortar(x, y) { if (gamePoints >= mortarCost && canPlaceTower(x, y)) { var mortar = new Mortar(); mortar.x = x; mortar.y = y; mortars.push(mortar); game.addChild(mortar); gamePoints -= mortarCost; updateUI(); } } function placeShockTrooper(x, y) { if (gamePoints >= shockTrooperCost) { var shockTrooper = new ShockTrooper(); shockTrooper.x = x; shockTrooper.y = y; shockTroopers.push(shockTrooper); game.addChild(shockTrooper); gamePoints -= shockTrooperCost; updateUI(); } } function placeTrap(x, y) { if (gamePoints >= trapCost) { var trap = new Trap(); trap.x = x; trap.y = y; traps.push(trap); game.addChild(trap); gamePoints -= trapCost; updateUI(); } } function getTowerAt(x, y) { for (var i = 0; i < towers.length; i++) { var tower = towers[i]; var dx = Math.abs(tower.x - x); var dy = Math.abs(tower.y - y); if (dx < gridSize / 2 && dy < gridSize / 2) { return tower; } } return null; } function updateButtonColors() { // Reset all button colors towerButton.tint = selectedMode === 'tower' ? 0x4CAF50 : 0xFFFFFF; barrierButton.tint = selectedMode === 'barrier' ? 0x4CAF50 : 0xFFFFFF; soldierButton.tint = selectedMode === 'soldier' ? 0x4CAF50 : 0xFFFFFF; gunnerButton.tint = selectedMode === 'gunner' ? 0x4CAF50 : 0xFFFFFF; bomberButton.tint = selectedMode === 'bomber' ? 0x4CAF50 : 0xFFFFFF; minerButton.tint = selectedMode === 'miner' ? 0x4CAF50 : 0xFFFFFF; catcherButton.tint = selectedMode === 'catcher' ? 0x4CAF50 : 0xFFFFFF; exploderButton.tint = selectedMode === 'exploder' ? 0x4CAF50 : 0xFFFFFF; freezerButton.tint = selectedMode === 'freezer' ? 0x4CAF50 : 0xFFFFFF; burnerButton.tint = selectedMode === 'burner' ? 0x4CAF50 : 0xFFFFFF; flamethrowerButton.tint = selectedMode === 'flamethrower' ? 0x4CAF50 : 0xFFFFFF; freezerTroopButton.tint = selectedMode === 'freezerTroop' ? 0x4CAF50 : 0xFFFFFF; eliteSniperButton.tint = selectedMode === 'eliteSniper' ? 0x4CAF50 : 0xFFFFFF; heavyTankButton.tint = selectedMode === 'heavyTank' ? 0x4CAF50 : 0xFFFFFF; laserTurretButton.tint = selectedMode === 'laserTurret' ? 0x4CAF50 : 0xFFFFFF; rocketLauncherButton.tint = selectedMode === 'rocketLauncher' ? 0x4CAF50 : 0xFFFFFF; shieldGeneratorButton.tint = selectedMode === 'shieldGenerator' ? 0x4CAF50 : 0xFFFFFF; supportMedicButton.tint = selectedMode === 'supportMedic' ? 0x4CAF50 : 0xFFFFFF; assassinButton.tint = selectedMode === 'assassin' ? 0x4CAF50 : 0xFFFFFF; engineerButton.tint = selectedMode === 'engineer' ? 0x4CAF50 : 0xFFFFFF; mortarButton.tint = selectedMode === 'mortar' ? 0x4CAF50 : 0xFFFFFF; shockTrooperButton.tint = selectedMode === 'shockTrooper' ? 0x4CAF50 : 0xFFFFFF; trapButton.tint = selectedMode === 'trap' ? 0x4CAF50 : 0xFFFFFF; } // Button event handlers towerButton.down = function () { selectedMode = 'tower'; updateButtonColors(); }; barrierButton.down = function () { selectedMode = 'barrier'; updateButtonColors(); }; soldierButton.down = function () { selectedMode = 'soldier'; updateButtonColors(); }; gunnerButton.down = function () { selectedMode = 'gunner'; updateButtonColors(); }; bomberButton.down = function () { selectedMode = 'bomber'; updateButtonColors(); }; minerButton.down = function () { selectedMode = 'miner'; updateButtonColors(); }; catcherButton.down = function () { selectedMode = 'catcher'; updateButtonColors(); }; exploderButton.down = function () { selectedMode = 'exploder'; updateButtonColors(); }; freezerButton.down = function () { selectedMode = 'freezer'; updateButtonColors(); }; burnerButton.down = function () { selectedMode = 'burner'; updateButtonColors(); }; flamethrowerButton.down = function () { selectedMode = 'flamethrower'; updateButtonColors(); }; freezerTroopButton.down = function () { selectedMode = 'freezerTroop'; updateButtonColors(); }; eliteSniperButton.down = function () { selectedMode = 'eliteSniper'; updateButtonColors(); }; heavyTankButton.down = function () { selectedMode = 'heavyTank'; updateButtonColors(); }; laserTurretButton.down = function () { selectedMode = 'laserTurret'; updateButtonColors(); }; rocketLauncherButton.down = function () { selectedMode = 'rocketLauncher'; updateButtonColors(); }; shieldGeneratorButton.down = function () { selectedMode = 'shieldGenerator'; updateButtonColors(); }; supportMedicButton.down = function () { selectedMode = 'supportMedic'; updateButtonColors(); }; assassinButton.down = function () { selectedMode = 'assassin'; updateButtonColors(); }; engineerButton.down = function () { selectedMode = 'engineer'; updateButtonColors(); }; mortarButton.down = function () { selectedMode = 'mortar'; updateButtonColors(); }; shockTrooperButton.down = function () { selectedMode = 'shockTrooper'; updateButtonColors(); }; trapButton.down = function () { selectedMode = 'trap'; updateButtonColors(); }; // Initialize button colors updateButtonColors(); function spawnZombie() { var zombie; // 4% chance to spawn a weakening zombie after wave 4 if (wave >= 4 && Math.random() < 0.04) { zombie = new WeakeningZombie(); } else if (wave >= 3 && Math.random() < 0.03) { // 3% chance to spawn an immunity zombie after wave 3 zombie = new ImmunityZombie(); } else if (wave >= 2 && Math.random() < 0.05) { // 5% chance to spawn a spawner zombie after wave 2 zombie = new SpawnerZombie(); } else if (wave >= 2 && Math.random() < 0.08) { // 8% chance to spawn a weaker zombie after wave 2 zombie = new WeakerZombie(); } else if (wave >= 2 && Math.random() < 0.1) { // 10% chance to spawn a booster zombie after wave 2 zombie = new BoosterZombie(); } else if (wave >= 1 && Math.random() < 0.15) { // 15% chance to spawn a speedy zombie from wave 1 zombie = new SpeedyZombie(); } else if (wave >= 1 && Math.random() < 0.4) { // 40% chance to spawn a tank zombie from wave 1 zombie = new TankZombie(); } else { zombie = new Zombie(); } // Spawn from random edge var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top zombie.x = Math.random() * 2048; zombie.y = 0; break; case 1: // Right zombie.x = 2048; zombie.y = Math.random() * 2732; break; case 2: // Bottom zombie.x = Math.random() * 2048; zombie.y = 2732; break; case 3: // Left zombie.x = 0; zombie.y = Math.random() * 2732; break; } // Increase speed and health with waves if (zombie instanceof WeakeningZombie) { zombie.speed = 0.9 + (wave - 1) * 0.07; // Weakening zombies moderate scaling zombie.health = 25 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; zombie.weakenRate = Math.max(90, 120 - (wave - 1) * 3); // Weaken more frequently over time } else if (zombie instanceof ImmunityZombie) { zombie.speed = 0.7 + (wave - 1) * 0.06; // Immunity zombies moderate scaling zombie.health = 28 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; zombie.immunityRate = Math.max(45, 60 - (wave - 1) * 2); // Grant immunity more frequently over time } else if (zombie instanceof SpawnerZombie) { zombie.speed = 0.8 + (wave - 1) * 0.05; // Spawner zombies scale slowest zombie.health = 25 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; zombie.spawnRate = Math.max(180, 300 - (wave - 1) * 10); // Spawn faster over time } else if (zombie instanceof WeakerZombie) { zombie.speed = 0.8 + (wave - 1) * 0.07; // Weaker zombies moderate scaling zombie.health = 22 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; zombie.weakenRate = Math.max(90, 120 - (wave - 1) * 3); // Weaken more frequently over time } else if (zombie instanceof BoosterZombie) { zombie.speed = 0.9 + (wave - 1) * 0.08; // Booster zombies moderate scaling zombie.health = 35 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; zombie.boostRate = Math.max(120, 180 - (wave - 1) * 5); // Boost more frequently over time } else if (zombie instanceof SpeedyZombie) { zombie.speed = 2.5 + (wave - 1) * 0.15; // Speedy zombies get even faster zombie.health = 15 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; } else if (zombie instanceof TankZombie) { zombie.speed = 0.6 + (wave - 1) * 0.1; // Tank zombies scale slower zombie.health = 20 + Math.floor((wave - 1) / 2); zombie.maxHealth = zombie.health; } else { zombie.speed = 1 + (wave - 1) * 0.2; zombie.health = 3 + Math.floor((wave - 1) / 3); zombie.maxHealth = zombie.health; } zombies.push(zombie); game.addChild(zombie); } function startNextWave() { wave++; zombiesToSpawn = 5 + wave * 2; zombiesSpawned = 0; waveComplete = false; spawnTimer = 0; updateUI(); } var holdTimer = 0; var isHolding = false; var holdPosition = { x: 0, y: 0 }; var lastTapTime = 0; var doubleTapDelay = 300; // milliseconds var selectedMode = 'tower'; // 'tower', 'barrier', 'soldier', or 'bomber' game.down = function (x, y, obj) { var gridX = snapToGrid(x); var gridY = snapToGrid(y); var existingTower = getTowerAt(gridX, gridY); if (existingTower) { // Try to upgrade tower existingTower.upgrade(); return; } // Place unit based on selected mode if (selectedMode === 'tower') { placeTower(gridX, gridY); } else if (selectedMode === 'barrier') { placeBarrier(gridX, gridY); } else if (selectedMode === 'soldier') { placeSoldier(x, y); } else if (selectedMode === 'gunner') { placeGunner(x, y); } else if (selectedMode === 'bomber') { placeBomber(x, y); } else if (selectedMode === 'miner') { placeMiner(x, y); } else if (selectedMode === 'catcher') { placeCatcher(x, y); } else if (selectedMode === 'exploder') { placeExploder(x, y); } else if (selectedMode === 'freezer') { placeFreezer(x, y); } else if (selectedMode === 'burner') { placeBurner(x, y); } else if (selectedMode === 'flamethrower') { placeFlamethrower(x, y); } else if (selectedMode === 'freezerTroop') { placeFreezerTroop(x, y); } else if (selectedMode === 'eliteSniper') { placeEliteSniper(x, y); } else if (selectedMode === 'heavyTank') { placeHeavyTank(x, y); } else if (selectedMode === 'laserTurret') { placeLaserTurret(gridX, gridY); } else if (selectedMode === 'rocketLauncher') { placeRocketLauncher(gridX, gridY); } else if (selectedMode === 'shieldGenerator') { placeShieldGenerator(gridX, gridY); } else if (selectedMode === 'supportMedic') { placeSupportMedic(x, y); } else if (selectedMode === 'assassin') { placeAssassin(x, y); } else if (selectedMode === 'engineer') { placeEngineer(x, y); } else if (selectedMode === 'mortar') { placeMortar(gridX, gridY); } else if (selectedMode === 'shockTrooper') { placeShockTrooper(x, y); } else if (selectedMode === 'trap') { placeTrap(x, y); } }; game.update = function () { // Spawn zombies for current wave if (!waveComplete) { spawnTimer++; if (spawnTimer >= 60 && zombiesSpawned < zombiesToSpawn) { // Spawn every second spawnZombie(); zombiesSpawned++; spawnTimer = 0; } if (zombiesSpawned >= zombiesToSpawn && zombies.length === 0) { waveComplete = true; LK.setTimeout(startNextWave, 2000); // Start next wave after 2 seconds } } // Check if zombies reached city center for (var i = zombies.length - 1; i >= 0; i--) { var zombie = zombies[i]; var dx = zombie.x - cityCenter.x; var dy = zombie.y - cityCenter.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { // Game over LK.showGameOver(); return; } } // Update all towers (this enables shooting) for (var i = 0; i < towers.length; i++) { towers[i].update(); } // Update all barriers (this enables damage dealing) for (var i = 0; i < barriers.length; i++) { barriers[i].update(); } // Update all soldiers (this enables movement and shooting) for (var i = 0; i < soldiers.length; i++) { soldiers[i].update(); } // Update all gunners (this enables movement and fast shooting) for (var i = 0; i < gunners.length; i++) { gunners[i].update(); } // Update all bombers (this enables movement and bomb launching) for (var i = 0; i < bombers.length; i++) { bombers[i].update(); } // Update all bombs (this enables movement and explosion) for (var i = 0; i < bombs.length; i++) { bombs[i].update(); } // Update all miners (this enables money generation) for (var i = 0; i < miners.length; i++) { miners[i].update(); } // Update all catchers (this enables zombie freezing) for (var i = 0; i < catchers.length; i++) { catchers[i].update(); } // Update all exploders (this enables explosion mechanics) for (var i = 0; i < exploders.length; i++) { exploders[i].update(); } // Update all freezers (this enables global freeze mechanics) for (var i = 0; i < freezers.length; i++) { freezers[i].update(); } // Update all burners (this enables global burn mechanics) for (var i = 0; i < burners.length; i++) { burners[i].update(); } // Update all flamethrowers (this enables continuous burn mechanics) for (var i = 0; i < flamethrowers.length; i++) { flamethrowers[i].update(); } // Update all freezer troops (this enables continuous freeze mechanics) for (var i = 0; i < freezerTroops.length; i++) { freezerTroops[i].update(); } // Update all elite snipers (this enables high-damage sniping) for (var i = 0; i < eliteSnipers.length; i++) { eliteSnipers[i].update(); } // Update all heavy tanks (this enables armored combat) for (var i = 0; i < heavyTanks.length; i++) { heavyTanks[i].update(); } // Update all laser turrets (this enables continuous beam damage) for (var i = 0; i < laserTurrets.length; i++) { laserTurrets[i].update(); } // Update all rocket launchers (this enables area damage rockets) for (var i = 0; i < rocketLaunchers.length; i++) { rocketLaunchers[i].update(); } // Update all rockets (this enables rocket movement and explosion) for (var i = 0; i < rockets.length; i++) { rockets[i].update(); } // Update all shield generators (this enables defensive support) for (var i = 0; i < shieldGenerators.length; i++) { shieldGenerators[i].update(); } // Update all support medics (this enables healing) for (var i = 0; i < supportMedics.length; i++) { supportMedics[i].update(); } // Update all assassins (this enables stealth attacks) for (var i = 0; i < assassins.length; i++) { assassins[i].update(); } // Update all engineers (this enables repair mechanics) for (var i = 0; i < engineers.length; i++) { engineers[i].update(); } // Update all mortars (this enables artillery strikes) for (var i = 0; i < mortars.length; i++) { mortars[i].update(); } // Update all shock troopers (this enables electrical attacks) for (var i = 0; i < shockTroopers.length; i++) { shockTroopers[i].update(); } // Update all traps (this enables zombie trapping) for (var i = 0; i < traps.length; i++) { traps[i].update(); } // Update all fire tiles (this enables fire damage) for (var i = 0; i < fireTiles.length; i++) { fireTiles[i].update(); } // Update score LK.setScore(gamePoints + (wave - 1) * 100); }; // Pause information text var pauseInfoText = new Text2('', { size: 40, fill: 0xFFFFFF }); pauseInfoText.anchor.set(0.5, 0.5); pauseInfoText.x = 1024; pauseInfoText.y = 1366; pauseInfoText.alpha = 0; game.addChild(pauseInfoText); // Show troop information when game is paused LK.on('pause', function () { var infoText = 'TROOP ABILITIES:\n\n'; infoText += 'TOWER (20): Shoots bullets at zombies\n'; infoText += 'BARRIER (30): Blocks zombies, takes damage\n'; infoText += 'SOLDIER (40): Patrols and shoots at zombies\n'; infoText += 'GUNNER (35): Fast shooting, lower damage\n'; infoText += 'BOMBER (60): Launches explosive bombs\n'; infoText += 'MINER (35): Generates money over time\n'; infoText += 'CATCHER (45): Freezes zombies in range\n'; infoText += 'EXPLODER (50): Explodes near zombies, creates fire\n'; infoText += 'FREEZER (70): Global freeze explosion\n'; infoText += 'BURNER (80): Global burn explosion\n'; infoText += 'FLAMETHROWER (55): Burns zombies continuously\n'; infoText += 'FREEZER TROOP (50): Freezes with breathing\n'; infoText += 'ELITE SNIPER (100): High damage, long range\n'; infoText += 'HEAVY TANK (120): Armored, high health\n'; infoText += 'LASER TURRET (90): Continuous beam damage\n'; infoText += 'ROCKET LAUNCHER (110): Area damage rockets\n'; infoText += 'SHIELD GENERATOR (80): Protects nearby troops\n'; infoText += 'SUPPORT MEDIC (65): Heals nearby troops\n'; infoText += 'ASSASSIN (85): Stealth high-damage attacks\n'; infoText += 'ENGINEER (70): Repairs structures and tanks\n'; infoText += 'MORTAR (130): Long-range artillery strikes\n'; infoText += 'SHOCK TROOPER (75): Electrical area damage\n'; infoText += 'TRAP (25): Single-use zombie trap'; pauseInfoText.setText(infoText); pauseInfoText.alpha = 1; }); // Hide troop information when game is resumed LK.on('resume', function () { pauseInfoText.alpha = 0; }); // Start first wave after 3 seconds LK.setTimeout(startNextWave, 3000); ;
===================================================================
--- original.js
+++ change.js
@@ -5,8 +5,121 @@
/****
* Classes
****/
+var Assassin = Container.expand(function () {
+ var self = Container.call(this);
+ var assassinGraphics = self.attachAsset('assassin', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ assassinGraphics.tint = 0x2F4F4F; // Dark slate gray tint for assassins
+ self.range = 80; // Short range
+ self.attackCooldown = 0;
+ self.attackRate = 180; // Slow but deadly attacks
+ self.speed = 1.5; // Fast movement
+ self.patrolTarget = null;
+ self.mode = 'patrol';
+ self.isStealthed = false;
+ self.stealthTimer = 0;
+ self.update = function () {
+ // Handle weakening effect
+ if (self.isWeakened) {
+ self.weakenTimer--;
+ if (self.weakenTimer <= 0) {
+ self.isWeakened = false;
+ self.speed = self.originalSpeed;
+ }
+ }
+ // Handle damage weakening effect
+ if (self.isDamageWeakened) {
+ self.damageWeakenTimer--;
+ if (self.damageWeakenTimer <= 0) {
+ self.isDamageWeakened = false;
+ }
+ }
+ // Stealth mechanics
+ if (self.isStealthed) {
+ self.stealthTimer--;
+ if (self.stealthTimer <= 0) {
+ self.isStealthed = false;
+ assassinGraphics.alpha = 1.0;
+ }
+ }
+ // Decrease attack cooldown
+ if (self.attackCooldown > 0) {
+ self.attackCooldown--;
+ }
+ // Find nearest zombie in range
+ var nearestZombie = null;
+ var nearestDistance = Infinity;
+ for (var i = 0; i < zombies.length; i++) {
+ var zombie = zombies[i];
+ var dx = zombie.x - self.x;
+ var dy = zombie.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.range && distance < nearestDistance) {
+ nearestDistance = distance;
+ nearestZombie = zombie;
+ }
+ }
+ if (nearestZombie && self.attackCooldown === 0) {
+ self.mode = 'combat';
+ self.assassinate(nearestZombie);
+ self.attackCooldown = self.attackRate;
+ } else {
+ self.mode = 'patrol';
+ if (!self.patrolTarget || self.reachedTarget()) {
+ self.setNewPatrolTarget();
+ }
+ self.moveTowardTarget();
+ }
+ };
+ self.assassinate = function (target) {
+ // Enter stealth after attack
+ self.isStealthed = true;
+ self.stealthTimer = 120; // 2 seconds of stealth
+ assassinGraphics.alpha = 0.3;
+ // Deal massive damage
+ var damage = 8;
+ if (self.isDamageWeakened) {
+ damage = damage * 0.5;
+ }
+ target.takeDamage(damage);
+ // Visual effect
+ LK.effects.flashObject(self, 0x2F4F4F, 300);
+ LK.effects.flashObject(target, 0xFF0000, 500);
+ LK.getSound('shoot').play();
+ };
+ self.setNewPatrolTarget = function () {
+ var angle = Math.random() * Math.PI * 2;
+ var radius = 150 + Math.random() * 250;
+ self.patrolTarget = {
+ x: cityCenter.x + Math.cos(angle) * radius,
+ y: cityCenter.y + Math.sin(angle) * radius
+ };
+ self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x));
+ self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y));
+ };
+ self.moveTowardTarget = function () {
+ if (!self.patrolTarget) return;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - 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;
+ }
+ };
+ self.reachedTarget = function () {
+ if (!self.patrolTarget) return true;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ return distance < 20;
+ };
+ return self;
+});
var Barrier = Container.expand(function () {
var self = Container.call(this);
var barrierGraphics = self.attachAsset('tower', {
anchorX: 0.5,
@@ -747,8 +860,107 @@
return distance < 20;
};
return self;
});
+var Engineer = Container.expand(function () {
+ var self = Container.call(this);
+ var engineerGraphics = self.attachAsset('engineer', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ engineerGraphics.tint = 0xFFD700; // Gold tint for engineers
+ self.range = 100;
+ self.buildCooldown = 0;
+ self.buildRate = 240; // Build every 4 seconds
+ self.speed = 0.7;
+ self.patrolTarget = null;
+ self.mode = 'patrol';
+ self.update = function () {
+ // Handle weakening effect
+ if (self.isWeakened) {
+ self.weakenTimer--;
+ if (self.weakenTimer <= 0) {
+ self.isWeakened = false;
+ self.speed = self.originalSpeed;
+ }
+ }
+ // Decrease build cooldown
+ if (self.buildCooldown > 0) {
+ self.buildCooldown--;
+ }
+ // Repair nearby barriers and towers
+ if (self.buildCooldown === 0) {
+ self.repairNearbyStructures();
+ self.buildCooldown = self.buildRate;
+ }
+ // Patrol behavior
+ self.mode = 'patrol';
+ if (!self.patrolTarget || self.reachedTarget()) {
+ self.setNewPatrolTarget();
+ }
+ self.moveTowardTarget();
+ };
+ self.repairNearbyStructures = function () {
+ var repairedAny = false;
+ // Repair barriers
+ for (var i = 0; i < barriers.length; i++) {
+ var barrier = barriers[i];
+ if (barrier.health >= barrier.maxHealth) continue;
+ var dx = barrier.x - self.x;
+ var dy = barrier.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.range) {
+ barrier.health = Math.min(barrier.maxHealth, barrier.health + 25);
+ LK.effects.flashObject(barrier, 0xFFD700, 300);
+ repairedAny = true;
+ }
+ }
+ // Repair heavy tanks
+ for (var i = 0; i < heavyTanks.length; i++) {
+ var tank = heavyTanks[i];
+ if (tank.health >= tank.maxHealth) continue;
+ var dx = tank.x - self.x;
+ var dy = tank.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.range) {
+ tank.health = Math.min(tank.maxHealth, tank.health + 20);
+ LK.effects.flashObject(tank, 0xFFD700, 300);
+ repairedAny = true;
+ }
+ }
+ if (repairedAny) {
+ LK.effects.flashObject(self, 0xFFD700, 500);
+ }
+ };
+ self.setNewPatrolTarget = function () {
+ var angle = Math.random() * Math.PI * 2;
+ var radius = 200 + Math.random() * 300;
+ self.patrolTarget = {
+ x: cityCenter.x + Math.cos(angle) * radius,
+ y: cityCenter.y + Math.sin(angle) * radius
+ };
+ self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x));
+ self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y));
+ };
+ self.moveTowardTarget = function () {
+ if (!self.patrolTarget) return;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - 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;
+ }
+ };
+ self.reachedTarget = function () {
+ if (!self.patrolTarget) return true;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ return distance < 20;
+ };
+ return self;
+});
var Exploder = Container.expand(function () {
var self = Container.call(this);
var exploderGraphics = self.attachAsset('exploder', {
anchorX: 0.5,
@@ -1863,8 +2075,94 @@
}
};
return self;
});
+var Mortar = Container.expand(function () {
+ var self = Container.call(this);
+ var mortarGraphics = self.attachAsset('mortar', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ mortarGraphics.tint = 0x696969; // Dim gray tint for mortars
+ self.range = 400; // Very long range
+ self.shootCooldown = 0;
+ self.shootRate = 180; // Slow but powerful
+ self.update = function () {
+ // Handle damage weakening effect
+ if (self.isDamageWeakened) {
+ self.damageWeakenTimer--;
+ if (self.damageWeakenTimer <= 0) {
+ self.isDamageWeakened = false;
+ }
+ }
+ if (self.shootCooldown > 0) {
+ self.shootCooldown--;
+ return;
+ }
+ // Find nearest zombie in range
+ var nearestZombie = null;
+ var nearestDistance = Infinity;
+ for (var i = 0; i < zombies.length; i++) {
+ var zombie = zombies[i];
+ var dx = zombie.x - self.x;
+ var dy = zombie.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.range && distance < nearestDistance) {
+ nearestDistance = distance;
+ nearestZombie = zombie;
+ }
+ }
+ if (nearestZombie) {
+ self.fireMortar(nearestZombie);
+ self.shootCooldown = self.shootRate;
+ }
+ };
+ self.fireMortar = function (target) {
+ // Create delayed explosion at target location
+ var explosionX = target.x;
+ var explosionY = target.y;
+ // Visual warning
+ LK.effects.flashObject(target, 0xFF0000, 1000);
+ // Delayed explosion
+ LK.setTimeout(function () {
+ var explosionRadius = 120;
+ for (var i = 0; i < zombies.length; i++) {
+ var zombie = zombies[i];
+ var dx = zombie.x - explosionX;
+ var dy = zombie.y - explosionY;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= explosionRadius) {
+ var damage = 4;
+ if (self.isDamageWeakened) {
+ damage = damage * 0.5;
+ }
+ zombie.takeDamage(damage);
+ }
+ }
+ // Explosion effect
+ LK.effects.flashScreen(0xFF4400, 300);
+ LK.getSound('bombExplode').play();
+ }, 1000);
+ // Recoil effect
+ tween(self, {
+ scaleX: 1.3,
+ scaleY: 1.3
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(self, {
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ }
+ });
+ };
+ return self;
+});
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphics = self.attachAsset('rocket', {
anchorX: 0.5,
@@ -2063,8 +2361,128 @@
LK.effects.flashObject(self, 0x00AAFF, 500);
};
return self;
});
+var ShockTrooper = Container.expand(function () {
+ var self = Container.call(this);
+ var shockGraphics = self.attachAsset('shockTrooper', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ shockGraphics.tint = 0x00CED1; // Dark turquoise tint for shock troopers
+ self.range = 160;
+ self.shockCooldown = 0;
+ self.shockRate = 120; // Shock every 2 seconds
+ self.speed = 1.0;
+ self.patrolTarget = null;
+ self.mode = 'patrol';
+ self.update = function () {
+ // Handle weakening effect
+ if (self.isWeakened) {
+ self.weakenTimer--;
+ if (self.weakenTimer <= 0) {
+ self.isWeakened = false;
+ self.speed = self.originalSpeed;
+ }
+ }
+ // Handle damage weakening effect
+ if (self.isDamageWeakened) {
+ self.damageWeakenTimer--;
+ if (self.damageWeakenTimer <= 0) {
+ self.isDamageWeakened = false;
+ }
+ }
+ // Decrease shock cooldown
+ if (self.shockCooldown > 0) {
+ self.shockCooldown--;
+ }
+ // Find zombies in range for shock attack
+ var zombiesInRange = [];
+ for (var i = 0; i < zombies.length; i++) {
+ var zombie = zombies[i];
+ var dx = zombie.x - self.x;
+ var dy = zombie.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.range) {
+ zombiesInRange.push(zombie);
+ }
+ }
+ if (zombiesInRange.length > 0 && self.shockCooldown === 0) {
+ self.mode = 'combat';
+ self.electricShock(zombiesInRange);
+ self.shockCooldown = self.shockRate;
+ } else {
+ self.mode = 'patrol';
+ if (!self.patrolTarget || self.reachedTarget()) {
+ self.setNewPatrolTarget();
+ }
+ self.moveTowardTarget();
+ }
+ };
+ self.electricShock = function (zombiesInRange) {
+ var damage = 2;
+ if (self.isDamageWeakened) {
+ damage = damage * 0.5;
+ }
+ for (var i = 0; i < zombiesInRange.length; i++) {
+ var zombie = zombiesInRange[i];
+ zombie.takeDamage(damage);
+ // Stun effect - slow zombie temporarily
+ zombie.isStunned = true;
+ zombie.stunnedTimer = 60; // 1 second stun
+ if (!zombie.originalSpeed) {
+ zombie.originalSpeed = zombie.speed;
+ }
+ zombie.speed = zombie.speed * 0.3; // 70% speed reduction
+ // Visual effect
+ tween(zombie, {
+ tint: 0x00CED1
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(zombie, {
+ tint: zombie.originalTint || 0xFFFFFF
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ }
+ });
+ }
+ // Shock visual effect
+ LK.effects.flashObject(self, 0x00CED1, 500);
+ LK.getSound('shoot').play();
+ };
+ self.setNewPatrolTarget = function () {
+ var angle = Math.random() * Math.PI * 2;
+ var radius = 200 + Math.random() * 300;
+ self.patrolTarget = {
+ x: cityCenter.x + Math.cos(angle) * radius,
+ y: cityCenter.y + Math.sin(angle) * radius
+ };
+ self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x));
+ self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y));
+ };
+ self.moveTowardTarget = function () {
+ if (!self.patrolTarget) return;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - 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;
+ }
+ };
+ self.reachedTarget = function () {
+ if (!self.patrolTarget) return true;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ return distance < 20;
+ };
+ return self;
+});
var Soldier = Container.expand(function () {
var self = Container.call(this);
var soldierGraphics = self.attachAsset('soldier', {
anchorX: 0.5,
@@ -2402,8 +2820,94 @@
self.destroy();
};
return self;
});
+var SupportMedic = Container.expand(function () {
+ var self = Container.call(this);
+ var medicGraphics = self.attachAsset('supportMedic', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ medicGraphics.tint = 0x00FF7F; // Spring green tint for support medics
+ self.range = 140;
+ self.healCooldown = 0;
+ self.healRate = 90; // Heal every 1.5 seconds
+ self.speed = 0.9;
+ self.patrolTarget = null;
+ self.mode = 'patrol';
+ self.update = function () {
+ // Handle weakening effect
+ if (self.isWeakened) {
+ self.weakenTimer--;
+ if (self.weakenTimer <= 0) {
+ self.isWeakened = false;
+ self.speed = self.originalSpeed;
+ }
+ }
+ // Decrease heal cooldown
+ if (self.healCooldown > 0) {
+ self.healCooldown--;
+ }
+ // Heal nearby troops
+ if (self.healCooldown === 0) {
+ self.healNearbyTroops();
+ self.healCooldown = self.healRate;
+ }
+ // Patrol behavior
+ self.mode = 'patrol';
+ if (!self.patrolTarget || self.reachedTarget()) {
+ self.setNewPatrolTarget();
+ }
+ self.moveTowardTarget();
+ };
+ self.healNearbyTroops = function () {
+ var healedAny = false;
+ var allTroops = [].concat(soldiers, gunners, bombers, heavyTanks, eliteSnipers);
+ for (var i = 0; i < allTroops.length; i++) {
+ var troop = allTroops[i];
+ if (!troop.health || troop.health >= troop.maxHealth) continue;
+ var dx = troop.x - self.x;
+ var dy = troop.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance <= self.range) {
+ troop.health = Math.min(troop.maxHealth, troop.health + 15);
+ LK.effects.flashObject(troop, 0x00FF7F, 300);
+ healedAny = true;
+ }
+ }
+ if (healedAny) {
+ LK.effects.flashObject(self, 0x00FF7F, 500);
+ }
+ };
+ self.setNewPatrolTarget = function () {
+ var angle = Math.random() * Math.PI * 2;
+ var radius = 200 + Math.random() * 300;
+ self.patrolTarget = {
+ x: cityCenter.x + Math.cos(angle) * radius,
+ y: cityCenter.y + Math.sin(angle) * radius
+ };
+ self.patrolTarget.x = Math.max(100, Math.min(1948, self.patrolTarget.x));
+ self.patrolTarget.y = Math.max(100, Math.min(2632, self.patrolTarget.y));
+ };
+ self.moveTowardTarget = function () {
+ if (!self.patrolTarget) return;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - 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;
+ }
+ };
+ self.reachedTarget = function () {
+ if (!self.patrolTarget) return true;
+ var dx = self.patrolTarget.x - self.x;
+ var dy = self.patrolTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ return distance < 20;
+ };
+ return self;
+});
var TankZombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('tankZombie', {
anchorX: 0.5,
@@ -2600,8 +3104,78 @@
return self.level * 15;
};
return self;
});
+var Trap = Container.expand(function () {
+ var self = Container.call(this);
+ var trapGraphics = self.attachAsset('trap', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ trapGraphics.tint = 0x8B4513; // Saddle brown tint for traps
+ self.isArmed = true;
+ self.lastIntersecting = {};
+ trapGraphics.alpha = 0.7; // Slightly transparent
+ self.update = function () {
+ if (!self.isArmed) return;
+ // Check collision with zombies
+ for (var i = 0; i < zombies.length; i++) {
+ var zombie = zombies[i];
+ var zombieId = zombies.indexOf(zombie);
+ // Initialize last intersecting state if not exists
+ if (self.lastIntersecting[zombieId] === undefined) {
+ self.lastIntersecting[zombieId] = false;
+ }
+ var currentIntersecting = self.intersects(zombie);
+ // Check if zombie just stepped on trap
+ if (!self.lastIntersecting[zombieId] && currentIntersecting) {
+ self.triggerTrap(zombie);
+ return;
+ }
+ // Update last intersecting state
+ self.lastIntersecting[zombieId] = currentIntersecting;
+ }
+ };
+ self.triggerTrap = function (zombie) {
+ // Trap zombie for 3 seconds
+ zombie.isTrapped = true;
+ zombie.trappedTimer = 180; // 3 seconds
+ if (!zombie.originalSpeed) {
+ zombie.originalSpeed = zombie.speed;
+ }
+ zombie.speed = 0; // Stop movement
+ // Deal damage over time
+ var trapDamage = 0;
+ var trapDamageInterval = LK.setInterval(function () {
+ if (zombie.isTrapped) {
+ zombie.takeDamage(0.5);
+ trapDamage++;
+ if (trapDamage >= 6) {
+ // Stop after 6 ticks
+ LK.clearInterval(trapDamageInterval);
+ }
+ } else {
+ LK.clearInterval(trapDamageInterval);
+ }
+ }, 30);
+ // Visual effects
+ LK.effects.flashObject(zombie, 0x8B4513, 300);
+ LK.effects.flashObject(self, 0xFF0000, 500);
+ // Disarm trap
+ self.isArmed = false;
+ trapGraphics.alpha = 0.3;
+ trapGraphics.tint = 0x696969; // Gray when used
+ // Remove trap after use
+ LK.setTimeout(function () {
+ self.destroy();
+ var index = traps.indexOf(self);
+ if (index > -1) {
+ traps.splice(index, 1);
+ }
+ }, 3000);
+ };
+ return self;
+});
var WeakeningZombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('weakeningZombie', {
anchorX: 0.5,
@@ -3091,8 +3665,24 @@
if (self.immunityTimer <= 0) {
self.isImmune = false;
}
}
+ // Handle stunned state
+ if (self.isStunned) {
+ self.stunnedTimer--;
+ if (self.stunnedTimer <= 0) {
+ self.isStunned = false;
+ self.speed = self.originalSpeed;
+ }
+ }
+ // Handle trapped state
+ if (self.isTrapped) {
+ self.trappedTimer--;
+ if (self.trappedTimer <= 0) {
+ self.isTrapped = false;
+ self.speed = self.originalSpeed;
+ }
+ }
// Handle frozen state
if (self.isFrozen) {
self.frozenTimer--;
if (self.frozenTimer <= 0) {
@@ -3201,8 +3791,14 @@
var laserTurrets = [];
var rocketLaunchers = [];
var rockets = [];
var shieldGenerators = [];
+var supportMedics = [];
+var assassins = [];
+var engineers = [];
+var mortars = [];
+var shockTroopers = [];
+var traps = [];
var gamePoints = 50;
var wave = 1;
var zombiesSpawned = 0;
var zombiesToSpawn = 5;
@@ -3225,8 +3821,14 @@
var heavyTankCost = 120;
var laserTurretCost = 90;
var rocketLauncherCost = 110;
var shieldGeneratorCost = 80;
+var supportMedicCost = 65;
+var assassinCost = 85;
+var engineerCost = 70;
+var mortarCost = 130;
+var shockTrooperCost = 75;
+var trapCost = 25;
// Create city center
var cityCenter = game.addChild(LK.getAsset('cityCenter', {
anchorX: 0.5,
anchorY: 0.5,
@@ -3389,8 +3991,56 @@
shieldGeneratorButton.anchor.set(0, 0);
shieldGeneratorButton.x = 120;
shieldGeneratorButton.y = 380;
LK.gui.topLeft.addChild(shieldGeneratorButton);
+var supportMedicButton = new Text2('SupportMedic (65)', {
+ size: 45,
+ fill: 0xFFFFFF
+});
+supportMedicButton.anchor.set(0, 0);
+supportMedicButton.x = 120;
+supportMedicButton.y = 440;
+LK.gui.topLeft.addChild(supportMedicButton);
+var assassinButton = new Text2('Assassin (85)', {
+ size: 45,
+ fill: 0xFFFFFF
+});
+assassinButton.anchor.set(0, 0);
+assassinButton.x = 120;
+assassinButton.y = 500;
+LK.gui.topLeft.addChild(assassinButton);
+var engineerButton = new Text2('Engineer (70)', {
+ size: 45,
+ fill: 0xFFFFFF
+});
+engineerButton.anchor.set(0, 0);
+engineerButton.x = 120;
+engineerButton.y = 560;
+LK.gui.topLeft.addChild(engineerButton);
+var mortarButton = new Text2('Mortar (130)', {
+ size: 45,
+ fill: 0xFFFFFF
+});
+mortarButton.anchor.set(0, 0);
+mortarButton.x = 120;
+mortarButton.y = 620;
+LK.gui.topLeft.addChild(mortarButton);
+var shockTrooperButton = new Text2('ShockTrooper (75)', {
+ size: 45,
+ fill: 0xFFFFFF
+});
+shockTrooperButton.anchor.set(0, 0);
+shockTrooperButton.x = 120;
+shockTrooperButton.y = 680;
+LK.gui.topLeft.addChild(shockTrooperButton);
+var trapButton = new Text2('Trap (25)', {
+ size: 45,
+ fill: 0xFFFFFF
+});
+trapButton.anchor.set(0, 0);
+trapButton.x = 120;
+trapButton.y = 740;
+LK.gui.topLeft.addChild(trapButton);
function updateUI() {
pointsText.setText('Points: ' + gamePoints);
moneyText.setText('Money: ' + gamePoints);
waveText.setText('Wave: ' + wave);
@@ -3608,8 +4258,74 @@
gamePoints -= shieldGeneratorCost;
updateUI();
}
}
+function placeSupportMedic(x, y) {
+ if (gamePoints >= supportMedicCost) {
+ var supportMedic = new SupportMedic();
+ supportMedic.x = x;
+ supportMedic.y = y;
+ supportMedics.push(supportMedic);
+ game.addChild(supportMedic);
+ gamePoints -= supportMedicCost;
+ updateUI();
+ }
+}
+function placeAssassin(x, y) {
+ if (gamePoints >= assassinCost) {
+ var assassin = new Assassin();
+ assassin.x = x;
+ assassin.y = y;
+ assassins.push(assassin);
+ game.addChild(assassin);
+ gamePoints -= assassinCost;
+ updateUI();
+ }
+}
+function placeEngineer(x, y) {
+ if (gamePoints >= engineerCost) {
+ var engineer = new Engineer();
+ engineer.x = x;
+ engineer.y = y;
+ engineers.push(engineer);
+ game.addChild(engineer);
+ gamePoints -= engineerCost;
+ updateUI();
+ }
+}
+function placeMortar(x, y) {
+ if (gamePoints >= mortarCost && canPlaceTower(x, y)) {
+ var mortar = new Mortar();
+ mortar.x = x;
+ mortar.y = y;
+ mortars.push(mortar);
+ game.addChild(mortar);
+ gamePoints -= mortarCost;
+ updateUI();
+ }
+}
+function placeShockTrooper(x, y) {
+ if (gamePoints >= shockTrooperCost) {
+ var shockTrooper = new ShockTrooper();
+ shockTrooper.x = x;
+ shockTrooper.y = y;
+ shockTroopers.push(shockTrooper);
+ game.addChild(shockTrooper);
+ gamePoints -= shockTrooperCost;
+ updateUI();
+ }
+}
+function placeTrap(x, y) {
+ if (gamePoints >= trapCost) {
+ var trap = new Trap();
+ trap.x = x;
+ trap.y = y;
+ traps.push(trap);
+ game.addChild(trap);
+ gamePoints -= trapCost;
+ updateUI();
+ }
+}
function getTowerAt(x, y) {
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
var dx = Math.abs(tower.x - x);
@@ -3638,8 +4354,14 @@
heavyTankButton.tint = selectedMode === 'heavyTank' ? 0x4CAF50 : 0xFFFFFF;
laserTurretButton.tint = selectedMode === 'laserTurret' ? 0x4CAF50 : 0xFFFFFF;
rocketLauncherButton.tint = selectedMode === 'rocketLauncher' ? 0x4CAF50 : 0xFFFFFF;
shieldGeneratorButton.tint = selectedMode === 'shieldGenerator' ? 0x4CAF50 : 0xFFFFFF;
+ supportMedicButton.tint = selectedMode === 'supportMedic' ? 0x4CAF50 : 0xFFFFFF;
+ assassinButton.tint = selectedMode === 'assassin' ? 0x4CAF50 : 0xFFFFFF;
+ engineerButton.tint = selectedMode === 'engineer' ? 0x4CAF50 : 0xFFFFFF;
+ mortarButton.tint = selectedMode === 'mortar' ? 0x4CAF50 : 0xFFFFFF;
+ shockTrooperButton.tint = selectedMode === 'shockTrooper' ? 0x4CAF50 : 0xFFFFFF;
+ trapButton.tint = selectedMode === 'trap' ? 0x4CAF50 : 0xFFFFFF;
}
// Button event handlers
towerButton.down = function () {
selectedMode = 'tower';
@@ -3708,8 +4430,32 @@
shieldGeneratorButton.down = function () {
selectedMode = 'shieldGenerator';
updateButtonColors();
};
+supportMedicButton.down = function () {
+ selectedMode = 'supportMedic';
+ updateButtonColors();
+};
+assassinButton.down = function () {
+ selectedMode = 'assassin';
+ updateButtonColors();
+};
+engineerButton.down = function () {
+ selectedMode = 'engineer';
+ updateButtonColors();
+};
+mortarButton.down = function () {
+ selectedMode = 'mortar';
+ updateButtonColors();
+};
+shockTrooperButton.down = function () {
+ selectedMode = 'shockTrooper';
+ updateButtonColors();
+};
+trapButton.down = function () {
+ selectedMode = 'trap';
+ updateButtonColors();
+};
// Initialize button colors
updateButtonColors();
function spawnZombie() {
var zombie;
@@ -3863,8 +4609,20 @@
} else if (selectedMode === 'rocketLauncher') {
placeRocketLauncher(gridX, gridY);
} else if (selectedMode === 'shieldGenerator') {
placeShieldGenerator(gridX, gridY);
+ } else if (selectedMode === 'supportMedic') {
+ placeSupportMedic(x, y);
+ } else if (selectedMode === 'assassin') {
+ placeAssassin(x, y);
+ } else if (selectedMode === 'engineer') {
+ placeEngineer(x, y);
+ } else if (selectedMode === 'mortar') {
+ placeMortar(gridX, gridY);
+ } else if (selectedMode === 'shockTrooper') {
+ placeShockTrooper(x, y);
+ } else if (selectedMode === 'trap') {
+ placeTrap(x, y);
}
};
game.update = function () {
// Spawn zombies for current wave
@@ -3968,8 +4726,32 @@
// Update all shield generators (this enables defensive support)
for (var i = 0; i < shieldGenerators.length; i++) {
shieldGenerators[i].update();
}
+ // Update all support medics (this enables healing)
+ for (var i = 0; i < supportMedics.length; i++) {
+ supportMedics[i].update();
+ }
+ // Update all assassins (this enables stealth attacks)
+ for (var i = 0; i < assassins.length; i++) {
+ assassins[i].update();
+ }
+ // Update all engineers (this enables repair mechanics)
+ for (var i = 0; i < engineers.length; i++) {
+ engineers[i].update();
+ }
+ // Update all mortars (this enables artillery strikes)
+ for (var i = 0; i < mortars.length; i++) {
+ mortars[i].update();
+ }
+ // Update all shock troopers (this enables electrical attacks)
+ for (var i = 0; i < shockTroopers.length; i++) {
+ shockTroopers[i].update();
+ }
+ // Update all traps (this enables zombie trapping)
+ for (var i = 0; i < traps.length; i++) {
+ traps[i].update();
+ }
// Update all fire tiles (this enables fire damage)
for (var i = 0; i < fireTiles.length; i++) {
fireTiles[i].update();
}
@@ -4004,9 +4786,15 @@
infoText += 'ELITE SNIPER (100): High damage, long range\n';
infoText += 'HEAVY TANK (120): Armored, high health\n';
infoText += 'LASER TURRET (90): Continuous beam damage\n';
infoText += 'ROCKET LAUNCHER (110): Area damage rockets\n';
- infoText += 'SHIELD GENERATOR (80): Protects nearby troops';
+ infoText += 'SHIELD GENERATOR (80): Protects nearby troops\n';
+ infoText += 'SUPPORT MEDIC (65): Heals nearby troops\n';
+ infoText += 'ASSASSIN (85): Stealth high-damage attacks\n';
+ infoText += 'ENGINEER (70): Repairs structures and tanks\n';
+ infoText += 'MORTAR (130): Long-range artillery strikes\n';
+ infoText += 'SHOCK TROOPER (75): Electrical area damage\n';
+ infoText += 'TRAP (25): Single-use zombie trap';
pauseInfoText.setText(infoText);
pauseInfoText.alpha = 1;
});
// Hide troop information when game is resumed
Citycenter. In-Game asset. 2d. High contrast. No shadows
Un zombie. In-Game asset. 2d. High contrast. No shadows
Una casilla. In-Game asset. 2d. High contrast. No shadows
Toreta. In-Game asset. 2d. High contrast. No shadows
Un cañón. In-Game asset. 2d. High contrast. No shadows
Que tenga bombas
Una bomba. In-Game asset. 2d. High contrast. No shadows
Crea una torreta. In-Game asset. 2d. High contrast. No shadows
Un minero. In-Game asset. 2d. High contrast. No shadows
Un zombie gigante. In-Game asset. 2d. High contrast. No shadows
Fuego. In-Game asset. 2d. High contrast. No shadows
Un congelador. In-Game asset. 2d. High contrast. No shadows
Un zombie con un traje de limpieza. In-Game asset. 2d. High contrast. No shadows
Crea un zombie con un coche. In-Game asset. 2d. High contrast. No shadows
Un tanque. In-Game asset. 2d. High contrast. No shadows
Laserturret. In-Game asset. 2d. High contrast. No shadows
Un misile. In-Game asset. 2d. High contrast. No shadows