User prompt
Creates a plant called puffshroom that costs 0 suns and shoots spores and creates a separate resource for the spore and has a range to detect a zombie of 3 tiles and can only be used from wave 11 onwards and appears on page 2 of the plant selector βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the repeater plant appear on the first page of the plant selector.
User prompt
Make the left arrow of the plant selector go further to the left so that the repeater plant comes in after the chomper plant in the plant selector on the first page.
User prompt
Make the gargantuar spawn a fastzombie 3 squares further away from the gargantuar
User prompt
Make the arrow button further to the left and on the first page of the plant selector, have Peashooter, Sunflower, Cherrypopper, Wallnut, Potatomine, Snowshooter, Chomper, and Repeater in that order.
User prompt
Make the gargantuar unable to be eaten by the chomper plant
User prompt
Make the chomper plant eat the nearest zombie and make the minerzombie take 5 seconds instead of 3 βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Also make the chomper plant adjust when it is black when it can't eat another zombie and return to its normal color when it can eat another zombie βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the first zombie spawn in wave 1 after 10 seconds.
User prompt
Sets the chomper to a two-tile range and a 15 second cooldown. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
fix the bug that causes the potatomine plant to explode without eliminating the zombie that touched it and make the potatomine plant take 15 seconds to charge, not 5 anymore, make it so that when the potatomine explodes with a newspaperzombie and gargantuar it leaves it at half health βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
creates a plant called potatomine that costs 25 suns and will take 5 seconds to be charged to explode when a zombie touches it this plant will explode and while it is on cooldown when placed it will be black and when it is charged it will return to its normal color βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Move the plant selector a little to the left and create a plant called chomper that eats the nearby zombie in a range of one square and has a cooldown to be able to eat another zombie and costs 150 soles and when it is on cooldown it has a black color βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now make different plant selectors with different plants and make splitpea appear in the second plant selector and for now let there only be 2 plant selectors and when pressing the right arrow button it changes to the second plant selector and when pressing the left arrow it returns to the previous plant selector
User prompt
Add two arrows, one on the left side of the plant selector and the other on the right side of the plant selector, which for now has no function.
User prompt
Make the suns bigger and have the suns that appear without a sunflower have an animation that says they are falling from the top to the bottom of the screen. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the shovel at the top right of the screen and make it bigger.
User prompt
Make the letters of the sun costs of the plants black and remove the black outline.
User prompt
Make the letters of the sole costs of the plants even bigger.
User prompt
Make the sun counter have a black outline and make the plant and shovel cost letters larger.
User prompt
make the sun letters have a black outline
User prompt
Modify Splitpea so that it can also detect zombies that are behind
User prompt
Create a plant called splitpea that costs 125 soles and shoots one pea forward and two peas backward.
User prompt
Create a plant called repeater that costs 200 soles and shoots two peas.
User prompt
create an asset for the minerzombie
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BackwardPea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pea', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint green to show it's from splitpea
graphics.tint = 0x44ff44;
self.speed = -8; // Negative speed to go backwards
self.damage = 15;
self.gridY = 0;
self.update = function () {
self.x += self.speed;
// Check collision with zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (zombie.gridY === self.gridY && self.intersects(zombie)) {
// Check if it's a JesterZombie
if (zombie.isJester) {
// Create reflected pea going forward
var reflectedPea = new ReflectedPea();
reflectedPea.x = zombie.x + 50;
reflectedPea.y = zombie.y;
reflectedPea.gridY = zombie.gridY;
reflectedpeas.push(reflectedPea);
game.addChild(reflectedPea);
// Flash jester zombie to show deflection
LK.effects.flashObject(zombie, 0xffff00, 200);
} else {
zombie.takeDamage(self.damage, 'pea');
}
self.destroy();
for (var j = 0; j < backwardpeas.length; j++) {
if (backwardpeas[j] === self) {
backwardpeas.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen (left side)
if (self.x < -100) {
self.destroy();
for (var k = 0; k < backwardpeas.length; k++) {
if (backwardpeas[k] === self) {
backwardpeas.splice(k, 1);
break;
}
}
}
};
return self;
});
var BasicZombie = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('basicZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5;
self.health = 100;
self.maxHealth = 100;
self.damage = 40;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 60;
self.update = function () {
// Check if there's a plant to attack
var plantToAttack = null;
for (var i = 0; i < plants.length; i++) {
var plant = plants[i];
if (plant.gridY === self.gridY && Math.abs(plant.x - self.x) < 80) {
plantToAttack = plant;
break;
}
}
if (plantToAttack) {
self.attackTimer++;
if (self.attackTimer >= self.attackDelay) {
if (plantToAttack.takeDamage) {
plantToAttack.takeDamage(self.damage);
}
self.attackTimer = 0;
}
} else {
self.x -= self.speed;
self.attackTimer = 0;
}
// Check if reached house
if (self.x < 150) {
LK.showGameOver();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('zombie_hit').play();
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < zombies.length; i++) {
if (zombies[i] === self) {
zombies.splice(i, 1);
break;
}
}
zombiesKilled++;
}
};
return self;
});
var Zomboni = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with zomboni asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('zomboni', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5; // Fast movement
self.health = 150;
self.maxHealth = 150;
self.damage = 100;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 30; // Faster elimination
self.update = function () {
// Move forward continuously
self.x -= self.speed;
// Check for plants to eliminate (in a wider area due to size)
for (var i = plants.length - 1; i >= 0; i--) {
var plant = plants[i];
if (plant.gridY === self.gridY && Math.abs(plant.x - self.x) < 100) {
// Instantly eliminate the plant
LK.effects.flashObject(plant, 0xff0000, 200);
// Remove from plant grid
var gridKey = plant.gridX + ',' + plant.gridY;
delete plantGrid[gridKey];
plant.destroy();
plants.splice(i, 1);
}
}
// Check if reached house
if (self.x < 150) {
LK.showGameOver();
}
};
return self;
});
var TankZombie = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with tank zombie asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('tankZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.3;
self.health = 200;
self.maxHealth = 200;
self.damage = 80;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 60;
return self;
});
var NewspaperZombie = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with newspaper zombie asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('newspaperZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5;
self.health = 100;
self.maxHealth = 100;
self.damage = 40;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 60;
self.hasRaged = false;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('zombie_hit').play();
// Check if health dropped to half or below and hasn't raged yet
if (self.health <= self.maxHealth / 2 && !self.hasRaged) {
self.hasRaged = true;
// Increase speed and damage
self.speed = 1.5;
self.damage = 80;
// Visual effect for rage mode - flash red and change tint
LK.effects.flashObject(self, 0xff0000, 500);
tween(graphics, {
tint: 0xff4444
}, {
duration: 300,
easing: tween.easeOut
});
}
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < zombies.length; i++) {
if (zombies[i] === self) {
zombies.splice(i, 1);
break;
}
}
zombiesKilled++;
}
};
return self;
});
var MinerZombie = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with miner zombie asset (appears as normal zombie)
self.removeChild(self.children[0]);
var graphics = self.attachAsset('minerZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5;
self.health = 80;
self.maxHealth = 80;
self.damage = 40;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 60;
self.teleportTimer = 0;
self.teleportDelay = 180; // 3 seconds at 60fps
self.hasTeleported = false;
self.update = function () {
// If not teleported yet, count down to teleport
if (!self.hasTeleported) {
self.teleportTimer++;
if (self.teleportTimer >= self.teleportDelay) {
self.teleport();
} else {
// Move normally before teleporting
self.x -= self.speed;
}
} else {
// After teleporting, behave like normal zombie but attacking from behind
var plantToAttack = null;
for (var i = 0; i < plants.length; i++) {
var plant = plants[i];
if (plant.gridY === self.gridY && Math.abs(plant.x - self.x) < 80) {
plantToAttack = plant;
break;
}
}
if (plantToAttack) {
self.attackTimer++;
if (self.attackTimer >= self.attackDelay) {
if (plantToAttack.takeDamage) {
plantToAttack.takeDamage(self.damage);
}
self.attackTimer = 0;
}
} else {
self.x += self.speed; // Move forward (right) after teleporting
self.attackTimer = 0;
}
}
// Check if reached house (only matters before teleporting)
if (!self.hasTeleported && self.x < 150) {
LK.showGameOver();
}
// Check if moved off screen after teleporting
if (self.hasTeleported && self.x > 2200) {
self.destroy();
for (var i = 0; i < zombies.length; i++) {
if (zombies[i] === self) {
zombies.splice(i, 1);
break;
}
}
}
};
self.teleport = function () {
if (self.hasTeleported) return;
self.hasTeleported = true;
// Flash effect before teleporting
LK.effects.flashObject(self, 0xffff00, 300);
// Teleport to the first column (leftmost position behind plants)
var newX = gridStartX + gridWidth / 2;
var newY = gridStartY + self.gridY * gridHeight + gridHeight / 2;
// Animate teleportation with tween
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Move to new position
self.x = newX;
self.y = newY;
// Animate appearing at new location
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Flash effect when appearing
LK.effects.flashObject(self, 0x00ff00, 300);
}
});
};
return self;
});
var JesterZombie = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with jester zombie asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('jesterZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.8;
self.health = 120;
self.maxHealth = 120;
self.damage = 50;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 60;
self.isJester = true; // Flag to identify this zombie type
// Override takeDamage to be immune to peas
self.takeDamage = function (damage, source) {
// Only take damage from non-pea sources
if (source !== 'pea' && source !== 'frozenpea') {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('zombie_hit').play();
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < zombies.length; i++) {
if (zombies[i] === self) {
zombies.splice(i, 1);
break;
}
}
zombiesKilled++;
}
}
};
return self;
});
var JackInBoxZombie = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with jack in box zombie asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('jackInBoxZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.7;
self.health = 80;
self.maxHealth = 80;
self.damage = 60;
self.hasExploded = false;
self.explode = function () {
if (self.hasExploded) return;
self.hasExploded = true;
// Flash the jack in box zombie white before exploding
LK.effects.flashObject(self, 0xffffff, 200);
// Scale up effect for explosion
tween(graphics, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove from zombies array
for (var i = 0; i < zombies.length; i++) {
if (zombies[i] === self) {
zombies.splice(i, 1);
break;
}
}
// Destroy the jack in box zombie
self.destroy();
}
});
// Eliminate plants in a 250 pixel radius
var explosionRadius = 250;
for (var i = plants.length - 1; i >= 0; i--) {
var plant = plants[i];
var distance = Math.sqrt(Math.pow(plant.x - self.x, 2) + Math.pow(plant.y - self.y, 2));
if (distance <= explosionRadius) {
// Flash plant red before destroying
LK.effects.flashObject(plant, 0xff0000, 200);
// Remove from plant grid
var gridKey = plant.gridX + ',' + plant.gridY;
delete plantGrid[gridKey];
plant.destroy();
plants.splice(i, 1);
}
}
};
self.update = function () {
// Check if there's a plant to explode on
var plantToExplode = null;
for (var i = 0; i < plants.length; i++) {
var plant = plants[i];
if (plant.gridY === self.gridY && Math.abs(plant.x - self.x) < 80) {
plantToExplode = plant;
break;
}
}
if (plantToExplode && !self.hasExploded) {
self.explode();
} else {
self.x -= self.speed;
}
// Check if reached house
if (self.x < 150) {
LK.showGameOver();
}
};
return self;
});
var Gargantuar = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with gargantuar asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('gargantuar', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.2; // Very slow
self.health = 400; // Very resistant
self.maxHealth = 400;
self.damage = 200; // High damage to eliminate plants instantly
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 30; // Fast elimination
self.hasSpawnedFastZombie = false;
self.isResistantToExplosion = true; // Flag for cherry popper resistance
self.update = function () {
// Check if there's a plant to eliminate
var plantToEliminate = null;
for (var i = 0; i < plants.length; i++) {
var plant = plants[i];
if (plant.gridY === self.gridY && Math.abs(plant.x - self.x) < 120) {
plantToEliminate = plant;
break;
}
}
if (plantToEliminate) {
self.attackTimer++;
if (self.attackTimer >= self.attackDelay) {
// Instantly eliminate the plant
LK.effects.flashObject(plantToEliminate, 0xff0000, 200);
// Remove from plant grid
var gridKey = plantToEliminate.gridX + ',' + plantToEliminate.gridY;
delete plantGrid[gridKey];
plantToEliminate.destroy();
for (var j = 0; j < plants.length; j++) {
if (plants[j] === plantToEliminate) {
plants.splice(j, 1);
break;
}
}
self.attackTimer = 0;
}
} else {
self.x -= self.speed;
self.attackTimer = 0;
}
// Spawn FastZombie when at half health
if (self.health <= self.maxHealth / 2 && !self.hasSpawnedFastZombie) {
self.hasSpawnedFastZombie = true;
var fastZombie = new FastZombie();
fastZombie.x = self.x + 50;
fastZombie.y = self.y;
fastZombie.gridY = self.gridY;
zombies.push(fastZombie);
game.addChild(fastZombie);
// Visual effect for spawning
LK.effects.flashObject(self, 0xffff00, 500);
}
// Check if reached house
if (self.x < 150) {
LK.showGameOver();
}
};
return self;
});
var FastZombie = BasicZombie.expand(function () {
var self = BasicZombie.call(this);
// Replace the graphics with fast zombie asset
self.removeChild(self.children[0]);
var graphics = self.attachAsset('fastZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.2;
self.health = 60;
self.maxHealth = 60;
self.damage = 40;
self.gridY = 0;
self.attackTimer = 0;
self.attackDelay = 60;
return self;
});
var CherryPopper = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('cherrypopper', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 150;
self.gridX = 0;
self.gridY = 0;
self.hasExploded = false;
self.explode = function () {
if (self.hasExploded) return;
self.hasExploded = true;
// Flash the cherry popper white before exploding
LK.effects.flashObject(self, 0xffffff, 200);
// Scale up effect for explosion
tween(graphics, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove from plants array
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
// Remove from plant grid
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
// Destroy the cherry popper
self.destroy();
}
});
// Eliminate zombies in a 300 pixel radius
var explosionRadius = 300;
for (var i = zombies.length - 1; i >= 0; i--) {
var zombie = zombies[i];
var distance = Math.sqrt(Math.pow(zombie.x - self.x, 2) + Math.pow(zombie.y - self.y, 2));
if (distance <= explosionRadius) {
// Special handling for Gargantuar
if (zombie.constructor === Gargantuar) {
// Flash zombie red
LK.effects.flashObject(zombie, 0xff0000, 200);
// If at full health or more than half, reduce to half
if (zombie.health > zombie.maxHealth / 2) {
zombie.health = zombie.maxHealth / 2;
// Visual effect for being damaged but not destroyed
tween(zombie, {
tint: 0xff4444
}, {
duration: 500,
easing: tween.easeOut
});
} else {
// Second explosion - eliminate Gargantuar
zombie.destroy();
zombies.splice(i, 1);
zombiesKilled++;
}
} else {
// Normal zombies - eliminate immediately
LK.effects.flashObject(zombie, 0xff0000, 200);
zombie.destroy();
zombies.splice(i, 1);
zombiesKilled++;
}
}
}
};
// Auto-explode when planted (immediately after placement)
self.update = function () {
if (!self.hasExploded) {
self.explode();
}
};
return self;
});
var FrozenPea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('frozenpea', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 15;
self.gridY = 0;
self.slowDuration = 300; // 5 seconds at 60fps
self.slowFactor = 0.3; // Reduce speed to 30%
self.update = function () {
self.x += self.speed;
// Check collision with zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (zombie.gridY === self.gridY && self.intersects(zombie)) {
// Check if it's a JesterZombie
if (zombie.isJester) {
// Create reflected frozen pea going back towards plants
var reflectedFrozenPea = new ReflectedFrozenPea();
reflectedFrozenPea.x = zombie.x - 50;
reflectedFrozenPea.y = zombie.y;
reflectedFrozenPea.gridY = zombie.gridY;
reflectedfrozenpeas.push(reflectedFrozenPea);
game.addChild(reflectedFrozenPea);
// Flash jester zombie to show deflection
LK.effects.flashObject(zombie, 0xffff00, 200);
} else {
zombie.takeDamage(self.damage, 'frozenpea');
// Apply slow effect only if not a Zomboni or NewspaperZombie
if (zombie.constructor !== Zomboni && zombie.constructor !== NewspaperZombie) {
if (!zombie.originalSpeed) {
zombie.originalSpeed = zombie.speed;
}
zombie.speed = zombie.originalSpeed * self.slowFactor;
zombie.slowTimer = self.slowDuration;
// Visual effect for slowed zombie
tween(zombie, {
tint: 0x87ceeb
}, {
duration: 300,
easing: tween.easeOut
});
}
}
self.destroy();
for (var j = 0; j < frozenpeas.length; j++) {
if (frozenpeas[j] === self) {
frozenpeas.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen
if (self.x > 2200) {
self.destroy();
for (var k = 0; k < frozenpeas.length; k++) {
if (frozenpeas[k] === self) {
frozenpeas.splice(k, 1);
break;
}
}
}
};
return self;
});
var Pea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pea', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 15;
self.gridY = 0;
self.update = function () {
self.x += self.speed;
// Check collision with zombies
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (zombie.gridY === self.gridY && self.intersects(zombie)) {
// Check if it's a JesterZombie
if (zombie.isJester) {
// Create reflected pea going back towards plants
var reflectedPea = new ReflectedPea();
reflectedPea.x = zombie.x - 50;
reflectedPea.y = zombie.y;
reflectedPea.gridY = zombie.gridY;
reflectedpeas.push(reflectedPea);
game.addChild(reflectedPea);
// Flash jester zombie to show deflection
LK.effects.flashObject(zombie, 0xffff00, 200);
} else {
zombie.takeDamage(self.damage, 'pea');
}
self.destroy();
for (var j = 0; j < peas.length; j++) {
if (peas[j] === self) {
peas.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen
if (self.x > 2200) {
self.destroy();
for (var k = 0; k < peas.length; k++) {
if (peas[k] === self) {
peas.splice(k, 1);
break;
}
}
}
};
return self;
});
var Peashooter = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('peashooter', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 100;
self.health = 100;
self.maxHealth = 100;
self.shootTimer = 0;
self.shootDelay = 90; // 1.5 seconds at 60fps
self.gridX = 0;
self.gridY = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
} else {
// Visual damage feedback
var damageRatio = self.health / self.maxHealth;
graphics.alpha = 0.3 + damageRatio * 0.7;
}
};
self.update = function () {
self.shootTimer++;
if (self.shootTimer >= self.shootDelay) {
// Check if there's a zombie in this lane
var hasZombieInLane = false;
for (var i = 0; i < zombies.length; i++) {
if (zombies[i].gridY === self.gridY && zombies[i].x > self.x) {
hasZombieInLane = true;
break;
}
}
if (hasZombieInLane) {
self.shoot();
self.shootTimer = 0;
}
}
};
self.shoot = function () {
var pea = new Pea();
pea.x = self.x + 60;
pea.y = self.y;
pea.gridY = self.gridY;
peas.push(pea);
game.addChild(pea);
LK.getSound('shoot').play();
};
return self;
});
var ReflectedFrozenPea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('frozenpea', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint dark red to show it's reflected
graphics.tint = 0xaa2222;
self.speed = -8; // Negative speed to go backwards
self.damage = 20; // Slightly more damage than regular frozen peas
self.gridY = 0;
self.update = function () {
self.x += self.speed;
// Check collision with plants
for (var i = 0; i < plants.length; i++) {
var plant = plants[i];
if (plant.gridY === self.gridY && self.intersects(plant)) {
if (plant.takeDamage) {
plant.takeDamage(self.damage);
}
self.destroy();
for (var j = 0; j < reflectedfrozenpeas.length; j++) {
if (reflectedfrozenpeas[j] === self) {
reflectedfrozenpeas.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen (left side)
if (self.x < -100) {
self.destroy();
for (var k = 0; k < reflectedfrozenpeas.length; k++) {
if (reflectedfrozenpeas[k] === self) {
reflectedfrozenpeas.splice(k, 1);
break;
}
}
}
};
return self;
});
var ReflectedPea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pea', {
anchorX: 0.5,
anchorY: 0.5
});
// Tint red to show it's reflected
graphics.tint = 0xff4444;
self.speed = -8; // Negative speed to go backwards
self.damage = 20; // Slightly more damage than regular peas
self.gridY = 0;
self.update = function () {
self.x += self.speed;
// Check collision with plants
for (var i = 0; i < plants.length; i++) {
var plant = plants[i];
if (plant.gridY === self.gridY && self.intersects(plant)) {
if (plant.takeDamage) {
plant.takeDamage(self.damage);
}
self.destroy();
for (var j = 0; j < reflectedpeas.length; j++) {
if (reflectedpeas[j] === self) {
reflectedpeas.splice(j, 1);
break;
}
}
return;
}
}
// Remove if off screen (left side)
if (self.x < -100) {
self.destroy();
for (var k = 0; k < reflectedpeas.length; k++) {
if (reflectedpeas[k] === self) {
reflectedpeas.splice(k, 1);
break;
}
}
}
};
return self;
});
var Repeater = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('repeater', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 200;
self.health = 100;
self.maxHealth = 100;
self.shootTimer = 0;
self.shootDelay = 90; // 1.5 seconds at 60fps
self.secondShotTimer = 0;
self.secondShotDelay = 15; // 0.25 seconds delay between shots
self.waitingForSecondShot = false;
self.gridX = 0;
self.gridY = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
} else {
// Visual damage feedback
var damageRatio = self.health / self.maxHealth;
graphics.alpha = 0.3 + damageRatio * 0.7;
}
};
self.update = function () {
// Handle second shot timing
if (self.waitingForSecondShot) {
self.secondShotTimer++;
if (self.secondShotTimer >= self.secondShotDelay) {
self.shoot(); // Fire second pea
self.waitingForSecondShot = false;
self.secondShotTimer = 0;
}
} else {
self.shootTimer++;
if (self.shootTimer >= self.shootDelay) {
// Check if there's a zombie in this lane
var hasZombieInLane = false;
for (var i = 0; i < zombies.length; i++) {
if (zombies[i].gridY === self.gridY && zombies[i].x > self.x) {
hasZombieInLane = true;
break;
}
}
if (hasZombieInLane) {
self.shoot(); // Fire first pea
self.waitingForSecondShot = true; // Queue second shot
self.shootTimer = 0;
}
}
}
};
self.shoot = function () {
var pea = new Pea();
pea.x = self.x + 60;
pea.y = self.y;
pea.gridY = self.gridY;
peas.push(pea);
game.addChild(pea);
LK.getSound('shoot').play();
};
return self;
});
var Snowshooter = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snowshooter', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 175;
self.health = 100;
self.maxHealth = 100;
self.shootTimer = 0;
self.shootDelay = 90; // 1.5 seconds at 60fps
self.gridX = 0;
self.gridY = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
} else {
// Visual damage feedback
var damageRatio = self.health / self.maxHealth;
graphics.alpha = 0.3 + damageRatio * 0.7;
}
};
self.update = function () {
self.shootTimer++;
if (self.shootTimer >= self.shootDelay) {
// Check if there's a zombie in this lane
var hasZombieInLane = false;
for (var i = 0; i < zombies.length; i++) {
if (zombies[i].gridY === self.gridY && zombies[i].x > self.x) {
hasZombieInLane = true;
break;
}
}
if (hasZombieInLane) {
self.shoot();
self.shootTimer = 0;
}
}
};
self.shoot = function () {
var frozenpea = new FrozenPea();
frozenpea.x = self.x + 60;
frozenpea.y = self.y;
frozenpea.gridY = self.gridY;
frozenpeas.push(frozenpea);
game.addChild(frozenpea);
LK.getSound('shoot').play();
};
return self;
});
var SplitPea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('splitpea', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 125;
self.health = 100;
self.maxHealth = 100;
self.shootTimer = 0;
self.shootDelay = 90; // 1.5 seconds at 60fps
self.gridX = 0;
self.gridY = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
} else {
// Visual damage feedback
var damageRatio = self.health / self.maxHealth;
graphics.alpha = 0.3 + damageRatio * 0.7;
}
};
self.update = function () {
self.shootTimer++;
if (self.shootTimer >= self.shootDelay) {
// Check if there's a zombie in this lane (both front and back)
var hasZombieInLane = false;
for (var i = 0; i < zombies.length; i++) {
if (zombies[i].gridY === self.gridY) {
hasZombieInLane = true;
break;
}
}
if (hasZombieInLane) {
self.shoot();
self.shootTimer = 0;
}
}
};
self.shoot = function () {
// Shoot one pea forward
var forwardPea = new Pea();
forwardPea.x = self.x + 60;
forwardPea.y = self.y;
forwardPea.gridY = self.gridY;
peas.push(forwardPea);
game.addChild(forwardPea);
// Shoot two peas backward
var backwardPea1 = new BackwardPea();
backwardPea1.x = self.x - 60;
backwardPea1.y = self.y - 20;
backwardPea1.gridY = self.gridY;
backwardpeas.push(backwardPea1);
game.addChild(backwardPea1);
var backwardPea2 = new BackwardPea();
backwardPea2.x = self.x - 60;
backwardPea2.y = self.y + 20;
backwardPea2.gridY = self.gridY;
backwardpeas.push(backwardPea2);
game.addChild(backwardPea2);
LK.getSound('shoot').play();
};
return self;
});
var Sun = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 25;
self.lifeTimer = 0;
self.maxLife = 600; // 10 seconds
self.update = function () {
self.lifeTimer++;
if (self.lifeTimer > self.maxLife) {
self.destroy();
for (var i = 0; i < suns.length; i++) {
if (suns[i] === self) {
suns.splice(i, 1);
break;
}
}
}
};
self.down = function (x, y, obj) {
sunPoints += self.value;
updateSunDisplay();
self.destroy();
for (var i = 0; i < suns.length; i++) {
if (suns[i] === self) {
suns.splice(i, 1);
break;
}
}
LK.getSound('collect').play();
};
return self;
});
var Sunflower = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('sunflower', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 50;
self.health = 100;
self.maxHealth = 100;
self.sunTimer = 0;
self.sunDelay = 600; // 10 seconds at 60fps
self.gridX = 0;
self.gridY = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
} else {
// Visual damage feedback
var damageRatio = self.health / self.maxHealth;
graphics.alpha = 0.3 + damageRatio * 0.7;
}
};
self.update = function () {
self.sunTimer++;
if (self.sunTimer >= self.sunDelay) {
self.produceSun();
self.sunTimer = 0;
}
};
self.produceSun = function () {
var sun = new Sun();
sun.x = self.x + (Math.random() - 0.5) * 50;
sun.y = self.y + (Math.random() - 0.5) * 50;
suns.push(sun);
game.addChild(sun);
};
return self;
});
var WallNut = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wallnut', {
anchorX: 0.5,
anchorY: 0.5
});
self.cost = 50;
self.health = 300;
self.maxHealth = 300;
self.gridX = 0;
self.gridY = 0;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.destroy();
for (var i = 0; i < plants.length; i++) {
if (plants[i] === self) {
plants.splice(i, 1);
break;
}
}
var gridKey = self.gridX + ',' + self.gridY;
delete plantGrid[gridKey];
} else {
// Visual damage feedback
var damageRatio = self.health / self.maxHealth;
graphics.alpha = 0.3 + damageRatio * 0.7;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x8BC34A
});
/****
* Game Code
****/
// Sounds
// Zombies
// Projectiles and collectibles
// Plants
// Game grid and UI elements
// Game variables
var sunPoints = 150;
var currentWave = 1;
var maxWaves = 20;
var waveTimer = 0;
var waveDelay = 1800; // 30 seconds
var zombieSpawnTimer = 0;
var zombieSpawnDelay = 240; // 4 seconds
var zombiesPerWave = 5;
var zombiesSpawned = 0;
var zombiesKilled = 0;
var totalZombiesToKill = 0;
var waveStarted = false;
var zombieSpawnQueue = [];
// Game arrays
var plants = [];
var zombies = [];
var peas = [];
var frozenpeas = [];
var reflectedpeas = [];
var reflectedfrozenpeas = [];
var backwardpeas = [];
var suns = [];
var plantGrid = {}; // Track occupied grid positions
// Grid settings
var gridStartX = 400;
var gridStartY = 400;
var gridWidth = 320;
var gridHeight = 227;
var gridCols = 5;
var gridRows = 5;
// Selected plant type
var selectedPlantType = null;
// Create lawn grid
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
var tile = game.addChild(LK.getAsset('grass', {
x: gridStartX + col * gridWidth,
y: gridStartY + row * gridHeight,
anchorX: 0,
anchorY: 0
}));
}
}
// Create paths (zombie lanes)
for (var lane = 0; lane < gridRows; lane++) {
var pathTile = game.addChild(LK.getAsset('path', {
x: gridStartX + gridCols * gridWidth,
y: gridStartY + lane * gridHeight,
anchorX: 0,
anchorY: 0
}));
}
// Create house
var house = game.addChild(LK.getAsset('house', {
x: 50,
y: gridStartY + gridRows * gridHeight / 2 - 200,
anchorX: 0,
anchorY: 0
}));
// UI Setup
var sunDisplay = new Text2(sunPoints.toString(), {
size: 80,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 3
});
sunDisplay.anchor.set(0, 0);
LK.gui.topLeft.addChild(sunDisplay);
sunDisplay.x = 120;
sunDisplay.y = 20;
var waveDisplay = new Text2('Wave: ' + currentWave + '/' + maxWaves, {
size: 60,
fill: 0x000000
});
waveDisplay.anchor.set(0.5, 0);
LK.gui.top.addChild(waveDisplay);
waveDisplay.y = 20;
// Plant selection buttons
var peashooterBtn = LK.getAsset('peashooter', {
x: 400,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(peashooterBtn);
var sunflowerBtn = LK.getAsset('sunflower', {
x: 650,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(sunflowerBtn);
var wallnutBtn = LK.getAsset('wallnut', {
x: 900,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(wallnutBtn);
var snowshooterBtn = LK.getAsset('snowshooter', {
x: 1150,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(snowshooterBtn);
var repeaterBtn = LK.getAsset('repeater', {
x: 1400,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(repeaterBtn);
var cherrypopperBtn = LK.getAsset('cherrypopper', {
x: 1650,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(cherrypopperBtn);
var splitpeaBtn = LK.getAsset('splitpea', {
x: 1900,
y: 2500,
scaleX: 0.8,
scaleY: 0.8,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(splitpeaBtn);
var shovelBtn = LK.getAsset('shovel', {
x: 1900,
y: 150,
scaleX: 1.5,
scaleY: 1.5,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(shovelBtn);
// Cost display texts
var peaCostTxt = new Text2('100', {
size: 70,
fill: 0x000000
});
peaCostTxt.anchor.set(0.5, 0);
game.addChild(peaCostTxt);
peaCostTxt.x = 400;
peaCostTxt.y = 2580;
var sunCostTxt = new Text2('50', {
size: 70,
fill: 0x000000
});
sunCostTxt.anchor.set(0.5, 0);
game.addChild(sunCostTxt);
sunCostTxt.x = 650;
sunCostTxt.y = 2580;
var wallCostTxt = new Text2('50', {
size: 70,
fill: 0x000000
});
wallCostTxt.anchor.set(0.5, 0);
game.addChild(wallCostTxt);
wallCostTxt.x = 900;
wallCostTxt.y = 2580;
var snowCostTxt = new Text2('175', {
size: 70,
fill: 0x000000
});
snowCostTxt.anchor.set(0.5, 0);
game.addChild(snowCostTxt);
snowCostTxt.x = 1150;
snowCostTxt.y = 2580;
var repeaterCostTxt = new Text2('200', {
size: 70,
fill: 0x000000
});
repeaterCostTxt.anchor.set(0.5, 0);
game.addChild(repeaterCostTxt);
repeaterCostTxt.x = 1400;
repeaterCostTxt.y = 2580;
var cherryCostTxt = new Text2('150', {
size: 70,
fill: 0x000000
});
cherryCostTxt.anchor.set(0.5, 0);
game.addChild(cherryCostTxt);
cherryCostTxt.x = 1650;
cherryCostTxt.y = 2580;
var splitpeaCostTxt = new Text2('125', {
size: 70,
fill: 0x000000
});
splitpeaCostTxt.anchor.set(0.5, 0);
game.addChild(splitpeaCostTxt);
splitpeaCostTxt.x = 1900;
splitpeaCostTxt.y = 2580;
var shovelCostTxt = new Text2('Free', {
size: 70,
fill: 0x000000
});
shovelCostTxt.anchor.set(0.5, 0);
game.addChild(shovelCostTxt);
shovelCostTxt.x = 1900;
shovelCostTxt.y = 230;
// Calculate total zombies for victory condition
for (var w = 1; w <= maxWaves; w++) {
totalZombiesToKill += zombiesPerWave + Math.floor(w / 2);
}
function updateSunDisplay() {
sunDisplay.setText(sunPoints.toString());
}
function getGridPosition(x, y) {
var col = Math.floor((x - gridStartX) / gridWidth);
var row = Math.floor((y - gridStartY) / gridHeight);
if (col >= 0 && col < gridCols && row >= 0 && row < gridRows) {
return {
col: col,
row: row,
x: gridStartX + col * gridWidth + gridWidth / 2,
y: gridStartY + row * gridHeight + gridHeight / 2
};
}
return null;
}
function spawnZombie() {
var lane = Math.floor(Math.random() * gridRows);
var zombieType = Math.random();
var zombie;
// Higher spawn rates for special zombies from wave 15 onwards
if (currentWave >= 15) {
if (zombieType < 0.25) {
zombie = new Gargantuar();
} else if (zombieType < 0.50) {
zombie = new Zomboni();
} else if (zombieType < 0.65) {
zombie = new JesterZombie();
} else if (zombieType < 0.75) {
zombie = new TankZombie();
} else if (zombieType < 0.80) {
zombie = new JackInBoxZombie();
} else if (zombieType < 0.86) {
zombie = new MinerZombie();
} else if (zombieType < 0.92) {
zombie = new FastZombie();
} else if (zombieType < 0.98) {
zombie = new NewspaperZombie();
} else {
zombie = new BasicZombie();
}
} else {
// Original spawn rates for waves before 15
if (currentWave > 8 && zombieType < 0.05) {
zombie = new Gargantuar();
} else if (currentWave > 6 && zombieType < 0.15) {
zombie = new Zomboni();
} else if (currentWave > 5 && zombieType < 0.25) {
zombie = new TankZombie();
} else if (currentWave > 4 && zombieType < 0.35) {
zombie = new JesterZombie();
} else if (currentWave > 2 && zombieType < 0.45) {
zombie = new JackInBoxZombie();
} else if (currentWave > 3 && zombieType < 0.60) {
zombie = new MinerZombie();
} else if (currentWave > 3 && zombieType < 0.75) {
zombie = new FastZombie();
} else if (currentWave > 1 && zombieType < 0.90) {
zombie = new NewspaperZombie();
} else {
zombie = new BasicZombie();
}
}
zombie.x = gridStartX + gridCols * gridWidth + 100;
zombie.y = gridStartY + lane * gridHeight + gridHeight / 2;
zombie.gridY = lane;
// Add spawn delay animation - zombie starts invisible and fades in
zombie.alpha = 0;
zombie.scaleX = 0.5;
zombie.scaleY = 0.5;
// Animate zombie spawning in
tween(zombie, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.easeOut
});
zombies.push(zombie);
game.addChild(zombie);
zombiesSpawned++;
}
function startNextWave() {
if (currentWave <= maxWaves) {
zombiesPerWave = 5 + Math.floor(currentWave / 2);
zombiesSpawned = 0;
waveStarted = false;
zombieSpawnQueue = [];
waveDisplay.setText('Wave: ' + currentWave + '/' + maxWaves);
// Change background color to dark blue from wave 11
if (currentWave >= 11) {
game.setBackgroundColor(0x191970); // Dark blue
}
// Flash screen red when wave increases
LK.effects.flashScreen(0xff0000, 1000);
// Add delay before wave actually starts spawning zombies
LK.setTimeout(function () {
waveStarted = true;
// Pre-queue zombie spawn times with delays
// Use faster spawn delay from wave 5 onwards, and even faster from wave 11
var currentSpawnDelay;
if (currentWave >= 11) {
currentSpawnDelay = 80; // Even faster from wave 11 (1.33 seconds)
} else if (currentWave >= 5) {
currentSpawnDelay = 120; // Faster from wave 5 (2 seconds)
} else {
currentSpawnDelay = zombieSpawnDelay; // Normal speed (4 seconds)
}
for (var i = 0; i < zombiesPerWave; i++) {
zombieSpawnQueue.push({
spawnTime: LK.ticks + i * currentSpawnDelay + Math.random() * 60,
// Add some randomness (reduced for faster waves)
spawned: false
});
}
}, 2000); // 2 second delay before wave starts
}
}
// Generate sun periodically
var sunGenerationTimer = 0;
var sunGenerationDelay = 480; // 8 seconds
// Event handlers
peashooterBtn.down = function () {
if (sunPoints >= 100) {
selectedPlantType = 'peashooter';
LK.effects.flashObject(peashooterBtn, 0x00ff00, 300);
}
};
sunflowerBtn.down = function () {
if (sunPoints >= 50) {
selectedPlantType = 'sunflower';
LK.effects.flashObject(sunflowerBtn, 0x00ff00, 300);
}
};
wallnutBtn.down = function () {
if (sunPoints >= 50) {
selectedPlantType = 'wallnut';
LK.effects.flashObject(wallnutBtn, 0x00ff00, 300);
}
};
snowshooterBtn.down = function () {
if (sunPoints >= 175) {
selectedPlantType = 'snowshooter';
LK.effects.flashObject(snowshooterBtn, 0x00ff00, 300);
}
};
repeaterBtn.down = function () {
if (sunPoints >= 200) {
selectedPlantType = 'repeater';
LK.effects.flashObject(repeaterBtn, 0x00ff00, 300);
}
};
cherrypopperBtn.down = function () {
if (sunPoints >= 150) {
selectedPlantType = 'cherrypopper';
LK.effects.flashObject(cherrypopperBtn, 0x00ff00, 300);
}
};
splitpeaBtn.down = function () {
if (sunPoints >= 125) {
selectedPlantType = 'splitpea';
LK.effects.flashObject(splitpeaBtn, 0x00ff00, 300);
}
};
shovelBtn.down = function () {
selectedPlantType = 'shovel';
LK.effects.flashObject(shovelBtn, 0x00ff00, 300);
};
game.down = function (x, y, obj) {
var gridPos = getGridPosition(x, y);
if (gridPos && selectedPlantType) {
var gridKey = gridPos.col + ',' + gridPos.row;
// Handle shovel - remove existing plant
if (selectedPlantType === 'shovel') {
if (plantGrid[gridKey]) {
var plantToRemove = plantGrid[gridKey];
// Remove from plants array
for (var i = 0; i < plants.length; i++) {
if (plants[i] === plantToRemove) {
plants.splice(i, 1);
break;
}
}
// Remove from grid
delete plantGrid[gridKey];
// Destroy the plant
plantToRemove.destroy();
selectedPlantType = null;
}
return;
}
// Check if position is already occupied
if (plantGrid[gridKey]) {
return;
}
var plant = null;
var cost = 0;
if (selectedPlantType === 'peashooter' && sunPoints >= 100) {
plant = new Peashooter();
cost = 100;
} else if (selectedPlantType === 'sunflower' && sunPoints >= 50) {
plant = new Sunflower();
cost = 50;
} else if (selectedPlantType === 'wallnut' && sunPoints >= 50) {
plant = new WallNut();
cost = 50;
} else if (selectedPlantType === 'snowshooter' && sunPoints >= 175) {
plant = new Snowshooter();
cost = 175;
} else if (selectedPlantType === 'repeater' && sunPoints >= 200) {
plant = new Repeater();
cost = 200;
} else if (selectedPlantType === 'cherrypopper' && sunPoints >= 150) {
plant = new CherryPopper();
cost = 150;
} else if (selectedPlantType === 'splitpea' && sunPoints >= 125) {
plant = new SplitPea();
cost = 125;
}
if (plant) {
plant.x = gridPos.x;
plant.y = gridPos.y;
plant.gridX = gridPos.col;
plant.gridY = gridPos.row;
plants.push(plant);
game.addChild(plant);
plantGrid[gridKey] = plant;
sunPoints -= cost;
updateSunDisplay();
selectedPlantType = null;
LK.getSound('plant').play();
}
}
};
game.update = function () {
// Generate sun periodically
sunGenerationTimer++;
if (sunGenerationTimer >= sunGenerationDelay) {
var sun = new Sun();
sun.x = 200 + Math.random() * 1600;
sun.y = 200 + Math.random() * 1000;
suns.push(sun);
game.addChild(sun);
sunGenerationTimer = 0;
}
// Wave management
if (currentWave <= maxWaves) {
waveTimer++;
// Spawn zombies for current wave using queue system
if (waveStarted && zombiesSpawned < zombiesPerWave) {
for (var i = 0; i < zombieSpawnQueue.length; i++) {
var queueItem = zombieSpawnQueue[i];
if (!queueItem.spawned && LK.ticks >= queueItem.spawnTime) {
spawnZombie();
queueItem.spawned = true;
break; // Only spawn one zombie per frame
}
}
}
// Start next wave
if (zombiesSpawned >= zombiesPerWave && zombies.length === 0) {
currentWave++;
if (currentWave <= maxWaves) {
startNextWave();
waveTimer = 0;
}
}
}
// Check victory condition
if (currentWave > maxWaves && zombies.length === 0) {
LK.showYouWin();
}
// Handle slow effects on zombies
for (var z = 0; z < zombies.length; z++) {
var zombie = zombies[z];
if (zombie.slowTimer) {
zombie.slowTimer--;
if (zombie.slowTimer <= 0) {
// Restore original speed
if (zombie.originalSpeed) {
zombie.speed = zombie.originalSpeed;
}
// Remove slow tint
tween(zombie, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
zombie.slowTimer = null;
}
}
}
// Update button availability
peashooterBtn.alpha = sunPoints >= 100 ? 1.0 : 0.5;
sunflowerBtn.alpha = sunPoints >= 50 ? 1.0 : 0.5;
wallnutBtn.alpha = sunPoints >= 50 ? 1.0 : 0.5;
snowshooterBtn.alpha = sunPoints >= 175 ? 1.0 : 0.5;
repeaterBtn.alpha = sunPoints >= 200 ? 1.0 : 0.5;
cherrypopperBtn.alpha = sunPoints >= 150 ? 1.0 : 0.5;
splitpeaBtn.alpha = sunPoints >= 125 ? 1.0 : 0.5;
shovelBtn.alpha = 1.0; // Shovel is always available
};
// Start first wave
startNextWave(); ===================================================================
--- original.js
+++ change.js
@@ -1348,12 +1348,12 @@
anchorY: 0.5
});
game.addChild(splitpeaBtn);
var shovelBtn = LK.getAsset('shovel', {
- x: 1024,
+ x: 1900,
y: 150,
- scaleX: 0.8,
- scaleY: 0.8,
+ scaleX: 1.5,
+ scaleY: 1.5,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(shovelBtn);
@@ -1419,9 +1419,9 @@
fill: 0x000000
});
shovelCostTxt.anchor.set(0.5, 0);
game.addChild(shovelCostTxt);
-shovelCostTxt.x = 1024;
+shovelCostTxt.x = 1900;
shovelCostTxt.y = 230;
// Calculate total zombies for victory condition
for (var w = 1; w <= maxWaves; w++) {
totalZombiesToKill += zombiesPerWave + Math.floor(w / 2);