User prompt
zombiler çiçekleri kırsın
User prompt
bombacı zombi spawn olsun
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function (indicator) {' Line Number: 86
User prompt
bombacı zombi için yeni bir görsel olştur
User prompt
8 9 ve 10. seviyelere bombacı zombı ekle
User prompt
chery bomb dev zombi hariç normal zombilere tek atsın
User prompt
zombiden hasar aldığı zaman ve parçalandığı zaman kırılma sesi ekle
User prompt
ceviz kırılma sesi ekle
User prompt
wallnut zombilerden devamlı hasar alsın ve canı bittiği zaman kırılsın
User prompt
zombi spawnını arttır
User prompt
cherybomb tek atmasın yüzdelik vursun
User prompt
zombilerin canını yükselt
User prompt
zombiler wallnuta geldiği zaman sürekli hasar versin wallnut kırıldığı zaman zombiler devam etsln ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
zombilerin çıkma oranını daha fazla arttır 1.30 dakıka kala
User prompt
zombi spawnı 1.30 dakıka kala fazlalaşsın
User prompt
oyuncu çiçek koymadan saniye başlamasın
User prompt
ilk 3 seviye 2 dakika olsun 4 5 6 2.5 dakika olsun 7 8 9 10 3.5 dakika olsun
User prompt
2.5 dakkaya çıkar
User prompt
her seviye için 2 dakika ver eğer oyuncu 2 dakika dayanabilirse o seviyeyi geçsin
User prompt
zombilerin yürüme hızını azalt
User prompt
wallnutun sağlığını 60 yap
User prompt
cevizin dayanma süresini arttır
User prompt
oyun müziği sesini kıs
/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BomberZombie = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('bomberZombieBody', { anchorX: 0.5, anchorY: 1 }); body.y = 25; var head = self.attachAsset('bomberZombieHead', { anchorX: 0.5, anchorY: 1 }); head.y = -10; // Add explosive belt around waist var belt = self.attachAsset('explosiveBelt', { anchorX: 0.5, anchorY: 0.5 }); belt.x = 0; belt.y = 15; // Add multiple bomb indicators on the belt for (var i = 0; i < 3; i++) { var bombIndicator = self.attachAsset('bombIndicator', { anchorX: 0.5, anchorY: 0.5 }); bombIndicator.x = (i - 1) * 25; // Spread across belt bombIndicator.y = 15; // Add blinking animation to bomb indicators var delay = i * 200; // Stagger the blinking LK.setTimeout(function () { var blinkTimer = LK.setInterval(function () { bombIndicator.alpha = bombIndicator.alpha > 0.5 ? 0.3 : 1.0; }, 800); }, delay); } // Add fuse wire coming from belt var fuse = self.attachAsset('fuseWire', { anchorX: 0.5, anchorY: 1 }); fuse.x = 30; fuse.y = 5; fuse.rotation = Math.PI / 6; // Slight angle // Add sparking effect to fuse tip var fuseTip = self.attachAsset('bombIndicator', { anchorX: 0.5, anchorY: 0.5 }); fuseTip.x = 35; fuseTip.y = -5; fuseTip.scaleX = 0.5; fuseTip.scaleY = 0.5; // Animate fuse tip sparking LK.setInterval(function () { fuseTip.alpha = Math.random() > 0.5 ? 1.0 : 0.2; fuseTip.tint = Math.random() > 0.5 ? 0xFFFF00 : 0xFF4500; }, 300); self.health = 80; // Lower health than regular zombie - easy to kill but dangerous self.speed = 0.4; // Slightly faster than regular zombie self.gridRow = 0; self.isEating = false; self.eatDamage = 8; self.hasAttackedHouse = false; self.hasExploded = false; self.update = function () { // Handle freeze effect if (self.isFrozen && LK.ticks > self.frozenUntil) { self.speed = self.originalSpeed; self.isFrozen = false; // Remove visual freeze effect but keep original orange tint if (self.body) { self.body.tint = 0xFF4500; } if (self.head) { self.head.tint = 0xFF4500; } } if (!self.isEating && !self.hasExploded) { self.x -= self.speed; } // Explode when health drops to 0 or below if (self.health <= 0 && !self.hasExploded) { self.hasExploded = true; // Explosive death - damages plants in 2x2 area around bomber for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; var distance = Math.sqrt(Math.pow(self.x - plant.x, 2) + Math.pow(self.y - plant.y, 2)); if (distance < 150) { // Explosion radius plant.health -= 40; // Significant damage to nearby plants if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); } } } // Flash explosion effect LK.effects.flashScreen(0xFF4500, 500); // Remove self for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } self.destroy(); return; } // Check if reached house if (self.x <= 150 && !self.hasAttackedHouse && !self.hasExploded) { houseHealth -= 20; // Extra damage when reaching house healthText.setText('House Health: ' + houseHealth); self.hasAttackedHouse = true; // Explode at house for extra damage self.hasExploded = true; LK.effects.flashScreen(0xFF4500, 500); self.destroy(); for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } if (houseHealth <= 0) { LK.showGameOver(); } } // Check collision with plants if (!self.hasExploded) { for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 50) { self.isEating = true; // WallNut plants block zombies completely if (plant instanceof WallNut) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 35 ticks while touching WallNut if (LK.ticks - self.lastDamageTime >= 35) { plant.health -= 8; self.lastDamageTime = LK.ticks; } // Zombie cannot move past WallNut until it's destroyed if (plant.health > 0) { // Push zombie back slightly to prevent overlap self.x = plant.x + 55; } } else { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 50 ticks while touching other plants if (LK.ticks - self.lastDamageTime >= 50) { plant.health -= 20; // Bomber zombie destroys plants with explosive damage self.lastDamageTime = LK.ticks; } } if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); self.isEating = false; self.lastDamageTime = undefined; // Reset damage timer when plant is destroyed } break; } } // Reset damage timer when not eating if (!self.isEating) { self.lastDamageTime = undefined; } } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bulletCore', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.damage = 50; self.row = 0; self.update = function () { self.x += self.speed; // Check collision with zombies for (var i = zombies.length - 1; i >= 0; i--) { var zombie = zombies[i]; if (zombie.gridRow === self.row && Math.abs(self.x - zombie.x) < 30) { // Handle ShieldZombie shield mechanics if (zombie instanceof ShieldZombie && zombie.hasShield) { zombie.shieldHealth -= self.damage; // Shield takes damage instead of zombie } else { zombie.health -= self.damage; } if (zombie.health <= 0) { zombie.destroy(); zombies.splice(i, 1); } self.destroy(); for (var j = bullets.length - 1; j >= 0; j--) { if (bullets[j] === self) { bullets.splice(j, 1); break; } } return; } } // Remove if off screen if (self.x > 2048) { self.destroy(); for (var k = bullets.length - 1; k >= 0; k--) { if (bullets[k] === self) { bullets.splice(k, 1); break; } } } }; return self; }); var CherryBomb = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('cherryImage', { anchorX: 0.5, anchorY: 0.5 }); self.health = 50; self.gridRow = 0; self.gridCol = 0; self.fuseTime = 180; // 3 seconds at 60fps self.planted = false; self.update = function () { if (!self.planted) { self.planted = true; self.plantedTick = LK.ticks; } // Check if any zombie is touching the cherry bomb var shouldExplode = false; for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(self.x - zombie.x, 2) + Math.pow(self.y - zombie.y, 2)); if (distance < 50) { // Touch distance - much smaller than explosion radius shouldExplode = true; break; } } // Explode after fuse time OR when touched by zombie if (shouldExplode || LK.ticks - self.plantedTick > self.fuseTime) { LK.getSound('cherybomb').play(); // Play cherrybomb sound when exploding // Deal damage to all zombies in 3x3 area around bomb for (var i = zombies.length - 1; i >= 0; i--) { var zombie = zombies[i]; var distance = Math.sqrt(Math.pow(self.x - zombie.x, 2) + Math.pow(self.y - zombie.y, 2)); if (distance < 200) { // Check zombie type for damage calculation if (zombie instanceof TankZombie) { // Deal 75% percentage damage to tank zombies var damageAmount = Math.floor(zombie.health * 0.75); zombie.health -= damageAmount; } else { // Instantly kill all other zombie types (regular, fast, shield, jumper) zombie.health = 0; } // Destroy zombie if health drops to or below 0 if (zombie.health <= 0) { zombie.destroy(); zombies.splice(i, 1); } } } // Remove self for (var j = plants.length - 1; j >= 0; j--) { if (plants[j] === self) { plants.splice(j, 1); break; } } self.destroy(); } }; return self; }); var DoublePeashooter = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('placedDoublePeaBody', { anchorX: 0.5, anchorY: 0.5 }); var cannon1 = self.attachAsset('peashooterCannon', { anchorX: 0, anchorY: 0.3 }); cannon1.x = 25; cannon1.y = -10; var cannon2 = self.attachAsset('peashooterCannon', { anchorX: 0, anchorY: 0.7 }); cannon2.x = 25; cannon2.y = 10; self.health = 100; self.lastShot = 0; self.shootDelay = 100; // Faster than regular peashooter self.gridRow = 0; self.gridCol = 0; self.shoot = function () { // Shoot two bullets var bullet1 = new Bullet(); bullet1.x = self.x + 50; bullet1.y = self.y - 10; bullet1.row = self.gridRow; bullets.push(bullet1); game.addChild(bullet1); var bullet2 = new Bullet(); bullet2.x = self.x + 50; bullet2.y = self.y + 10; bullet2.row = self.gridRow; bullets.push(bullet2); game.addChild(bullet2); LK.getSound('peasshooter').play(); // Play peashooter sound when shooting }; self.update = function () { if (LK.ticks - self.lastShot > self.shootDelay) { var zombieInRow = false; for (var i = 0; i < zombies.length; i++) { if (zombies[i].gridRow === self.gridRow && zombies[i].x > self.x) { zombieInRow = true; break; } } if (zombieInRow) { self.shoot(); self.lastShot = LK.ticks; } } }; return self; }); var FastZombie = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('zombieBody', { anchorX: 0.5, anchorY: 1 }); body.y = 25; body.tint = 0xFF6666; // Reddish tint to distinguish from regular zombie var head = self.attachAsset('zombieHead', { anchorX: 0.5, anchorY: 1 }); head.y = -10; head.tint = 0xFF6666; // Reddish tint to distinguish from regular zombie self.health = 100; // Lower health than regular zombie self.speed = 0.8; // Faster than regular zombie self.gridRow = 0; self.isEating = false; self.eatDamage = 15; // More damage when eating self.hasAttackedHouse = false; self.update = function () { // Handle freeze effect if (self.isFrozen && LK.ticks > self.frozenUntil) { self.speed = self.originalSpeed; self.isFrozen = false; // Remove visual freeze effect but keep original red tint if (self.body) { self.body.tint = 0xFF6666; } if (self.head) { self.head.tint = 0xFF6666; } } if (!self.isEating) { self.x -= self.speed; } // Check if reached house - zombie damages house once with 15 health if (self.x <= 150 && !self.hasAttackedHouse) { houseHealth -= 15; healthText.setText('House Health: ' + houseHealth); self.hasAttackedHouse = true; // Destroy zombie after attacking house self.destroy(); for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } // Check game over condition if (houseHealth <= 0) { LK.showGameOver(); } } // Check collision with plants for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 50) { self.isEating = true; // WallNut plants block zombies completely if (plant instanceof WallNut) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 25 ticks (faster than regular zombie) while touching WallNut if (LK.ticks - self.lastDamageTime >= 25) { plant.health -= 15; // Fast zombie damages wallnut more self.lastDamageTime = LK.ticks; } // Zombie cannot move past WallNut until it's destroyed if (plant.health > 0) { // Push zombie back slightly to prevent overlap self.x = plant.x + 55; } } else { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 45 ticks while touching other plants if (LK.ticks - self.lastDamageTime >= 45) { plant.health -= 15; // Fast zombie destroys plants quickly self.lastDamageTime = LK.ticks; } } if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); self.isEating = false; self.lastDamageTime = undefined; // Reset damage timer when plant is destroyed } break; } } // Reset damage timer when not eating if (!self.isEating) { self.lastDamageTime = undefined; } }; return self; }); var IceBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('iceBulletCore', { anchorX: 0.5, anchorY: 0.5 }); // Add ice crystal effects around the main bullet for (var i = 0; i < 4; i++) { var crystal = self.attachAsset('iceCrystal', { anchorX: 0.5, anchorY: 0.5 }); var angle = i / 4 * Math.PI * 2; crystal.x = Math.cos(angle) * 8; crystal.y = Math.sin(angle) * 8; crystal.rotation = angle; crystal.scaleX = 0.3; crystal.scaleY = 0.4; crystal.alpha = 0.8; // Add sparkle animation to crystals tween(crystal, { alpha: 0.3 }, { duration: 300, easing: tween.easeInOut }); tween(crystal, { alpha: 0.8 }, { duration: 300, easing: tween.easeInOut }); } self.speed = 6; // Slightly faster than regular bullet self.damage = 40; self.row = 0; self.update = function () { self.x += self.speed; // Check collision with zombies for (var i = zombies.length - 1; i >= 0; i--) { var zombie = zombies[i]; if (zombie.gridRow === self.row && Math.abs(self.x - zombie.x) < 30) { // Handle ShieldZombie shield mechanics if (zombie instanceof ShieldZombie && zombie.hasShield) { zombie.shieldHealth -= self.damage; // Shield takes damage instead of zombie } else { zombie.health -= self.damage; } // Apply freeze effect - slow down zombie for 3 seconds if (!zombie.isFrozen) { zombie.originalSpeed = zombie.speed; zombie.speed = zombie.speed * 0.3; // Slow to 30% speed zombie.isFrozen = true; zombie.frozenUntil = LK.ticks + 180; // 3 seconds at 60fps // Visual freeze effect if (zombie.body) { zombie.body.tint = 0x87CEEB; } if (zombie.head) { zombie.head.tint = 0x87CEEB; } } if (zombie.health <= 0) { zombie.destroy(); zombies.splice(i, 1); } self.destroy(); for (var j = bullets.length - 1; j >= 0; j--) { if (bullets[j] === self) { bullets.splice(j, 1); break; } } return; } } // Remove if off screen if (self.x > 2048) { self.destroy(); for (var k = bullets.length - 1; k >= 0; k--) { if (bullets[k] === self) { bullets.splice(k, 1); break; } } } }; return self; }); var IcePeashooter = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('icePeashooterBody', { anchorX: 0.5, anchorY: 0.5 }); // Add ice crystals around the body for visual effect for (var i = 0; i < 6; i++) { var crystal = self.attachAsset('iceCrystal', { anchorX: 0.5, anchorY: 0.5 }); var angle = i / 6 * Math.PI * 2; crystal.x = Math.cos(angle) * 30; crystal.y = Math.sin(angle) * 30; crystal.rotation = angle; crystal.scaleX = 0.6; crystal.scaleY = 0.8; } var cannon = self.attachAsset('peashooterCannon', { anchorX: 0, anchorY: 0.5 }); cannon.x = 25; cannon.y = 0; cannon.tint = 0x87CEEB; // Light blue tint for ice effect self.health = 100; self.lastShot = 0; self.shootDelay = 120; // Faster than regular peashooter self.gridRow = 0; self.gridCol = 0; self.shoot = function () { var bullet = new IceBullet(); bullet.x = self.x + 50; bullet.y = self.y; bullet.row = self.gridRow; bullets.push(bullet); game.addChild(bullet); LK.getSound('peasshooter').play(); // Play peashooter sound when shooting }; self.update = function () { if (LK.ticks - self.lastShot > self.shootDelay) { // Check if there's a zombie in this row var zombieInRow = false; for (var i = 0; i < zombies.length; i++) { if (zombies[i].gridRow === self.gridRow && zombies[i].x > self.x) { zombieInRow = true; break; } } if (zombieInRow) { self.shoot(); self.lastShot = LK.ticks; } } }; return self; }); var JumperZombie = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('zombieBody', { anchorX: 0.5, anchorY: 1 }); body.y = 25; body.tint = 0x00FF00; // Green tint for jumper zombie var head = self.attachAsset('zombieHead', { anchorX: 0.5, anchorY: 1 }); head.y = -10; head.tint = 0x00FF00; self.health = 120; self.speed = 0.5; self.gridRow = 0; self.isEating = false; self.eatDamage = 12; self.hasAttackedHouse = false; self.canJump = true; self.update = function () { // Handle freeze effect if (self.isFrozen && LK.ticks > self.frozenUntil) { self.speed = self.originalSpeed; self.isFrozen = false; // Remove visual freeze effect but keep original green tint if (self.body) { self.body.tint = 0x00FF00; } if (self.head) { self.head.tint = 0x00FF00; } } if (!self.isEating) { self.x -= self.speed; } // Jump over first plant encountered if (self.canJump) { for (var i = 0; i < plants.length; i++) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 80 && self.x > plant.x) { self.x = plant.x - 80; // Jump past the plant self.canJump = false; break; } } } // Check if reached house if (self.x <= 150 && !self.hasAttackedHouse) { houseHealth -= 12; healthText.setText('House Health: ' + houseHealth); self.hasAttackedHouse = true; self.destroy(); for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } if (houseHealth <= 0) { LK.showGameOver(); } } // Check collision with plants (only if can't jump) if (!self.canJump) { for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 50) { self.isEating = true; // WallNut plants block zombies completely if (plant instanceof WallNut) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 30 ticks while touching WallNut if (LK.ticks - self.lastDamageTime >= 30) { plant.health -= 12; // Jumper zombie damages wallnut self.lastDamageTime = LK.ticks; } // Zombie cannot move past WallNut until it's destroyed if (plant.health > 0) { // Push zombie back slightly to prevent overlap self.x = plant.x + 55; } } else { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 60 ticks while touching other plants if (LK.ticks - self.lastDamageTime >= 60) { plant.health -= 15; // Jumper zombie destroys plants with high damage self.lastDamageTime = LK.ticks; } } if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); self.isEating = false; self.lastDamageTime = undefined; // Reset damage timer when plant is destroyed } break; } } // Reset damage timer when not eating if (!self.isEating && !self.canJump) { self.lastDamageTime = undefined; } } }; return self; }); // Event handlers var LevelButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('levelButton', { anchorX: 0.5, anchorY: 0.5 }); self.levelNumber = 1; self.setLevelNumber = function (number) { self.levelNumber = number; self.levelText.setText(number.toString()); }; self.isUnlocked = true; self.stars = 0; self.maxStars = 3; // Create level number text self.levelText = new Text2(self.levelNumber.toString(), { size: 50, fill: 0xFFFFFF }); self.levelText.anchor.set(0.5, 0.5); self.levelText.y = -30; self.addChild(self.levelText); // Create stars display self.starContainers = []; for (var i = 0; i < self.maxStars; i++) { var star = LK.getAsset('starShape', { anchorX: 0.5, anchorY: 0.5 }); star.x = (i - 1) * 50; star.y = 30; star.tint = 0x666666; // Dark by default self.addChild(star); self.starContainers.push(star); } self.setStars = function (starCount) { self.stars = starCount; for (var i = 0; i < self.maxStars; i++) { if (i < starCount) { self.starContainers[i].tint = 0xFFD700; // Golden } else { self.starContainers[i].tint = 0x666666; // Dark } } }; self.setUnlocked = function (unlocked) { self.isUnlocked = unlocked; if (unlocked) { buttonBg.tint = 0xFFFFFF; self.levelText.tint = 0xFFFFFF; } else { buttonBg.tint = 0x666666; self.levelText.tint = 0x666666; } }; self.down = function (x, y, obj) { if (self.isUnlocked) { LK.getSound('buttonClick').play(); // Start the selected level startLevel(self.levelNumber); } else { // Play a different sound or show feedback for locked levels console.log('Level ' + self.levelNumber + ' is locked. Complete previous levels first.'); } }; return self; }); // Plant classes var Peashooter = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('peashooterBody', { anchorX: 0.5, anchorY: 0.5 }); var cannon = self.attachAsset('peashooterCannon', { anchorX: 0, anchorY: 0.5 }); cannon.x = 25; cannon.y = 0; self.health = 100; self.lastShot = 0; self.shootDelay = 150; // 2.5 seconds at 60fps self.gridRow = 0; self.gridCol = 0; self.shoot = function () { var bullet = new Bullet(); bullet.x = self.x + 50; bullet.y = self.y; bullet.row = self.gridRow; bullets.push(bullet); game.addChild(bullet); LK.getSound('peasshooter').play(); // Play peashooter sound when shooting }; self.update = function () { if (LK.ticks - self.lastShot > self.shootDelay) { // Check if there's a zombie in this row var zombieInRow = false; for (var i = 0; i < zombies.length; i++) { if (zombies[i].gridRow === self.gridRow && zombies[i].x > self.x) { zombieInRow = true; break; } } if (zombieInRow) { self.shoot(); self.lastShot = LK.ticks; } } }; return self; }); var ShieldZombie = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('zombieBody', { anchorX: 0.5, anchorY: 1 }); body.y = 25; body.tint = 0x8B4513; // Brown tint for shield zombie var head = self.attachAsset('zombieHead', { anchorX: 0.5, anchorY: 1 }); head.y = -10; head.tint = 0x8B4513; // Create shield visual with rim, main body, and center decoration var shieldRim = self.attachAsset('shieldRim', { anchorX: 0.5, anchorY: 0.5 }); shieldRim.x = 25; // Position shield in front of zombie shieldRim.y = 0; var shield = self.attachAsset('shieldVisual', { anchorX: 0.5, anchorY: 0.5 }); shield.x = 25; // Position shield in front of zombie shield.y = 0; var shieldCenter = self.attachAsset('shieldCenter', { anchorX: 0.5, anchorY: 0.5 }); shieldCenter.x = 25; // Position shield center decoration shieldCenter.y = 0; self.health = 150; // Zombie health (only takes damage after shield is destroyed) self.shieldHealth = 150; // Shield health (must be destroyed first) self.speed = 0.25; // Slower than regular zombie due to shield weight self.gridRow = 0; self.isEating = false; self.eatDamage = 12; self.hasAttackedHouse = false; self.hasShield = true; // Track if shield is still active self.update = function () { // Handle freeze effect if (self.isFrozen && LK.ticks > self.frozenUntil) { self.speed = self.originalSpeed; self.isFrozen = false; // Remove visual freeze effect but keep original brown tint if (self.body) { self.body.tint = 0x8B4513; } if (self.head) { self.head.tint = 0x8B4513; } } if (!self.isEating) { self.x -= self.speed; } // Check if shield is destroyed if (self.hasShield && self.shieldHealth <= 0) { self.hasShield = false; shield.destroy(); // Remove shield visual shieldRim.destroy(); // Remove shield rim shieldCenter.destroy(); // Remove shield center decoration self.speed = 0.4; // Increase speed when shield is lost } // Check if reached house if (self.x <= 150 && !self.hasAttackedHouse) { houseHealth -= 12; healthText.setText('House Health: ' + houseHealth); self.hasAttackedHouse = true; self.destroy(); for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } if (houseHealth <= 0) { LK.showGameOver(); } } // Check collision with plants for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 50) { self.isEating = true; // WallNut plants block zombies completely if (plant instanceof WallNut) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 30 ticks while touching WallNut if (LK.ticks - self.lastDamageTime >= 30) { plant.health -= 12; self.lastDamageTime = LK.ticks; } // Zombie cannot move past WallNut until it's destroyed if (plant.health > 0) { // Push zombie back slightly to prevent overlap self.x = plant.x + 55; } } else { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 60 ticks while touching other plants if (LK.ticks - self.lastDamageTime >= 60) { plant.health -= 12; // Shield zombie destroys plants with moderate damage self.lastDamageTime = LK.ticks; } } if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); self.isEating = false; self.lastDamageTime = undefined; // Reset damage timer when plant is destroyed } break; } } // Reset damage timer when not eating if (!self.isEating) { self.lastDamageTime = undefined; } }; return self; }); var Sunflower = Container.expand(function () { var self = Container.call(this); // Create petals around center for (var i = 0; i < 8; i++) { var petal = self.attachAsset('sunflowerPetal', { anchorX: 0.5, anchorY: 1 }); var angle = i / 8 * Math.PI * 2; petal.x = Math.cos(angle) * 25; petal.y = Math.sin(angle) * 25; petal.rotation = angle + Math.PI / 2; } var center = self.attachAsset('sunflowerCenter', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.lastSunGeneration = 0; self.sunDelay = 300; // 5 seconds at 60fps self.gridRow = 0; self.gridCol = 0; self.generateSun = function () { sun += 25; sunText.setText('Sun: ' + sun); self.lastSunGeneration = LK.ticks; }; self.update = function () { if (LK.ticks - self.lastSunGeneration > self.sunDelay) { self.generateSun(); } }; return self; }); var TankZombie = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('zombieBody', { anchorX: 0.5, anchorY: 1 }); body.y = 25; body.tint = 0x333333; // Dark gray tint for tank zombie body.scaleX = 1.5; body.scaleY = 1.5; var head = self.attachAsset('zombieHead', { anchorX: 0.5, anchorY: 1 }); head.y = -15; head.tint = 0x333333; head.scaleX = 1.5; head.scaleY = 1.5; self.health = 450; // Very high health self.speed = 0.2; // Very slow self.gridRow = 0; self.isEating = false; self.eatDamage = 20; self.hasAttackedHouse = false; self.update = function () { // Handle freeze effect if (self.isFrozen && LK.ticks > self.frozenUntil) { self.speed = self.originalSpeed; self.isFrozen = false; // Remove visual freeze effect but keep original dark gray tint if (self.body) { self.body.tint = 0x333333; } if (self.head) { self.head.tint = 0x333333; } } if (!self.isEating) { self.x -= self.speed; } // Check if reached house if (self.x <= 150 && !self.hasAttackedHouse) { houseHealth -= 25; healthText.setText('House Health: ' + houseHealth); self.hasAttackedHouse = true; self.destroy(); for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } if (houseHealth <= 0) { LK.showGameOver(); } } // Check collision with plants for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 50) { self.isEating = true; // WallNut plants block zombies completely if (plant instanceof WallNut) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 40 ticks (slower but high damage) while touching WallNut if (LK.ticks - self.lastDamageTime >= 40) { plant.health -= 20; // Tank zombie destroys wallnut with high damage self.lastDamageTime = LK.ticks; } // Zombie cannot move past WallNut until it's destroyed if (plant.health > 0) { // Push zombie back slightly to prevent overlap self.x = plant.x + 55; } } else { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 70 ticks while touching other plants if (LK.ticks - self.lastDamageTime >= 70) { plant.health -= 25; // Tank zombie destroys plants with massive damage self.lastDamageTime = LK.ticks; } } if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); self.isEating = false; self.lastDamageTime = undefined; // Reset damage timer when plant is destroyed } break; } } // Reset damage timer when not eating if (!self.isEating) { self.lastDamageTime = undefined; } }; return self; }); var WallNut = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('placedWallNutBody', { anchorX: 0.5, anchorY: 0.5 }); body.scaleX = 1.3; body.scaleY = 1.3; self.health = 60; // Increased health, breaks after 6 zombie hits self.gridRow = 0; self.gridCol = 0; self.update = function () { // Check if being touched by any zombie and take continuous damage for (var i = 0; i < zombies.length; i++) { var zombie = zombies[i]; if (zombie.gridRow === self.gridRow && Math.abs(zombie.x - self.x) < 50) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Take damage every 30 ticks (0.5 seconds) from any zombie type if (LK.ticks - self.lastDamageTime >= 30) { var damageAmount = 10; // Base damage from regular zombies if (zombie instanceof FastZombie) { damageAmount = 15; } else if (zombie instanceof TankZombie) { damageAmount = 20; } else if (zombie instanceof ShieldZombie) { damageAmount = 12; } else if (zombie instanceof JumperZombie) { damageAmount = 12; } self.health -= damageAmount; self.lastDamageTime = LK.ticks; } break; // Only take damage from one zombie at a time } } // Reset damage timer when no zombies are touching var anyZombieTouching = false; for (var j = 0; j < zombies.length; j++) { var zombie = zombies[j]; if (zombie.gridRow === self.gridRow && Math.abs(zombie.x - self.x) < 50) { anyZombieTouching = true; break; } } if (!anyZombieTouching) { self.lastDamageTime = undefined; } // Check if health decreased to play breaking sound if (self.lastHealth === undefined) { self.lastHealth = self.health; } if (self.lastHealth > self.health) { LK.getSound('ceviz').play(); // Play walnut breaking sound when damaged } self.lastHealth = self.health; // Check if wallnut is destroyed if (self.health <= 0) { // Play walnut breaking sound when completely destroyed LK.getSound('ceviz').play(); // Remove from plants array and destroy for (var k = plants.length - 1; k >= 0; k--) { if (plants[k] === self) { plants.splice(k, 1); break; } } self.destroy(); } }; return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('zombieBody', { anchorX: 0.5, anchorY: 1 }); body.y = 25; var head = self.attachAsset('zombieHead', { anchorX: 0.5, anchorY: 1 }); head.y = -10; self.health = 150; self.speed = 0.3; self.gridRow = 0; self.isEating = false; self.eatDamage = 10; self.hasAttackedHouse = false; self.update = function () { // Handle freeze effect if (self.isFrozen && LK.ticks > self.frozenUntil) { self.speed = self.originalSpeed; self.isFrozen = false; // Remove visual freeze effect if (self.body) { self.body.tint = 0xFFFFFF; } if (self.head) { self.head.tint = 0xFFFFFF; } } if (!self.isEating) { self.x -= self.speed; } // Check if reached house - zombie damages house once with 10 health if (self.x <= 150 && !self.hasAttackedHouse) { houseHealth -= 10; healthText.setText('House Health: ' + houseHealth); self.hasAttackedHouse = true; // Destroy zombie after attacking house self.destroy(); for (var z = zombies.length - 1; z >= 0; z--) { if (zombies[z] === self) { zombies.splice(z, 1); break; } } // Check game over condition if (houseHealth <= 0) { LK.showGameOver(); } } // Check collision with plants for (var i = plants.length - 1; i >= 0; i--) { var plant = plants[i]; if (plant.gridRow === self.gridRow && Math.abs(self.x - plant.x) < 50) { self.isEating = true; // WallNut plants block zombies completely if (plant instanceof WallNut) { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 30 ticks (0.5 seconds) while touching WallNut if (LK.ticks - self.lastDamageTime >= 30) { plant.health -= 10; // Continuous damage to wallnut self.lastDamageTime = LK.ticks; } // Zombie cannot move past WallNut until it's destroyed if (plant.health > 0) { // Push zombie back slightly to prevent overlap self.x = plant.x + 55; } } else { // Initialize damage timer if not set if (self.lastDamageTime === undefined) { self.lastDamageTime = LK.ticks; } // Deal damage every 60 ticks (1 second) while touching other plants if (LK.ticks - self.lastDamageTime >= 60) { plant.health -= 10; // Increased damage to destroy plants faster self.lastDamageTime = LK.ticks; } } if (plant.health <= 0) { plant.destroy(); plants.splice(i, 1); self.isEating = false; self.lastDamageTime = undefined; // Reset damage timer when plant is destroyed } break; } } // Reset damage timer when not eating if (!self.isEating) { self.lastDamageTime = undefined; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x5D4E37 // Darker brown paper background color }); /**** * Game Code ****/ // Level selection screen variables // Import storage for persistent level progression var levelButtons = []; var totalLevels = 10; var unlockedLevels = storage.unlockedLevels || 1; // Load from storage or default to 1 var levelProgress = storage.levelProgress || {}; // Load from storage or default to empty // Global game variables var plants = []; var zombies = []; var bullets = []; var sun = 150; var sunText; var houseHealth; var healthText; // Music control variables var isMusicOn = storage.isMusicOn !== undefined ? storage.isMusicOn : true; // Default music on var musicButton; // Create brown paper background var background = LK.getAsset('paperBackground', { anchorX: 0, anchorY: 0 }); game.addChild(background); // Create title var titleBg = LK.getAsset('titleBackground', { anchorX: 0.5, anchorY: 0.5 }); titleBg.x = 1024; titleBg.y = 300; game.addChild(titleBg); // Create level buttons in a grid layout var buttonsPerRow = 5; var buttonSpacingX = 350; var buttonSpacingY = 250; var startX = 400; var startY = 700; for (var i = 0; i < totalLevels; i++) { var levelButton = new LevelButton(); levelButton.setLevelNumber(i + 1); // Calculate position in grid var row = Math.floor(i / buttonsPerRow); var col = i % buttonsPerRow; levelButton.x = startX + col * buttonSpacingX; levelButton.y = startY + row * buttonSpacingY; // Set unlock status - only unlock levels up to the player's progress levelButton.setUnlocked(i < unlockedLevels); // Set stars from progress (if any) if (levelProgress[i + 1]) { levelButton.setStars(levelProgress[i + 1]); } else { levelButton.setStars(0); } levelButtons.push(levelButton); game.addChild(levelButton); } // Create music toggle button with new design musicButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5 }); musicButton.x = 1700; musicButton.y = 200; musicButton.scaleX = 0.5; musicButton.scaleY = 0.5; musicButton.tint = isMusicOn ? 0x4CAF50 : 0xF44336; game.addChild(musicButton); // Add music icon symbol var musicIcon = new Text2(isMusicOn ? '♪' : '♪', { size: 50, fill: 0xFFFFFF }); musicIcon.anchor.set(0.5, 0.5); musicIcon.x = 1700; musicIcon.y = 185; musicIcon.alpha = isMusicOn ? 1.0 : 0.3; game.addChild(musicIcon); // Add music status text var musicText = new Text2(isMusicOn ? 'ON' : 'OFF', { size: 24, fill: 0xFFFFFF }); musicText.anchor.set(0.5, 0.5); musicText.x = 1700; musicText.y = 215; game.addChild(musicText); // Music button event handler musicButton.down = function () { LK.getSound('buttonClick').play(); isMusicOn = !isMusicOn; storage.isMusicOn = isMusicOn; // Save to storage musicButton.tint = isMusicOn ? 0x4CAF50 : 0xF44336; musicIcon.alpha = isMusicOn ? 1.0 : 0.3; musicText.setText(isMusicOn ? 'ON' : 'OFF'); if (isMusicOn) { // Resume music if we're in a level if (currentLevel > 0) { LK.playMusic('game'); } } else { LK.stopMusic(); } }; // Function to start a level function startLevel(levelNumber) { LK.getSound('levelSelect').play(); console.log('Starting level: ' + levelNumber); // Set current level for pause functionality currentLevel = levelNumber; // Clear the level selection screen game.removeChildren(); // Initialize the appropriate level if (levelNumber === 1) { initializeLevel1(); } else if (levelNumber === 2) { initializeLevel2(); } else if (levelNumber >= 3 && levelNumber <= 10) { // Initialize dynamic levels for 3-10 initializeDynamicLevel(levelNumber); } } // Initialize Level 1 Plants vs Zombies game function initializeLevel1() { // Start playing game music only if music is enabled if (isMusicOn) { LK.playMusic('game'); } // Game variables houseHealth = 100; sun = 150; // Starting money for level 1 plants = []; // Make plants global zombies = []; // Make zombies global bullets = []; // Make bullets global var sunflowers = []; var lastSunGeneration = 0; var lastZombieSpawn = 0; var levelStartTime = null; // Track when level started - will be set when first plant is placed var levelDuration = 7200; // 2 minutes at 60fps (120 seconds * 60 = 7200 ticks) // Grid setup var gridRows = 10; var gridCols = 12; var gridCellWidth = 180; var gridCellHeight = 120; var gridStartX = 200; var gridStartY = 500; // UI elements sunText = new Text2('Sun: ' + sun, { size: 40, fill: 0x000000 }); sunText.x = 1500; sunText.y = 50; game.addChild(sunText); healthText = new Text2('House Health: ' + houseHealth, { size: 40, fill: 0xFF0000 }); healthText.x = 1500; healthText.y = 100; game.addChild(healthText); // Add timer display var timerText = new Text2('Time: 2:00', { size: 40, fill: 0x0000FF }); timerText.x = 1500; timerText.y = 200; game.addChild(timerText); // Create grid for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { var gridCell = LK.getAsset('gridTile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.75, scaleY: 0.75 }); gridCell.x = gridStartX + col * gridCellWidth; gridCell.y = gridStartY + row * gridCellHeight; gridCell.alpha = 0.8; gridCell.tint = 0x8B7355; game.addChild(gridCell); } } // Plant selection buttons with proper spacing var peashooterButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); peashooterButton.x = 400; peashooterButton.y = 1800; peashooterButton.tint = 0x006400; game.addChild(peashooterButton); // Add peashooter image to button var peashooterImage = LK.getAsset('peashooterBody', { anchorX: 0.5, anchorY: 0.5 }); peashooterImage.x = 400; peashooterImage.y = 1780; peashooterImage.scaleX = 1.0; peashooterImage.scaleY = 1.0; game.addChild(peashooterImage); var peashooterCost = 50 + Math.max(0, 1 - 5) * 5; // Level 1 cost: 50, same for levels 1-5 var peashooterText = new Text2(peashooterCost + ' Sun', { size: 32, fill: 0xFFFFFF }); peashooterText.anchor.set(0.5, 0.5); peashooterText.x = 400; peashooterText.y = 1830; game.addChild(peashooterText); var sunflowerButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); sunflowerButton.x = 1000; sunflowerButton.y = 1800; sunflowerButton.tint = 0xB8860B; game.addChild(sunflowerButton); // Add sunflower image to button var sunflowerImage = LK.getAsset('sunflowerCenter', { anchorX: 0.5, anchorY: 0.5 }); sunflowerImage.x = 1000; sunflowerImage.y = 1780; sunflowerImage.scaleX = 0.75; sunflowerImage.scaleY = 0.75; game.addChild(sunflowerImage); var sunflowerCost = 50 + Math.max(0, 1 - 5) * 5; // Level 1 cost: 50, same for levels 1-5 var sunflowerText = new Text2(sunflowerCost + ' Sun', { size: 32, fill: 0xFFFFFF }); sunflowerText.anchor.set(0.5, 0.5); sunflowerText.x = 1000; sunflowerText.y = 1830; game.addChild(sunflowerText); var selectedPlant = null; // Event handlers peashooterButton.down = function () { if (sun >= peashooterCost) { selectedPlant = 'peashooter'; } }; sunflowerButton.down = function () { if (sun >= sunflowerCost) { selectedPlant = 'sunflower'; } }; game.down = function (x, y, obj) { if (selectedPlant && x >= gridStartX && x <= gridStartX + gridCols * gridCellWidth && y >= gridStartY && y <= gridStartY + gridRows * gridCellHeight) { var gridCol = Math.floor((x - gridStartX) / gridCellWidth); var gridRow = Math.floor((y - gridStartY) / gridCellHeight); // Check if position is valid and empty var positionEmpty = true; for (var i = 0; i < plants.length; i++) { if (plants[i].gridRow === gridRow && plants[i].gridCol === gridCol) { positionEmpty = false; break; } } if (positionEmpty && gridCol >= 0 && gridCol < gridCols && gridRow >= 0 && gridRow < gridRows) { var plant = null; if (selectedPlant === 'peashooter' && sun >= peashooterCost) { plant = new Peashooter(); sun -= peashooterCost; } else if (selectedPlant === 'sunflower' && sun >= sunflowerCost) { plant = new Sunflower(); sun -= sunflowerCost; } if (plant) { plant.x = gridStartX + gridCol * gridCellWidth; plant.y = gridStartY + gridRow * gridCellHeight; plant.gridRow = gridRow; plant.gridCol = gridCol; plants.push(plant); game.addChild(plant); sunText.setText('Sun: ' + sun); selectedPlant = null; } } } }; var zombiesStarted = false; // Track if zombies have started spawning // Game update function game.update = function () { // Start zombie spawning and timer only after first plant is placed if (!zombiesStarted && plants.length > 0) { zombiesStarted = true; levelStartTime = LK.ticks; // Start level timer when first plant is placed lastZombieSpawn = LK.ticks; // Initialize spawn timer } // Spawn zombies only after they have been started - progressive spawn rate // Start slow and gradually increase spawn rate over time var gameProgress = Math.min(LK.ticks / 3600, 1); // Progress from 0 to 1 over 60 seconds var currentSpawnRate = 180 - gameProgress * 120; // Start at 180 (3 seconds), end at 60 (1 second) if (zombiesStarted && LK.ticks - lastZombieSpawn > currentSpawnRate) { var zombie = new Zombie(); var row = Math.floor(Math.random() * gridRows); zombie.x = 1900; zombie.y = gridStartY + row * gridCellHeight; zombie.gridRow = row; zombies.push(zombie); game.addChild(zombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastZombieSpawn = LK.ticks; } // Update all game objects for (var i = plants.length - 1; i >= 0; i--) { plants[i].update(); } for (var j = zombies.length - 1; j >= 0; j--) { zombies[j].update(); } for (var k = bullets.length - 1; k >= 0; k--) { bullets[k].update(); } // Generate sun from sunflowers - only if sunflowers exist var sunflowerCount = 0; for (var s = 0; s < plants.length; s++) { if (plants[s] instanceof Sunflower) { sunflowerCount++; } } if (sunflowerCount > 0 && LK.ticks - lastSunGeneration > 600) { // Every 10 seconds, only if sunflowers exist sun += 10; sunText.setText('Sun: ' + sun); lastSunGeneration = LK.ticks; } // Increased spawn when 1.5 minutes (90 seconds = 5400 ticks) remain - starts at 1.5 minutes left var timeElapsed = levelStartTime ? LK.ticks - levelStartTime : 0; var timeRemaining = Math.max(0, levelDuration - timeElapsed); if (timeRemaining <= 5400) { // 1.5 minutes = 90 seconds = 5400 ticks var intensifiedSpawnRate = 30 - (5400 - timeRemaining) / 5400 * 20; // Start at 30 (0.5 seconds), end at 10 (0.17 seconds) if (LK.ticks - lastZombieSpawn > intensifiedSpawnRate) { var zombie = new Zombie(); var row = Math.floor(Math.random() * gridRows); zombie.x = 1900; zombie.y = gridStartY + row * gridCellHeight; zombie.gridRow = row; zombies.push(zombie); game.addChild(zombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastZombieSpawn = LK.ticks; } } // Update timer display var timeElapsed = levelStartTime ? LK.ticks - levelStartTime : 0; var timeRemaining = Math.max(0, levelDuration - timeElapsed); var minutes = Math.floor(timeRemaining / 3600); var seconds = Math.floor(timeRemaining % 3600 / 60); var timeString = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; timerText.setText('Time: ' + timeString); // Check win condition - survive for 2 minutes if (levelStartTime && timeElapsed >= levelDuration) { // Player survived 2 minutes - they win! unlockNextLevel(); // Unlock next level when current level is completed // Calculate stars based on house health: 3 stars = 80+%, 2 stars = 50+%, 1 star = any health remaining var stars = 1; if (houseHealth >= 80) { stars = 3; } else if (houseHealth >= 50) { stars = 2; } setLevelStars(1, stars); LK.showYouWin(); } }; } // Initialize Level 2 Plants vs Zombies game with more zombies and fast zombies function initializeLevel2() { // Start playing game music only if music is enabled if (isMusicOn) { LK.playMusic('game'); } // Game variables houseHealth = 100; sun = 200; // Starting money for level 2 (50 more than level 1) plants = []; // Make plants global zombies = []; // Make zombies global bullets = []; // Make bullets global var levelStartTime = null; // Track when level started - will be set when first plant is placed var levelDuration = 7200; // 2 minutes at 60fps (120 seconds * 60 = 7200 ticks) // Night theme background var nightBg = LK.getAsset('nightBackground', { anchorX: 0, anchorY: 0 }); game.addChild(nightBg); var sunflowers = []; var lastSunGeneration = 0; var lastZombieSpawn = 0; var lastFastZombieSpawn = 0; // Grid setup var gridRows = 10; var gridCols = 12; var gridCellWidth = 180; var gridCellHeight = 120; var gridStartX = 200; var gridStartY = 500; // UI elements sunText = new Text2('Sun: ' + sun, { size: 40, fill: 0x000000 }); sunText.x = 1500; sunText.y = 50; game.addChild(sunText); healthText = new Text2('House Health: ' + houseHealth, { size: 40, fill: 0xFF0000 }); healthText.x = 1500; healthText.y = 100; game.addChild(healthText); // Level indicator var levelText = new Text2('Level 2', { size: 50, fill: 0xFFFFFF }); levelText.x = 1500; levelText.y = 150; game.addChild(levelText); // Add timer display var timerText = new Text2('Time: 2:00', { size: 40, fill: 0x0000FF }); timerText.x = 1500; timerText.y = 200; game.addChild(timerText); // Create grid for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { var gridCell = LK.getAsset('gridTile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.75, scaleY: 0.75 }); gridCell.x = gridStartX + col * gridCellWidth; gridCell.y = gridStartY + row * gridCellHeight; gridCell.alpha = 0.9; gridCell.tint = 0x1A0D33; game.addChild(gridCell); } } // Plant selection buttons with proper spacing var peashooterButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); peashooterButton.x = 350; peashooterButton.y = 1800; peashooterButton.tint = 0x006400; game.addChild(peashooterButton); // Add peashooter image to button var peashooterImage = LK.getAsset('peashooterBody', { anchorX: 0.5, anchorY: 0.5 }); peashooterImage.x = 350; peashooterImage.y = 1780; peashooterImage.scaleX = 1.0; peashooterImage.scaleY = 1.0; game.addChild(peashooterImage); var peashooterCost = 50 + Math.max(0, 2 - 5) * 5; // Level 2 cost: 50, same for levels 1-5 var peashooterText = new Text2(peashooterCost + ' Sun', { size: 32, fill: 0xFFFFFF }); peashooterText.anchor.set(0.5, 0.5); peashooterText.x = 350; peashooterText.y = 1830; game.addChild(peashooterText); var sunflowerButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); sunflowerButton.x = 800; sunflowerButton.y = 1800; sunflowerButton.tint = 0xB8860B; game.addChild(sunflowerButton); // Add sunflower image to button var sunflowerImage = LK.getAsset('sunflowerCenter', { anchorX: 0.5, anchorY: 0.5 }); sunflowerImage.x = 800; sunflowerImage.y = 1780; sunflowerImage.scaleX = 0.75; sunflowerImage.scaleY = 0.75; game.addChild(sunflowerImage); var sunflowerCost = 50 + Math.max(0, 2 - 5) * 5; // Level 2 cost: 50, same for levels 1-5 var sunflowerText = new Text2(sunflowerCost + ' Sun', { size: 32, fill: 0xFFFFFF }); sunflowerText.anchor.set(0.5, 0.5); sunflowerText.x = 800; sunflowerText.y = 1830; game.addChild(sunflowerText); var selectedPlant = null; // Add CherryBomb button for level 2 var cherrybombButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); cherrybombButton.x = 1250; cherrybombButton.y = 1800; cherrybombButton.tint = 0xFF0000; game.addChild(cherrybombButton); var cherrybombImage = LK.getAsset('cherryImage', { anchorX: 0.5, anchorY: 0.5 }); cherrybombImage.x = 1250; cherrybombImage.y = 1780; cherrybombImage.scaleX = 0.75; cherrybombImage.scaleY = 0.75; game.addChild(cherrybombImage); var cherrybombCost = 100 + Math.max(0, 2 - 5) * 10; // Level 2 cost: 100, same for levels 1-5 var cherrybombText = new Text2(cherrybombCost + ' Sun', { size: 32, fill: 0xFFFFFF }); cherrybombText.anchor.set(0.5, 0.5); cherrybombText.x = 1250; cherrybombText.y = 1830; game.addChild(cherrybombText); cherrybombButton.down = function () { if (sun >= cherrybombCost) { selectedPlant = 'cherrybomb'; } }; // Event handlers peashooterButton.down = function () { if (sun >= peashooterCost) { selectedPlant = 'peashooter'; } }; sunflowerButton.down = function () { if (sun >= sunflowerCost) { selectedPlant = 'sunflower'; } }; game.down = function (x, y, obj) { if (selectedPlant && x >= gridStartX && x <= gridStartX + gridCols * gridCellWidth && y >= gridStartY && y <= gridStartY + gridRows * gridCellHeight) { var gridCol = Math.floor((x - gridStartX) / gridCellWidth); var gridRow = Math.floor((y - gridStartY) / gridCellHeight); // Check if position is valid and empty var positionEmpty = true; for (var i = 0; i < plants.length; i++) { if (plants[i].gridRow === gridRow && plants[i].gridCol === gridCol) { positionEmpty = false; break; } } if (positionEmpty && gridCol >= 0 && gridCol < gridCols && gridRow >= 0 && gridRow < gridRows) { var plant = null; if (selectedPlant === 'peashooter' && sun >= peashooterCost) { plant = new Peashooter(); sun -= peashooterCost; } else if (selectedPlant === 'sunflower' && sun >= sunflowerCost) { plant = new Sunflower(); sun -= sunflowerCost; } else if (selectedPlant === 'cherrybomb' && sun >= cherrybombCost) { plant = new CherryBomb(); sun -= cherrybombCost; } if (plant) { plant.x = gridStartX + gridCol * gridCellWidth; plant.y = gridStartY + gridRow * gridCellHeight; plant.gridRow = gridRow; plant.gridCol = gridCol; plants.push(plant); game.addChild(plant); sunText.setText('Sun: ' + sun); selectedPlant = null; } } } }; var zombiesStarted = false; // Track if zombies have started spawning // Game update function for Level 2 game.update = function () { // Start zombie spawning and timer only after first plant is placed if (!zombiesStarted && plants.length > 0) { zombiesStarted = true; levelStartTime = LK.ticks; // Start level timer when first plant is placed lastZombieSpawn = LK.ticks; // Initialize spawn timer lastFastZombieSpawn = LK.ticks; // Initialize fast zombie spawn timer } // Spawn regular zombies with progressive spawn rate - only after zombies started var gameProgress = Math.min(LK.ticks / 5400, 1); // Progress from 0 to 1 over 90 seconds var currentSpawnRate = 120 - gameProgress * 80; // Start at 120 (2 seconds), end at 40 (0.67 seconds) if (zombiesStarted && LK.ticks - lastZombieSpawn > currentSpawnRate) { var zombie = new Zombie(); var row = Math.floor(Math.random() * gridRows); zombie.x = 1900; zombie.y = gridStartY + row * gridCellHeight; zombie.gridRow = row; zombies.push(zombie); game.addChild(zombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastZombieSpawn = LK.ticks; } // Spawn fast zombies with progressive spawn rate - only after zombies started var fastSpawnRate = 180 - gameProgress * 120; // Start at 180 (3 seconds), end at 60 (1 second) if (zombiesStarted && LK.ticks - lastFastZombieSpawn > fastSpawnRate) { var fastZombie = new FastZombie(); var row = Math.floor(Math.random() * gridRows); fastZombie.x = 1900; fastZombie.y = gridStartY + row * gridCellHeight; fastZombie.gridRow = row; zombies.push(fastZombie); game.addChild(fastZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastFastZombieSpawn = LK.ticks; } // Spawn tank zombies with progressive spawn rate - only after zombies started var tankSpawnRate = 300 - gameProgress * 150; // Start at 300 (5 seconds), end at 150 (2.5 seconds) if (zombiesStarted && LK.ticks % tankSpawnRate === 0 && LK.ticks > 0) { var tankZombie = new TankZombie(); var row = Math.floor(Math.random() * gridRows); tankZombie.x = 1900; tankZombie.y = gridStartY + row * gridCellHeight; tankZombie.gridRow = row; zombies.push(tankZombie); game.addChild(tankZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning } // Update all game objects for (var i = plants.length - 1; i >= 0; i--) { plants[i].update(); } for (var j = zombies.length - 1; j >= 0; j--) { zombies[j].update(); } for (var k = bullets.length - 1; k >= 0; k--) { bullets[k].update(); } // Generate sun from sunflowers - only if sunflowers exist var sunflowerCount = 0; for (var s = 0; s < plants.length; s++) { if (plants[s] instanceof Sunflower) { sunflowerCount++; } } if (sunflowerCount > 0 && LK.ticks - lastSunGeneration > 600) { // Every 10 seconds, only if sunflowers exist sun += 10; sunText.setText('Sun: ' + sun); lastSunGeneration = LK.ticks; } // Increased spawn when 1.5 minutes (90 seconds = 5400 ticks) remain - starts at 1.5 minutes left var timeElapsed = levelStartTime ? LK.ticks - levelStartTime : 0; var timeRemaining = Math.max(0, levelDuration - timeElapsed); if (timeRemaining <= 5400) { // 1.5 minutes = 90 seconds = 5400 ticks var intensifiedSpawnRate = 30 - (5400 - timeRemaining) / 5400 * 20; // Start at 30 (0.5 seconds), end at 10 (0.17 seconds) if (LK.ticks - lastZombieSpawn > intensifiedSpawnRate) { var zombie = new Zombie(); var row = Math.floor(Math.random() * gridRows); zombie.x = 1900; zombie.y = gridStartY + row * gridCellHeight; zombie.gridRow = row; zombies.push(zombie); game.addChild(zombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastZombieSpawn = LK.ticks; } // Also spawn fast zombies more frequently during intensified wave var intensifiedFastSpawnRate = 60 - (5400 - timeRemaining) / 5400 * 45; // Start at 60 (1 second), end at 15 (0.25 seconds) if (LK.ticks - lastFastZombieSpawn > intensifiedFastSpawnRate) { var fastZombie = new FastZombie(); var row = Math.floor(Math.random() * gridRows); fastZombie.x = 1900; fastZombie.y = gridStartY + row * gridCellHeight; fastZombie.gridRow = row; zombies.push(fastZombie); game.addChild(fastZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastFastZombieSpawn = LK.ticks; } } // Update timer display var timeElapsed = levelStartTime ? LK.ticks - levelStartTime : 0; var timeRemaining = Math.max(0, levelDuration - timeElapsed); var minutes = Math.floor(timeRemaining / 3600); var seconds = Math.floor(timeRemaining % 3600 / 60); var timeString = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; timerText.setText('Time: ' + timeString); // Check win condition - survive for 2 minutes if (levelStartTime && timeElapsed >= levelDuration) { // Player survived 2 minutes - they win! unlockNextLevel(); // Unlock next level when current level is completed // Calculate stars based on house health: 3 stars = 80+%, 2 stars = 50+%, 1 star = any health remaining var stars = 1; if (houseHealth >= 80) { stars = 3; } else if (houseHealth >= 50) { stars = 2; } setLevelStars(2, stars); LK.showYouWin(); } }; } // Initialize Dynamic Level for levels 3 and beyond function initializeDynamicLevel(levelNumber) { // Start playing game music only if music is enabled if (isMusicOn) { LK.playMusic('game'); } // Game variables houseHealth = 100; sun = 150 + (levelNumber - 1) * 50; // Progressive starting money: level 1=150, level 2=200, level 3=250, etc. plants = []; // Make plants global zombies = []; // Make zombies global bullets = []; // Make bullets global // Dynamic theme based on level var themeBackgrounds = ['desertBackground', 'iceBackground', 'jungleBackground']; var themeIndex = (levelNumber - 3) % themeBackgrounds.length; var themeBg = LK.getAsset(themeBackgrounds[themeIndex], { anchorX: 0, anchorY: 0 }); game.addChild(themeBg); var sunflowers = []; var lastSunGeneration = 0; var lastZombieSpawn = 0; var lastFastZombieSpawn = 0; // Dynamic difficulty scaling based on level - with increased spawn rates var difficultyMultiplier = levelNumber - 2; // Starts at 1 for level 3 var zombieSpawnRate = Math.max(30, 90 - difficultyMultiplier * 15); // Much faster spawning, increased each level var fastZombieSpawnRate = Math.max(60, 180 - difficultyMultiplier * 20); // Much more fast zombies // Dynamic level duration based on level number var levelDuration; if (levelNumber === 3) { levelDuration = 7200; // 2 minutes at 60fps (120 seconds * 60 = 7200 ticks) } else if (levelNumber >= 4 && levelNumber <= 6) { levelDuration = 9000; // 2.5 minutes at 60fps (150 seconds * 60 = 9000 ticks) } else if (levelNumber >= 7 && levelNumber <= 10) { levelDuration = 12600; // 3.5 minutes at 60fps (210 seconds * 60 = 12600 ticks) } var finalWaveStart = levelDuration - 1800; // Final wave starts 30 seconds before end var levelStartTime = null; // Track when level started - will be set when first plant is placed // Grid setup var gridRows = 10; var gridCols = 12; var gridCellWidth = 180; var gridCellHeight = 120; var gridStartX = 200; var gridStartY = 500; // UI elements sunText = new Text2('Sun: ' + sun, { size: 40, fill: 0x000000 }); sunText.x = 1500; sunText.y = 50; game.addChild(sunText); healthText = new Text2('House Health: ' + houseHealth, { size: 40, fill: 0xFF0000 }); healthText.x = 1500; healthText.y = 100; game.addChild(healthText); // Level indicator var levelText = new Text2('Level ' + levelNumber, { size: 50, fill: 0xFFFFFF }); levelText.x = 1500; levelText.y = 150; game.addChild(levelText); // Add timer display var initialTimeString; if (levelNumber === 3) { initialTimeString = 'Time: 2:00'; } else if (levelNumber >= 4 && levelNumber <= 6) { initialTimeString = 'Time: 2:30'; } else if (levelNumber >= 7 && levelNumber <= 10) { initialTimeString = 'Time: 3:30'; } var timerText = new Text2(initialTimeString, { size: 40, fill: 0x0000FF }); timerText.x = 1500; timerText.y = 200; game.addChild(timerText); // Create grid for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { var gridCell = LK.getAsset('gridTile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.75, scaleY: 0.75 }); gridCell.x = gridStartX + col * gridCellWidth; gridCell.y = gridStartY + row * gridCellHeight; gridCell.alpha = 0.9; // Apply theme-specific tinting with unique grid appearances if (themeBackgrounds[themeIndex] === 'desertBackground') { gridCell.tint = 0xD2691E; // Sandy orange for desert } else if (themeBackgrounds[themeIndex] === 'iceBackground') { gridCell.tint = 0x87CEEB; // Light blue for ice } else if (themeBackgrounds[themeIndex] === 'jungleBackground') { gridCell.tint = 0x228B22; // Forest green for jungle } game.addChild(gridCell); } } // Plant selection buttons with proper spacing var peashooterButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); peashooterButton.x = 300; peashooterButton.y = 1800; peashooterButton.tint = 0x006400; game.addChild(peashooterButton); // Add peashooter image to button var peashooterImage = LK.getAsset('peashooterBody', { anchorX: 0.5, anchorY: 0.5 }); peashooterImage.x = 300; peashooterImage.y = 1780; peashooterImage.scaleX = 1.0; peashooterImage.scaleY = 1.0; game.addChild(peashooterImage); var peashooterCost = 50 + Math.max(0, levelNumber - 5) * 5; // Cost same for levels 1-5, then increases by 5 per level var peashooterText = new Text2(peashooterCost + ' Sun', { size: 32, fill: 0xFFFFFF }); peashooterText.anchor.set(0.5, 0.5); peashooterText.x = 300; peashooterText.y = 1830; game.addChild(peashooterText); var sunflowerButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); sunflowerButton.x = 700; sunflowerButton.y = 1800; sunflowerButton.tint = 0xB8860B; game.addChild(sunflowerButton); // Add sunflower image to button var sunflowerImage = LK.getAsset('sunflowerCenter', { anchorX: 0.5, anchorY: 0.5 }); sunflowerImage.x = 700; sunflowerImage.y = 1780; sunflowerImage.scaleX = 0.75; sunflowerImage.scaleY = 0.75; game.addChild(sunflowerImage); var sunflowerCost = 50 + Math.max(0, levelNumber - 5) * 5; // Cost same for levels 1-5, then increases by 5 per level var sunflowerText = new Text2(sunflowerCost + ' Sun', { size: 32, fill: 0xFFFFFF }); sunflowerText.anchor.set(0.5, 0.5); sunflowerText.x = 700; sunflowerText.y = 1830; game.addChild(sunflowerText); var selectedPlant = null; // Add more plant options based on level if (levelNumber >= 3) { // Add DoublePeashooter button var doublePeaButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); doublePeaButton.x = 1100; doublePeaButton.y = 1800; doublePeaButton.tint = 0x00AA00; game.addChild(doublePeaButton); var doublePeaImage = LK.getAsset('placedDoublePeaBody', { anchorX: 0.5, anchorY: 0.5 }); doublePeaImage.x = 1100; doublePeaImage.y = 1780; game.addChild(doublePeaImage); var doublePeaCost = 100 + Math.max(0, levelNumber - 5) * 10; // Cost same for levels 1-5, then increases by 10 per level var doublePeaText = new Text2(doublePeaCost + ' Sun', { size: 28, fill: 0xFFFFFF }); doublePeaText.anchor.set(0.5, 0.5); doublePeaText.x = 1100; doublePeaText.y = 1830; game.addChild(doublePeaText); doublePeaButton.down = function () { if (sun >= doublePeaCost) { selectedPlant = 'doublepea'; } }; } if (levelNumber >= 4) { // Add CherryBomb button var cherrybombButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); cherrybombButton.x = 1500; cherrybombButton.y = 1800; cherrybombButton.tint = 0xFF0000; game.addChild(cherrybombButton); var cherrybombImage = LK.getAsset('cherryImage', { anchorX: 0.5, anchorY: 0.5 }); cherrybombImage.x = 1500; cherrybombImage.y = 1780; cherrybombImage.scaleX = 0.6; cherrybombImage.scaleY = 0.6; game.addChild(cherrybombImage); var cherrybombCost = 100 + Math.max(0, levelNumber - 5) * 10; // Cost same for levels 1-5, then increases by 10 per level var cherrybombText = new Text2(cherrybombCost + ' Sun', { size: 28, fill: 0xFFFFFF }); cherrybombText.anchor.set(0.5, 0.5); cherrybombText.x = 1500; cherrybombText.y = 1830; game.addChild(cherrybombText); cherrybombButton.down = function () { if (sun >= cherrybombCost) { selectedPlant = 'cherrybomb'; } }; } if (levelNumber >= 6) { // Add WallNut button below CherryBomb button var wallnutButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); wallnutButton.x = 1500; wallnutButton.y = 2000; wallnutButton.tint = 0x8B4513; game.addChild(wallnutButton); var wallnutImage = LK.getAsset('placedWallNutBody', { anchorX: 0.5, anchorY: 0.5 }); wallnutImage.x = 1500; wallnutImage.y = 1980; wallnutImage.scaleX = 0.9; wallnutImage.scaleY = 0.9; game.addChild(wallnutImage); var wallnutCost = 50 + Math.max(0, levelNumber - 5) * 5; // Cost same for levels 1-5, then increases by 5 per level var wallnutText = new Text2(wallnutCost + ' Sun', { size: 32, fill: 0xFFFFFF }); wallnutText.anchor.set(0.5, 0.5); wallnutText.x = 1500; wallnutText.y = 2030; game.addChild(wallnutText); wallnutButton.down = function () { if (sun >= wallnutCost) { selectedPlant = 'wallnut'; } }; } if (levelNumber >= 8) { // Add IcePeashooter button below Peashooter var icepeaButton = LK.getAsset('selectionBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); icepeaButton.x = 300; icepeaButton.y = 2000; icepeaButton.tint = 0x87CEEB; game.addChild(icepeaButton); var icepeaImage = LK.getAsset('icePeashooterBody', { anchorX: 0.5, anchorY: 0.5 }); icepeaImage.x = 300; icepeaImage.y = 1980; icepeaImage.scaleX = 1.0; icepeaImage.scaleY = 1.0; game.addChild(icepeaImage); var icepeaCost = 75 + Math.max(0, levelNumber - 5) * 8; // Cost same for levels 1-5, then increases by 8 per level var icepeaText = new Text2(icepeaCost + ' Sun', { size: 32, fill: 0xFFFFFF }); icepeaText.anchor.set(0.5, 0.5); icepeaText.x = 300; icepeaText.y = 2030; game.addChild(icepeaText); icepeaButton.down = function () { if (sun >= icepeaCost) { selectedPlant = 'icepea'; } }; } // Event handlers peashooterButton.down = function () { if (sun >= peashooterCost) { selectedPlant = 'peashooter'; } }; sunflowerButton.down = function () { if (sun >= sunflowerCost) { selectedPlant = 'sunflower'; } }; game.down = function (x, y, obj) { if (selectedPlant && x >= gridStartX && x <= gridStartX + gridCols * gridCellWidth && y >= gridStartY && y <= gridStartY + gridRows * gridCellHeight) { var gridCol = Math.floor((x - gridStartX) / gridCellWidth); var gridRow = Math.floor((y - gridStartY) / gridCellHeight); // Check if position is valid and empty var positionEmpty = true; for (var i = 0; i < plants.length; i++) { if (plants[i].gridRow === gridRow && plants[i].gridCol === gridCol) { positionEmpty = false; break; } } if (positionEmpty && gridCol >= 0 && gridCol < gridCols && gridRow >= 0 && gridRow < gridRows) { var plant = null; if (selectedPlant === 'peashooter' && sun >= peashooterCost) { plant = new Peashooter(); sun -= peashooterCost; } else if (selectedPlant === 'sunflower' && sun >= sunflowerCost) { plant = new Sunflower(); sun -= sunflowerCost; } else if (selectedPlant === 'doublepea' && sun >= doublePeaCost) { plant = new DoublePeashooter(); sun -= doublePeaCost; } else if (selectedPlant === 'cherrybomb' && sun >= cherrybombCost) { plant = new CherryBomb(); sun -= cherrybombCost; } else if (selectedPlant === 'wallnut' && sun >= wallnutCost) { plant = new WallNut(); sun -= wallnutCost; } else if (selectedPlant === 'icepea' && sun >= icepeaCost) { plant = new IcePeashooter(); sun -= icepeaCost; } if (plant) { plant.x = gridStartX + gridCol * gridCellWidth; plant.y = gridStartY + gridRow * gridCellHeight; plant.gridRow = gridRow; plant.gridCol = gridCol; plants.push(plant); game.addChild(plant); sunText.setText('Sun: ' + sun); selectedPlant = null; } } } }; var zombiesStarted = false; // Track if zombies have started spawning // Game update function for Dynamic Levels game.update = function () { // Start zombie spawning and timer only after first plant is placed if (!zombiesStarted && plants.length > 0) { zombiesStarted = true; levelStartTime = LK.ticks; // Start level timer when first plant is placed lastZombieSpawn = LK.ticks; // Initialize spawn timer lastFastZombieSpawn = LK.ticks; // Initialize fast zombie spawn timer } // Spawn regular zombies with progressive and scaled difficulty - only after zombies started var gameProgress = Math.min(LK.ticks / levelDuration, 1); // Progress from 0 to 1 over level duration var progressiveSpawnRate = zombieSpawnRate * 2 - gameProgress * zombieSpawnRate; // Start at 2x spawn rate, end at 1x if (zombiesStarted && LK.ticks - lastZombieSpawn > progressiveSpawnRate) { var zombie = new Zombie(); var row = Math.floor(Math.random() * gridRows); zombie.x = 1900; zombie.y = gridStartY + row * gridCellHeight; zombie.gridRow = row; zombies.push(zombie); game.addChild(zombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastZombieSpawn = LK.ticks; } // Spawn fast zombies with progressive and scaled difficulty - only after zombies started var progressiveFastSpawnRate = fastZombieSpawnRate * 2 - gameProgress * fastZombieSpawnRate; // Start at 2x spawn rate, end at 1x if (zombiesStarted && LK.ticks - lastFastZombieSpawn > progressiveFastSpawnRate) { var fastZombie = new FastZombie(); var row = Math.floor(Math.random() * gridRows); fastZombie.x = 1900; fastZombie.y = gridStartY + row * gridCellHeight; fastZombie.gridRow = row; zombies.push(fastZombie); game.addChild(fastZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastFastZombieSpawn = LK.ticks; } // Spawn tank zombies on higher levels with progressive spawn rate - only after zombies started if (zombiesStarted && levelNumber >= 4) { var baseTankSpawnRate = 180 - difficultyMultiplier * 30; var progressiveTankSpawnRate = baseTankSpawnRate * 2 - gameProgress * baseTankSpawnRate; // Start at 2x spawn rate, end at 1x if (LK.ticks % progressiveTankSpawnRate === 0 && LK.ticks > 0) { var tankZombie = new TankZombie(); var row = Math.floor(Math.random() * gridRows); tankZombie.x = 1900; tankZombie.y = gridStartY + row * gridCellHeight; tankZombie.gridRow = row; zombies.push(tankZombie); game.addChild(tankZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning } } // Spawn shield zombies starting from level 5 with progressive spawn rate - only after zombies started if (zombiesStarted && levelNumber >= 5) { var baseShieldSpawnRate = 210 - difficultyMultiplier * 30; var progressiveShieldSpawnRate = baseShieldSpawnRate * 2 - gameProgress * baseShieldSpawnRate; // Start at 2x spawn rate, end at 1x if (LK.ticks % progressiveShieldSpawnRate === 0 && LK.ticks > 0) { var shieldZombie = new ShieldZombie(); var row = Math.floor(Math.random() * gridRows); shieldZombie.x = 1900; shieldZombie.y = gridStartY + row * gridCellHeight; shieldZombie.gridRow = row; zombies.push(shieldZombie); game.addChild(shieldZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning } } // Spawn jumper zombies on even higher levels with progressive spawn rate - only after zombies started if (zombiesStarted && levelNumber >= 6) { var baseJumperSpawnRate = 150 - difficultyMultiplier * 20; var progressiveJumperSpawnRate = baseJumperSpawnRate * 2 - gameProgress * baseJumperSpawnRate; // Start at 2x spawn rate, end at 1x if (LK.ticks % progressiveJumperSpawnRate === 0 && LK.ticks > 0) { var jumperZombie = new JumperZombie(); var row = Math.floor(Math.random() * gridRows); jumperZombie.x = 1900; jumperZombie.y = gridStartY + row * gridCellHeight; jumperZombie.gridRow = row; zombies.push(jumperZombie); game.addChild(jumperZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning } } // Spawn bomber zombies on levels 8, 9, and 10 with progressive spawn rate - only after zombies started if (zombiesStarted && levelNumber >= 8) { var baseBomberSpawnRate = Math.max(180, 240 - difficultyMultiplier * 25); var progressiveBomberSpawnRate = baseBomberSpawnRate * 2 - gameProgress * baseBomberSpawnRate; // Start at 2x spawn rate, end at 1x if (LK.ticks - lastZombieSpawn > progressiveBomberSpawnRate && LK.ticks % 300 === 0) { var bomberZombie = new BomberZombie(); var row = Math.floor(Math.random() * gridRows); bomberZombie.x = 1900; bomberZombie.y = gridStartY + row * gridCellHeight; bomberZombie.gridRow = row; zombies.push(bomberZombie); game.addChild(bomberZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning } } // Update all game objects for (var i = plants.length - 1; i >= 0; i--) { plants[i].update(); } for (var j = zombies.length - 1; j >= 0; j--) { zombies[j].update(); } for (var k = bullets.length - 1; k >= 0; k--) { bullets[k].update(); } // Generate sun from sunflowers - only if sunflowers exist var sunflowerCount = 0; for (var s = 0; s < plants.length; s++) { if (plants[s] instanceof Sunflower) { sunflowerCount++; } } if (sunflowerCount > 0 && LK.ticks - lastSunGeneration > 600) { // Every 10 seconds, only if sunflowers exist sun += 10; sunText.setText('Sun: ' + sun); lastSunGeneration = LK.ticks; } // Intensified wave - spawn many more zombies rapidly when 1.5 minutes remain var timeRemaining = Math.max(0, levelDuration - timeElapsed); if (levelStartTime && timeRemaining <= 5400) { // 1.5 minutes = 90 seconds = 5400 ticks var intensifiedProgress = (5400 - timeRemaining) / 5400; // Progress from 0 to 1 over intensified period var baseIntensifiedSpawnRate = Math.max(8, zombieSpawnRate / 8); // Much faster in intensified wave var progressiveIntensifiedSpawnRate = baseIntensifiedSpawnRate * 3 - intensifiedProgress * baseIntensifiedSpawnRate * 2; // Start at 3x, end at 1x if (LK.ticks - lastZombieSpawn > progressiveIntensifiedSpawnRate) { var zombie = new Zombie(); var row = Math.floor(Math.random() * gridRows); zombie.x = 1900; zombie.y = gridStartY + row * gridCellHeight; zombie.gridRow = row; zombies.push(zombie); game.addChild(zombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastZombieSpawn = LK.ticks; } // Also spawn fast zombies more frequently during intensified wave var baseIntensifiedFastRate = Math.max(15, fastZombieSpawnRate / 8); var progressiveIntensifiedFastRate = baseIntensifiedFastRate * 3 - intensifiedProgress * baseIntensifiedFastRate * 2; // Start at 3x, end at 1x if (LK.ticks - lastFastZombieSpawn > progressiveIntensifiedFastRate) { var fastZombie = new FastZombie(); var row = Math.floor(Math.random() * gridRows); fastZombie.x = 1900; fastZombie.y = gridStartY + row * gridCellHeight; fastZombie.gridRow = row; zombies.push(fastZombie); game.addChild(fastZombie); LK.getSound('zombisesi').play(); // Play zombie sound when spawning lastFastZombieSpawn = LK.ticks; } } // Update timer display var timeElapsed = levelStartTime ? LK.ticks - levelStartTime : 0; var timeRemaining = Math.max(0, levelDuration - timeElapsed); var minutes = Math.floor(timeRemaining / 3600); var seconds = Math.floor(timeRemaining % 3600 / 60); var timeString = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; timerText.setText('Time: ' + timeString); // Check win condition - survive for 2 minutes if (levelStartTime && timeElapsed >= levelDuration) { // Player survived 2 minutes - they win! unlockNextLevel(); // Unlock next level when current level is completed // Calculate stars based on house health: 3 stars = 80+%, 2 stars = 50+%, 1 star = any health remaining var stars = 1; if (houseHealth >= 80) { stars = 3; } else if (houseHealth >= 50) { stars = 2; } setLevelStars(levelNumber, stars); LK.showYouWin(); } }; } // Function to unlock next level function unlockNextLevel() { // Only unlock the next level if current level is completed and next level exists if (currentLevel === unlockedLevels && unlockedLevels < totalLevels) { unlockedLevels++; storage.unlockedLevels = unlockedLevels; // Save to storage if (levelButtons[unlockedLevels - 1]) { levelButtons[unlockedLevels - 1].setUnlocked(true); } } } // Function to set stars for a level function setLevelStars(levelNumber, stars) { levelProgress[levelNumber] = stars; storage.levelProgress = levelProgress; // Save to storage if (levelButtons[levelNumber - 1]) { levelButtons[levelNumber - 1].setStars(stars); } } // Pause menu variables var isPaused = false; var pauseMenu = null; var currentLevel = 0; // Function to show pause menu function showPauseMenu() { if (pauseMenu) return; // Already showing // Create pause menu background pauseMenu = new Container(); var pauseBg = LK.getAsset('paperBackground', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.4 }); pauseBg.x = 0; pauseBg.y = 0; pauseBg.tint = 0x000000; pauseBg.alpha = 0.8; pauseMenu.addChild(pauseBg); // Pause title var pauseTitle = new Text2('PAUSED', { size: 60, fill: 0xFFFFFF }); pauseTitle.anchor.set(0.5, 0.5); pauseTitle.x = 0; pauseTitle.y = -100; pauseMenu.addChild(pauseTitle); // Restart button var restartButton = LK.getAsset('levelButton', { anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 0; restartButton.y = 0; restartButton.tint = 0x4CAF50; pauseMenu.addChild(restartButton); var restartText = new Text2('RESTART', { size: 40, fill: 0x000000 }); restartText.anchor.set(0.5, 0.5); restartText.x = 0; restartText.y = 0; pauseMenu.addChild(restartText); // Resume button var resumeButton = LK.getAsset('levelButton', { anchorX: 0.5, anchorY: 0.5 }); resumeButton.x = 0; resumeButton.y = 120; resumeButton.tint = 0x2196F3; pauseMenu.addChild(resumeButton); var resumeText = new Text2('RESUME', { size: 40, fill: 0x000000 }); resumeText.anchor.set(0.5, 0.5); resumeText.x = 0; resumeText.y = 120; pauseMenu.addChild(resumeText); // Position pause menu at center of screen pauseMenu.x = 1024; pauseMenu.y = 1366; // Add event handlers restartButton.down = function () { LK.getSound('buttonClick').play(); hidePauseMenu(); // Restart current level if (currentLevel === 1) { game.removeChildren(); initializeLevel1(); } else if (currentLevel === 2) { game.removeChildren(); initializeLevel2(); } else if (currentLevel >= 3 && currentLevel <= 10) { game.removeChildren(); initializeDynamicLevel(currentLevel); } }; resumeButton.down = function () { LK.getSound('buttonClick').play(); hidePauseMenu(); }; game.addChild(pauseMenu); } // Function to hide pause menu function hidePauseMenu() { if (pauseMenu) { game.removeChild(pauseMenu); pauseMenu = null; } isPaused = false; } // Override game pause handler LK.on('pause', function () { if (currentLevel > 0) { // Only show pause menu during gameplay isPaused = true; showPauseMenu(); } }); // Simple game update for level selection screen game.update = function () { // No specific updates needed for level selection // All interactions are handled by level button click events };
===================================================================
--- original.js
+++ change.js
@@ -162,9 +162,9 @@
self.lastDamageTime = LK.ticks;
}
// Deal damage every 50 ticks while touching other plants
if (LK.ticks - self.lastDamageTime >= 50) {
- plant.health -= 3;
+ plant.health -= 20; // Bomber zombie destroys plants with explosive damage
self.lastDamageTime = LK.ticks;
}
}
if (plant.health <= 0) {
@@ -433,9 +433,9 @@
self.lastDamageTime = LK.ticks;
}
// Deal damage every 45 ticks while touching other plants
if (LK.ticks - self.lastDamageTime >= 45) {
- plant.health -= 3; // Fast zombie eats faster
+ plant.health -= 15; // Fast zombie destroys plants quickly
self.lastDamageTime = LK.ticks;
}
}
if (plant.health <= 0) {
@@ -694,9 +694,9 @@
self.lastDamageTime = LK.ticks;
}
// Deal damage every 60 ticks while touching other plants
if (LK.ticks - self.lastDamageTime >= 60) {
- plant.health -= 3;
+ plant.health -= 15; // Jumper zombie destroys plants with high damage
self.lastDamageTime = LK.ticks;
}
}
if (plant.health <= 0) {
@@ -937,9 +937,9 @@
self.lastDamageTime = LK.ticks;
}
// Deal damage every 60 ticks while touching other plants
if (LK.ticks - self.lastDamageTime >= 60) {
- plant.health -= 3;
+ plant.health -= 12; // Shield zombie destroys plants with moderate damage
self.lastDamageTime = LK.ticks;
}
}
if (plant.health <= 0) {
@@ -1075,9 +1075,9 @@
self.lastDamageTime = LK.ticks;
}
// Deal damage every 70 ticks while touching other plants
if (LK.ticks - self.lastDamageTime >= 70) {
- plant.health -= 5; // Tank zombie eats slowly but powerfully
+ plant.health -= 25; // Tank zombie destroys plants with massive damage
self.lastDamageTime = LK.ticks;
}
}
if (plant.health <= 0) {
@@ -1249,9 +1249,9 @@
self.lastDamageTime = LK.ticks;
}
// Deal damage every 60 ticks (1 second) while touching other plants
if (LK.ticks - self.lastDamageTime >= 60) {
- plant.health -= 2;
+ plant.health -= 10; // Increased damage to destroy plants faster
self.lastDamageTime = LK.ticks;
}
}
if (plant.health <= 0) {
Kahverengi sayfa yaprağı. In-Game asset. 2d. High contrast. No shadows
Kağıdın içinde plants vs zombies yazsin
Plant vs zombies ay çiçeği. In-Game asset. 2d. High contrast. No shadows
boş buton. In-Game asset. 2d. High contrast. No shadows
plans vs zombies double shoters. In-Game asset. 2d. High contrast. No shadows
çöl. In-Game asset. 2d. High contrast. No shadows
buz arkaplan. In-Game asset. 2d. High contrast. No shadows
gece gökyüzü. In-Game asset. 2d. High contrast. No shadows
orman. In-Game asset. 2d. High contrast. No shadows
toprak arka plan. In-Game asset. 2d. High contrast. No shadows
plants vs zombies ceviz. In-Game asset. 2d. High contrast. No shadows
ıcepeasshooter plants vs zombies. In-Game asset. 2d. High contrast. No shadows
kankanlı zombi plants vs zombies. In-Game asset. 2d. High contrast. No shadows
plants vs zombies olü ceviz. In-Game asset. 2d. High contrast. No shadows
bombacı zombi plants vs zombies. In-Game asset. 2d. High contrast. No shadows