User prompt
Ponele al sniper más rango
User prompt
Pone un monton de topas qué sean buenas ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pone un zombie qué ace qué tus topas acen menos daño
User prompt
Crea una tropa qué congela a los zombies con rispirar ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Que los tank zombies aparezcan en más cantidad
User prompt
Que los zombies tengan más vida
User prompt
Crea un zombie qué no puede ser congelado y es rápido ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Crea un zombie qué aga qué los efectos no funcionan conta los zombies
User prompt
Pone el botón del feamethtower al arriba al oeste
User prompt
Pone el botón de el fomet tower arriba de los ortos
User prompt
Una tropa qué quéma a los zombies qué es ten cerca ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Crea una tropa qué espota y quema a todos los zombies ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Crea una tropa qué espota y congela a todos los zombies por 6.8 segundos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Crea una tropa qué espote y deja una casilla con fuego qué ace daño ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Que el wacer zombie tenga más vida
User prompt
Crea un zombie qué ace qué tus topas tengan menos daño
User prompt
Que los zombies especiales aparezcan más temprano
User prompt
Crea una tropa qué cógela a los zombies y las tropas tenen tenpo para usarlo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Crea un zombie qué ase a los zombies más rápidos
User prompt
Crea un zombie qué genera tanks zombies
User prompt
Que los zombies tengan una barra de vida
User prompt
Que los zombies puedan romper las topas
User prompt
Al tank zombie más vida
User prompt
Si al miner lo toca un zombie se tanfoma en un zombie
User prompt
Crea un zombie qué tene mucha vida
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ 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 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 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 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 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 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 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 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 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; // 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); 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 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; } // 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(); }; // 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); } }; 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 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); }; // Start first wave after 3 seconds LK.setTimeout(startNextWave, 3000);
===================================================================
--- original.js
+++ change.js
@@ -96,10 +96,19 @@
var dx = zombie.x - self.x;
var dy = zombie.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= explosionRadius) {
- zombie.takeDamage();
- zombie.takeDamage(); // Bombs do double damage
+ 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);
@@ -133,8 +142,15 @@
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--;
}
@@ -360,10 +376,27 @@
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
- self.target.takeDamage();
+ // 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);
@@ -747,9 +780,18 @@
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
// Hit target with reduced damage
- self.target.takeDamage(self.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);
@@ -1197,8 +1239,15 @@
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--;
}
@@ -1490,8 +1539,15 @@
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--;
}
@@ -1945,8 +2001,15 @@
}
// 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;
}
@@ -1991,8 +2054,201 @@
return self.level * 15;
};
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,
@@ -2779,10 +3035,13 @@
// Initialize button colors
updateButtonColors();
function spawnZombie() {
var zombie;
- // 3% chance to spawn an immunity zombie after wave 3
- if (wave >= 3 && Math.random() < 0.03) {
+ // 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();
@@ -2825,9 +3084,14 @@
zombie.y = Math.random() * 2732;
break;
}
// Increase speed and health with waves
- if (zombie instanceof ImmunityZombie) {
+ 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
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