User prompt
Yükseltmr seviyesi 5 e gelince maks olur ve daha Max yazar
User prompt
Fire machine machine gün ve fire trapi laser turretin sağına şekilde taşı hepi alt alta kalsın
User prompt
Hiçbir makine metni birbirine karışmamalı ve lazer taretinin yanında bulunmamalıdır.
User prompt
Fire trap yazı olan butonu machine gün yazısının sağına taşı
User prompt
increase the size of the machine gun
User prompt
Increase the size of the machine gun to be the same as the fire trap
User prompt
Add the same range of the fire trap to the assault rifle
User prompt
Make the size of the fire trap the same as the size of the assault rifle
User prompt
set all machine prices to 0
User prompt
No machine text should interfere with each other and should not be adjacent to the laser turret.
User prompt
Add a 1000 coin machine gun next to the laser turret and that machine gun will be fast and very powerful.
User prompt
remove transparency from roads and grass
User prompt
Make the road and grass more vibrant colors
User prompt
Create the grass tile to assets and set the background to this color
User prompt
make the background green
User prompt
Move the sell and upgrade and start wave buttons down a little bit
User prompt
move price text next to machine texts
User prompt
Go A little up all text
User prompt
leave some space between all machine text
User prompt
go To all the left
User prompt
Move the machines' text above the sell turret text
User prompt
Add all your machines on the sell turret text, just the machine and align them
User prompt
UI kısmında sağ altta bulunan tüm kule makineleri (Laser Turret, Missile Tower, Fire Blaster vs.) şu anda sağa sola kaymış ve hizasız duruyor. Hepsini tek bir dikey çizgi üzerinde, eşit aralıklarla, düzgün hizalanmış olacak şekilde yerleştir. Yazılar ve butonlar sola hizalı ve aynı hizada olacak. Aralarında eşit boşluk olsun, karışık ve dağınık görünmesin.
User prompt
UI kısmında sağ altta bulunan tüm kule makineleri (Laser Turret, Missile Tower, Fire Blaster vs.) şu anda sağa sola kaymış ve hizasız duruyor. Hepsini tek bir dikey çizgi üzerinde, eşit aralıklarla, düzgün hizalanmış olacak şekilde yerleştir. Yazılar ve butonlar sola hizalı ve aynı hizada olacak. Aralarında eşit boşluk olsun, karışık ve dağınık görünmesin.
User prompt
Oyunun alt kısmında listelenen kuleleri (Laser Gun, Missile Tower, Fire Blaster, Electric Field, Fire Machine, Fire Trap) sürükleyip sadece yol kenarındaki karelere yerleştirilebilecek şekilde yap. Oyuncu bu kuleleri seçip, üst kısımdaki haritada sadece geçerli yerlere koyabilsin
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BuildSpot = Container.expand(function () {
var self = Container.call(this);
var spotGraphics = self.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.isOccupied = false;
self.turret = null;
self.previewRange = null;
self.move = function (x, y, obj) {
if (self.isOccupied) return;
if (!self.previewRange) {
// Create preview range indicator
self.previewRange = self.addChild(LK.getAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.15,
tint: selectedTowerType === 'laser' ? 0x4444FF : selectedTowerType === 'machineGun' ? 0xFF6600 : selectedTowerType === 'missile' ? 0xFF4444 : selectedTowerType === 'fire' ? 0xFF8800 : selectedTowerType === 'fireMachine' ? 0xFF2200 : selectedTowerType === 'fireTrap' ? 0xFF4400 : 0xFFFF00,
scaleX: selectedTowerType === 'laser' ? 3.0 : selectedTowerType === 'machineGun' ? 4.0 : selectedTowerType === 'missile' ? 3.4 : selectedTowerType === 'fire' ? 3.6 : selectedTowerType === 'fireMachine' ? 5.0 : selectedTowerType === 'fireTrap' ? 4.0 : 4.4,
scaleY: selectedTowerType === 'laser' ? 3.0 : selectedTowerType === 'machineGun' ? 4.0 : selectedTowerType === 'missile' ? 3.4 : selectedTowerType === 'fire' ? 3.6 : selectedTowerType === 'fireMachine' ? 5.0 : selectedTowerType === 'fireTrap' ? 4.0 : 4.4
}));
}
};
self.up = function (x, y, obj) {
if (self.previewRange) {
self.previewRange.destroy();
self.previewRange = null;
}
};
self.down = function (x, y, obj) {
if (self.isOccupied) return;
if (currency < selectedTowerCost) return;
// Build turret
var turret = new Turret();
turret.x = self.x;
turret.y = self.y;
turret.towerType = selectedTowerType;
turret.cost = selectedTowerCost;
turret.updateTowerProperties(); // Update properties based on tower type
self.turret = turret;
self.isOccupied = true;
currency -= selectedTowerCost;
updateCurrencyDisplay();
turrets.push(turret);
game.addChild(turret);
// Hide build spot
spotGraphics.alpha = 0;
// Flash green when built with tower type color
var flashColor = selectedTowerType === 'laser' ? 0x4444FF : selectedTowerType === 'machineGun' ? 0xFF6600 : selectedTowerType === 'missile' ? 0xFF4444 : selectedTowerType === 'fire' ? 0xFF8800 : selectedTowerType === 'fireMachine' ? 0xFF2200 : selectedTowerType === 'fireTrap' ? 0xFF4400 : 0xFFFF00;
LK.effects.flashObject(turret, flashColor, 500);
};
return self;
});
var FireTrap = Container.expand(function () {
var self = Container.call(this);
var fireGraphics = self.attachAsset('fireTrap', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.damage = 80; // Increased immediate damage
self.burnDuration = 3000; // 3 seconds
self.lastDamage = 0;
self.damageRate = 20; // Faster damage rate - hits more frequently
// Add range indicator
self.rangeIndicator = self.addChild(LK.getAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.15,
tint: 0xFF4400,
scaleX: 8.0,
// 400 pixel range
scaleY: 8.0
}));
// Create fire effect animation
tween(fireGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(fireGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart animation loop
if (self.parent) {
tween(fireGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
}
});
}
});
self.update = function () {
// Check for zombies within firing range
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (zombie.isDead) continue;
var dx = zombie.x - self.x;
var dy = zombie.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
// Within firing range - deal immediate damage
self.lastDamage += speedMultiplier;
if (self.lastDamage >= self.damageRate) {
// Deal immediate damage every damage rate interval
zombie.takeDamage(self.damage);
self.lastDamage = 0;
// Create fire explosion effect at zombie location
var fireExplosion = game.addChild(LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: zombie.x,
y: zombie.y,
tint: 0xFF4400,
scaleX: 1.5,
scaleY: 1.5
}));
tween(fireExplosion, {
alpha: 0,
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 400,
onFinish: function onFinish() {
fireExplosion.destroy();
}
});
LK.getSound('explosion').play();
}
// Apply powerful burning effect for 5 seconds
if (!zombie.isBurning) {
zombie.isBurning = true;
zombie.burnTimer = 0;
zombie.burnDuration = 300; // 5 seconds at 60fps
zombie.burnDamage = 40; // Increased burn damage
// More intense visual burning effect
tween(zombie.children[0], {
tint: 0xFF2200
}, {
duration: 150,
onFinish: function onFinish() {
tween(zombie.children[0], {
tint: 0xFFFFFF
}, {
duration: 150,
onFinish: function onFinish() {
if (zombie.isBurning && zombie.parent) {
tween(zombie.children[0], {
tint: 0xFF2200
}, {
duration: 150,
onFinish: arguments.callee
});
}
}
});
}
});
// Add fire aura effect around burning zombie
var fireAura = zombie.addChild(LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0xFF4400,
scaleX: 1.2,
scaleY: 1.2
}));
tween(fireAura, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0.2
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (fireAura.parent) {
tween(fireAura, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.6
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
}
});
}
}
}
};
return self;
});
var Turret = Container.expand(function () {
var self = Container.call(this);
var turretGraphics = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 0.5
});
// Add range indicator (will be updated based on tower type)
self.rangeIndicator = self.addChild(LK.getAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.25,
tint: 0x4444FF,
scaleX: 4,
scaleY: 4
}));
// Add cross indicator (hidden by default)
self.crossIndicator = self.addChild(LK.getAsset('cross', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
rotation: Math.PI / 4 // 45 degrees to make it look like an X
}));
self.damage = 75;
self.range = 200;
self.fireRate = 15; // frames between shots
self.lastShot = 0;
self.target = null;
self.cost = 50;
self.sellPrice = 25; // 50% of cost back when sold
self.towerType = 'laser'; // Default type
self.upgradeLevel = 1; // Track upgrade level
self.upgradeCost = 50; // Cost to upgrade
self.updateTowerProperties = function () {
var upgradeMultiplier = 1 + (self.upgradeLevel - 1) * 0.5; // 50% increase per level
if (self.towerType === 'laser') {
self.range = 150 * upgradeMultiplier;
self.damage = 75 * upgradeMultiplier;
self.fireRate = Math.max(5, 15 - (self.upgradeLevel - 1) * 2); // Faster fire rate
self.rangeIndicator.tint = 0x4444FF;
self.rangeIndicator.scaleX = 3.0; // Keep visual size constant
self.rangeIndicator.scaleY = 3.0; // Keep visual size constant
self.sellPrice = Math.floor((50 + (self.upgradeLevel - 1) * 50) * 0.5); // 50% of total cost back
self.upgradeCost = 50 * self.upgradeLevel; // Increasing upgrade cost
} else if (self.towerType === 'missile') {
self.range = 170 * upgradeMultiplier;
self.damage = 120 * upgradeMultiplier;
self.fireRate = Math.max(8, 20 - (self.upgradeLevel - 1) * 3);
self.rangeIndicator.tint = 0xFF4444;
self.rangeIndicator.scaleX = 3.4; // Keep visual size constant
self.rangeIndicator.scaleY = 3.4; // Keep visual size constant
self.sellPrice = Math.floor((100 + (self.upgradeLevel - 1) * 100) * 0.5); // 50% of total cost back
self.upgradeCost = 100 * self.upgradeLevel;
} else if (self.towerType === 'fire') {
self.range = 180 * upgradeMultiplier;
self.damage = 90 * upgradeMultiplier;
self.fireRate = Math.max(4, 10 - (self.upgradeLevel - 1) * 2);
self.rangeIndicator.tint = 0xFF8800;
self.rangeIndicator.scaleX = 3.6; // Keep visual size constant
self.rangeIndicator.scaleY = 3.6; // Keep visual size constant
self.sellPrice = Math.floor((200 + (self.upgradeLevel - 1) * 200) * 0.5); // 50% of total cost back
self.upgradeCost = 200 * self.upgradeLevel;
} else if (self.towerType === 'electric') {
self.range = 220 * upgradeMultiplier;
self.damage = 60 * upgradeMultiplier;
self.fireRate = Math.max(6, 12 - (self.upgradeLevel - 1) * 2);
self.rangeIndicator.tint = 0xFFFF00;
self.rangeIndicator.scaleX = 4.4; // Keep visual size constant
self.rangeIndicator.scaleY = 4.4; // Keep visual size constant
self.sellPrice = Math.floor((300 + (self.upgradeLevel - 1) * 300) * 0.5); // 50% of total cost back
self.upgradeCost = 300 * self.upgradeLevel;
} else if (self.towerType === 'fireMachine') {
self.range = 250 * upgradeMultiplier;
self.damage = 200 * upgradeMultiplier;
self.fireRate = Math.max(3, 8 - (self.upgradeLevel - 1) * 2);
self.rangeIndicator.tint = 0xFF2200;
self.rangeIndicator.scaleX = 5.0; // Keep visual size constant
self.rangeIndicator.scaleY = 5.0; // Keep visual size constant
self.sellPrice = Math.floor((500 + (self.upgradeLevel - 1) * 500) * 0.5); // 50% of total cost back
self.upgradeCost = 500 * self.upgradeLevel;
} else if (self.towerType === 'machineGun') {
self.range = 200 * upgradeMultiplier;
self.damage = 300 * upgradeMultiplier;
self.fireRate = Math.max(2, 5 - (self.upgradeLevel - 1) * 1);
self.rangeIndicator.tint = 0xFF6600;
self.rangeIndicator.scaleX = 4.0; // Keep visual size constant
self.rangeIndicator.scaleY = 4.0; // Keep visual size constant
self.sellPrice = Math.floor((1000 + (self.upgradeLevel - 1) * 1000) * 0.5); // 50% of total cost back
self.upgradeCost = 1000 * self.upgradeLevel;
} else if (self.towerType === 'fireTrap') {
self.range = 400 * upgradeMultiplier;
self.damage = 50 * upgradeMultiplier;
self.fireRate = Math.max(10, 30 - (self.upgradeLevel - 1) * 5);
self.rangeIndicator.tint = 0xFF4400;
self.rangeIndicator.scaleX = 4.0; // Keep visual size constant
self.rangeIndicator.scaleY = 4.0; // Keep visual size constant
self.sellPrice = Math.floor((700 + (self.upgradeLevel - 1) * 700) * 0.5); // 50% of total cost back
self.upgradeCost = 700 * self.upgradeLevel;
}
};
self.towerType = 'laser'; // Default type
self.findTarget = function () {
var closestZombie = null;
var closestDistance = self.range;
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (zombie.isDead) continue;
var dx = zombie.x - self.x;
var dy = zombie.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestZombie = zombie;
}
}
return closestZombie;
};
self.shoot = function (target) {
// Direct damage to target without bullets
if (target && !target.isDead) {
target.takeDamage(self.damage);
// Create explosion effect at target location
var explosion = game.addChild(LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: target.x,
y: target.y
}));
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
explosion.destroy();
}
});
LK.getSound('explosion').play();
}
LK.getSound('shoot').play();
// Flash blue when shooting
LK.effects.flashObject(self, 0x4444ff, 200);
};
self.down = function (x, y, obj) {
if (placementMode) return; // Don't select turrets in placement mode
selectTurret(self);
}; //{1j_new}
self.update = function () {
// Skip shooting if turret is frozen
if (self.isFrozen) return;
self.lastShot += speedMultiplier;
if (self.lastShot >= self.fireRate) {
var target = self.findTarget();
if (target) {
self.shoot(target);
self.lastShot = 0;
}
}
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.speed = 1;
self.reward = 10;
self.pathIndex = 0;
self.targetX = 0;
self.targetY = 0;
self.isDead = false;
// Create health bar
self.healthBar = self.addChild(LK.getAsset('buildSpot', {
anchorX: 0,
anchorY: 0.5,
x: -25,
y: -40,
width: 50,
height: 6,
color: 0x44FF44
}));
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.isDead = true;
// Directly add currency without visual money drop
currency += self.reward;
updateCurrencyDisplay();
LK.getSound('zombieHit').play();
}
};
self.update = function () {
if (self.isDead) return;
// Move towards target continuously
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Always move towards target, no stopping threshold
if (distance > 0.1) {
var moveX = dx / distance * self.speed * speedMultiplier;
var moveY = dy / distance * self.speed * speedMultiplier;
self.x += moveX;
self.y += moveY;
}
// Check if we've reached or passed the current target
if (distance <= self.speed * speedMultiplier + 1) {
// Move to next path point immediately
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
// Reached end - damage base
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.isDead = true;
} else {
self.targetX = gamePath[self.pathIndex].x;
self.targetY = gamePath[self.pathIndex].y;
}
}
// Handle burning effect
if (self.isBurning) {
self.burnTimer += speedMultiplier;
if (self.burnTimer >= 60) {
// Burn damage every second
self.takeDamage(self.burnDamage);
self.burnTimer = 0;
}
// Stop burning after 5 seconds
if (self.burnTimer >= self.burnDuration) {
self.isBurning = false;
tween.stop(self.children[0], {
tint: true
});
self.children[0].tint = 0xFFFFFF;
}
}
// Handle freeze effect for levels 11 and 15
if (self.hasFreezeEffect && !self.freezeEffectUsed) {
self.freezeEffectCooldown += speedMultiplier;
// Use freeze effect when zombie is at half health or after 5 seconds
var healthPercent = self.health / self.maxHealth;
if (healthPercent <= 0.5 || self.freezeEffectCooldown >= 300) {
self.freezeEffectUsed = true;
activateZombieFreezeEffect();
// Add visual indication that zombie used freeze effect
var freezeIndicator = self.addChild(LK.getAsset('cross', {
anchorX: 0.5,
anchorY: 0.5,
y: -50,
tint: 0x00CCFF,
scaleX: 1.5,
scaleY: 1.5
}));
tween(freezeIndicator, {
alpha: 0,
y: -80,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 1000,
onFinish: function onFinish() {
if (freezeIndicator.parent) {
freezeIndicator.destroy();
}
}
});
}
}
// Update health bar if it exists
if (self.healthBar) {
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent;
self.healthBar.tint = healthPercent > 0.5 ? 0x44FF44 : healthPercent > 0.25 ? 0xFFFF44 : 0xFF4444;
}
};
return self;
});
var FlyingZombie = Zombie.expand(function () {
var self = Zombie.call(this);
// Mark as flying type
self.isFlying = true;
// Add flying visual indicator - wings or glow effect
var flyingIndicator = self.addChild(LK.getAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4,
tint: 0x00FFFF,
scaleX: 1.5,
scaleY: 0.8,
y: -10
}));
// Start floating animation
function startFloatingAnimation() {
tween(self, {
y: self.y - 15
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 15
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.parent && !self.isDead) {
startFloatingAnimation();
}
}
});
}
});
}
// Store the original update method from parent Zombie class
var originalUpdate = self.update;
self.update = function () {
if (self.isDead) return;
// Initialize flying zombie movement properties if not set
if (!self.flyingInitialized) {
self.flyingInitialized = true;
// Set initial target as the final destination
self.finalTargetX = gamePath[gamePath.length - 1].x;
self.finalTargetY = gamePath[gamePath.length - 1].y;
// Flying zombies move more directly but with some wandering
self.wanderAngle = Math.random() * Math.PI * 2;
self.wanderTimer = 0;
self.wanderChangeRate = 180; // Change direction every 3 seconds
}
// Flying zombie free movement logic
var dx = self.finalTargetX - self.x;
var dy = self.finalTargetY - self.y;
var distanceToTarget = Math.sqrt(dx * dx + dy * dy);
// Add wandering behavior to make movement more interesting
self.wanderTimer += speedMultiplier;
if (self.wanderTimer >= self.wanderChangeRate) {
self.wanderAngle += (Math.random() - 0.5) * 0.8; // Random direction change
self.wanderTimer = 0;
}
// Calculate movement with wandering
var wanderStrength = 0.3; // How much the zombie wanders vs goes direct
var directX = dx / distanceToTarget;
var directY = dy / distanceToTarget;
var wanderX = Math.cos(self.wanderAngle) * wanderStrength;
var wanderY = Math.sin(self.wanderAngle) * wanderStrength;
// Combine direct movement with wandering
var moveX = (directX * (1 - wanderStrength) + wanderX) * self.speed * speedMultiplier;
var moveY = (directY * (1 - wanderStrength) + wanderY) * self.speed * speedMultiplier;
// Apply movement
self.x += moveX;
self.y += moveY;
// Keep flying zombies within game bounds
if (self.x < 50) self.x = 50;
if (self.x > 1998) self.x = 1998;
if (self.y < 50) self.y = 50;
if (self.y > 2050) self.y = 2050;
// Check if reached the end
if (distanceToTarget <= 100) {
// Reached end - damage base
lives--;
updateLivesDisplay();
if (lives <= 0) {
LK.showGameOver();
}
self.isDead = true;
}
// Handle burning effect (same as regular zombies)
if (self.isBurning) {
self.burnTimer += speedMultiplier;
if (self.burnTimer >= 60) {
// Burn damage every second
self.takeDamage(self.burnDamage);
self.burnTimer = 0;
}
// Stop burning after 5 seconds
if (self.burnTimer >= self.burnDuration) {
self.isBurning = false;
tween.stop(self.children[0], {
tint: true
});
self.children[0].tint = 0xFFFFFF;
}
}
// Handle freeze effect for levels 11 and 15 (same as regular zombies)
if (self.hasFreezeEffect && !self.freezeEffectUsed) {
self.freezeEffectCooldown += speedMultiplier;
var healthPercent = self.health / self.maxHealth;
if (healthPercent <= 0.5 || self.freezeEffectCooldown >= 300) {
self.freezeEffectUsed = true;
activateZombieFreezeEffect();
var freezeIndicator = self.addChild(LK.getAsset('cross', {
anchorX: 0.5,
anchorY: 0.5,
y: -50,
tint: 0x00CCFF,
scaleX: 1.5,
scaleY: 1.5
}));
tween(freezeIndicator, {
alpha: 0,
y: -80,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 1000,
onFinish: function onFinish() {
if (freezeIndicator.parent) {
freezeIndicator.destroy();
}
}
});
}
}
// Update health bar if it exists
if (self.healthBar) {
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent;
self.healthBar.tint = healthPercent > 0.5 ? 0x44FF44 : healthPercent > 0.25 ? 0xFFFF44 : 0xFF4444;
}
// Start floating animation if not already started
if (!self.floatingStarted && self.parent) {
self.floatingStarted = true;
startFloatingAnimation();
}
// Add gentle rotation for flying effect
if (self.children[0]) {
self.children[0].rotation += 0.02 * speedMultiplier;
}
// Pulsing glow effect for flying indicator
if (flyingIndicator && flyingIndicator.parent) {
flyingIndicator.alpha = 0.4 + Math.sin(LK.ticks * 0.1) * 0.2;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var zombies = [];
var turrets = [];
var bullets = [];
var buildSpots = [];
var fireTraps = [];
var gamePath = [];
var currency = 100;
var lives = 10;
var wave = 1;
var zombiesSpawned = 0;
var zombiesToSpawn = 5;
var spawnTimer = 0;
var spawnRate = 120; // frames between spawns
var baseSpawnRate = 120; // Store base spawn rate
var waveActive = false;
var waveCompleted = false;
var selectedTowerType = 'laser';
var selectedTowerCost = 50;
// Create path points for zombies to follow - Shorter strategic path
gamePath = [{
x: 0,
y: 1366
}, {
x: 400,
y: 1366
}, {
x: 400,
y: 1000
}, {
x: 800,
y: 1000
}, {
x: 800,
y: 1500
}, {
x: 1200,
y: 1500
}, {
x: 1200,
y: 800
}, {
x: 1600,
y: 800
}, {
x: 1600,
y: 400
}, {
x: 1000,
y: 400
}, {
x: 1000,
y: 1800
}, {
x: 1400,
y: 1800
}, {
x: 2048,
y: 1800
}];
// Create visual path
for (var i = 0; i < gamePath.length - 1; i++) {
var start = gamePath[i];
var end = gamePath[i + 1];
var steps = Math.floor(Math.sqrt((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / 120);
for (var j = 0; j <= steps; j++) {
var t = j / steps;
var pathX = start.x + (end.x - start.x) * t;
var pathY = start.y + (end.y - start.y) * t;
var pathTile = game.addChild(LK.getAsset('path', {
anchorX: 0.5,
anchorY: 0.5,
x: pathX,
y: pathY,
alpha: 0.3
}));
}
}
// Build spots are no longer needed - turrets can be placed anywhere
// buildSpots array is kept for compatibility but not used
// UI Elements
var currencyTxt = new Text2('Money: $' + currency, {
size: 72,
fill: 0x00FFFF
});
currencyTxt.anchor.set(0, 0);
currencyTxt.x = 120; // Offset from left edge to avoid platform menu
currencyTxt.y = 100;
LK.gui.topLeft.addChild(currencyTxt);
// Add glowing effect to currency
LK.effects.flashObject(currencyTxt, 0x00FFFF, 2000);
var livesTxt = new Text2('Lives: ' + lives, {
size: 60,
fill: 0xFF4444
});
livesTxt.anchor.set(0, 0);
livesTxt.x = 120; // Offset from left edge to avoid platform menu
livesTxt.y = 20;
LK.gui.topLeft.addChild(livesTxt);
// Tower purchase menu at bottom left - vertical layout with consistent alignment
var towerMenuX = 120; // Left side position for tower menu
var towerMenuStartY = 1550; // Starting Y position - moved up to be above sell turret text
var towerMenuSpacing = 120; // Increased spacing between buttons
var laserTurretBtn = new Text2('Laser Turret\n$50', {
size: 48,
fill: 0x4444FF
});
laserTurretBtn.anchor.set(0, 0.5); // Left-aligned anchor
laserTurretBtn.x = towerMenuX;
laserTurretBtn.y = towerMenuStartY;
game.addChild(laserTurretBtn);
var missileLauncherBtn = new Text2('Missile Tower\n$100', {
size: 48,
fill: 0xFF4444
});
missileLauncherBtn.anchor.set(0, 0.5); // Left-aligned anchor
missileLauncherBtn.x = towerMenuX;
missileLauncherBtn.y = towerMenuStartY + towerMenuSpacing;
game.addChild(missileLauncherBtn);
var fireDroneBtn = new Text2('Fire Blaster\n$200', {
size: 48,
fill: 0xFF8800
});
fireDroneBtn.anchor.set(0, 0.5); // Left-aligned anchor
fireDroneBtn.x = towerMenuX;
fireDroneBtn.y = towerMenuStartY + towerMenuSpacing * 2;
game.addChild(fireDroneBtn);
var electricTrapBtn = new Text2('Electric Field\n$300', {
size: 48,
fill: 0xFFFF00
});
electricTrapBtn.anchor.set(0, 0.5); // Left-aligned anchor
electricTrapBtn.x = towerMenuX;
electricTrapBtn.y = towerMenuStartY + towerMenuSpacing * 3;
game.addChild(electricTrapBtn);
var fireMachineBtn = new Text2('Fire Machine\n$500', {
size: 48,
fill: 0xFF2200
});
fireMachineBtn.anchor.set(0, 0.5); // Left-aligned anchor
fireMachineBtn.x = towerMenuX;
fireMachineBtn.y = towerMenuStartY + towerMenuSpacing * 4;
game.addChild(fireMachineBtn);
var machineGunBtn = new Text2('Machine Gun\n$1000', {
size: 48,
fill: 0xFF6600
});
machineGunBtn.anchor.set(0, 0.5); // Left-aligned anchor
machineGunBtn.x = towerMenuX;
machineGunBtn.y = towerMenuStartY + towerMenuSpacing * 5;
game.addChild(machineGunBtn);
var fireTrapBtn = new Text2('Fire Trap\n$700', {
size: 48,
fill: 0xFF4400
});
fireTrapBtn.anchor.set(0, 0.5); // Left-aligned anchor
fireTrapBtn.x = towerMenuX;
fireTrapBtn.y = towerMenuStartY + towerMenuSpacing * 7;
game.addChild(fireTrapBtn);
var waveTxt = new Text2('Level ' + wave, {
size: 80,
fill: 0x44FF44
});
waveTxt.anchor.set(0.5, 0);
waveTxt.y = 20;
LK.gui.top.addChild(waveTxt);
// Bomb system
var bombsLeft = 3;
var bombTxt = new Text2('Bombs: ' + bombsLeft, {
size: 72,
fill: 0xFF0000
});
bombTxt.anchor.set(1, 0);
bombTxt.x = -20;
bombTxt.y = -80;
LK.gui.topRight.addChild(bombTxt);
var bombBtn = new Text2('💣 BOMB', {
size: 80,
fill: 0xFF4444
});
bombBtn.anchor.set(1, 1);
bombBtn.x = -20;
bombBtn.y = -20;
LK.gui.bottomRight.addChild(bombBtn);
var startWaveBtn = new Text2('START WAVE', {
size: 80,
fill: 0xFFFFFF
});
startWaveBtn.anchor.set(0.5, 0.5);
startWaveBtn.x = 500;
startWaveBtn.y = 2550;
game.addChild(startWaveBtn);
var sellBtn = new Text2('SELL\nTURRET\n$0', {
size: 64,
fill: 0xFFAA00
});
sellBtn.anchor.set(0.5, 0.5);
sellBtn.x = 300; // Position to the left
sellBtn.y = 2400; // Move down
sellBtn.alpha = 0.5; // Start dimmed
game.addChild(sellBtn);
var upgradeBtn = new Text2('UPGRADE\nTURRET\n$0', {
size: 64,
fill: 0x00FF00
});
upgradeBtn.anchor.set(0.5, 0.5);
upgradeBtn.x = 700; // Position to the right
upgradeBtn.y = 2400; // Same height as sell button - moved down
upgradeBtn.alpha = 0.5; // Start dimmed
game.addChild(upgradeBtn);
// Speed acceleration system
var gameSpeed = 1.0;
var speedMultiplier = 1.0;
// Speed acceleration buttons
var speed1xBtn = new Text2('1x Speed', {
size: 48,
fill: 0x00FF00
});
speed1xBtn.anchor.set(0.5, 0.5);
speed1xBtn.x = 1400;
speed1xBtn.y = 2180;
game.addChild(speed1xBtn);
var speed2xBtn = new Text2('2x Speed', {
size: 48,
fill: 0xFFFF00
});
speed2xBtn.anchor.set(0.5, 0.5);
speed2xBtn.x = 1400;
speed2xBtn.y = 2280;
game.addChild(speed2xBtn);
var speed3xBtn = new Text2('3x Speed', {
size: 48,
fill: 0xFF8800
});
speed3xBtn.anchor.set(0.5, 0.5);
speed3xBtn.x = 1400;
speed3xBtn.y = 2380;
game.addChild(speed3xBtn);
function distanceToLineSegment(px, py, x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
var length = Math.sqrt(dx * dx + dy * dy);
if (length === 0) return Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
var t = ((px - x1) * dx + (py - y1) * dy) / (length * length);
t = Math.max(0, Math.min(1, t));
var projX = x1 + t * dx;
var projY = y1 + t * dy;
return Math.sqrt((px - projX) * (px - projX) + (py - projY) * (py - projY));
}
function updateCurrencyDisplay() {
currencyTxt.setText('Money: $' + currency);
// Add glowing effect when currency changes
LK.effects.flashObject(currencyTxt, 0x00FFFF, 500);
}
function updateBombDisplay() {
bombTxt.setText('Bombs: ' + bombsLeft);
}
function useBomb() {
if (bombsLeft <= 0) return;
bombsLeft--;
updateBombDisplay();
// Create massive explosion effect
var bombExplosion = game.addChild(LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 10,
scaleY: 10,
alpha: 0.8
}));
// Damage all zombies significantly
for (var i = 0; i < zombies.length; i++) {
if (!zombies[i].isDead) {
zombies[i].takeDamage(150);
LK.effects.flashObject(zombies[i], 0xFF0000, 500);
}
}
// Animate explosion
tween(bombExplosion, {
alpha: 0,
scaleX: 15,
scaleY: 15
}, {
duration: 1000,
onFinish: function onFinish() {
bombExplosion.destroy();
}
});
LK.getSound('explosion').play();
LK.effects.flashScreen(0xFF4444, 800);
}
function updateLivesDisplay() {
livesTxt.setText('Lives: ' + lives);
}
function updateWaveDisplay() {
waveTxt.setText('Level ' + wave);
}
function startWave() {
if (waveActive) return;
waveActive = true;
waveCompleted = false;
zombiesSpawned = 0;
// Make first level easier with fewer zombies
if (wave === 1) {
zombiesToSpawn = 3; // Only 3 zombies for first wave
} else if (wave >= 9 && wave <= 10) {
zombiesToSpawn = 10; // Only 10 enemies for levels 9 and 10
} else if (wave >= 11) {
zombiesToSpawn = 12 + (wave - 11) * 2; // More enemies for levels 11-15
} else {
zombiesToSpawn = 5 + (wave - 1) * 2; // Adjusted formula for subsequent waves
}
spawnTimer = 0;
startWaveBtn.alpha = 0.3;
// Increase zombie health each wave, but start lower for first level
if (wave === 1) {
Zombie.prototype.baseHealth = 60; // Weaker zombies for first level
} else if (wave <= 5) {
Zombie.prototype.baseHealth = 100 + (wave - 1) * 35; // Adjusted for waves 2-5
} else if (wave <= 10) {
// After level 5, base health becomes extremely high for boss-level enemies
var levelBonus = wave - 5;
Zombie.prototype.baseHealth = 2000 + levelBonus * 800; // Extremely high base health after level 5 - boss-level
} else {
// Levels 11-15: Ultimate boss enemies with exponential health scaling
var levelBonus = wave - 10;
Zombie.prototype.baseHealth = 8000 + levelBonus * 2000; // Exponential health scaling for levels 11-15
}
}
function spawnZombie() {
if (zombiesSpawned >= zombiesToSpawn) return;
// Determine if this should be a flying zombie (30% chance for waves 10+)
var shouldBeFlyingZombie = wave >= 10 && Math.random() < 0.3;
var zombie = shouldBeFlyingZombie ? new FlyingZombie() : new Zombie();
zombie.x = gamePath[0].x;
zombie.y = gamePath[0].y;
zombie.targetX = gamePath[1].x;
zombie.targetY = gamePath[1].y;
// Make first level zombies weaker and slower
if (wave === 1) {
zombie.health = 60; // Much weaker for first level
zombie.speed = 1.2; // Faster for first level
zombie.reward = 15; // Higher reward for first level to help progression
} else if (wave <= 5) {
zombie.health = 100 + (wave - 1) * 35; // Adjusted for waves 2-5
zombie.speed = 1.5 + (wave - 1) * 0.4; // Faster for waves 2-5
zombie.reward = 10 + wave * 5;
} else {
// After level 5, enemies become extremely strong bosses
var levelBonus = wave - 5;
// Levels 9 and 10 have nearly indestructible enemies
if (wave >= 9 && wave <= 10) {
zombie.health = 15000 + levelBonus * 5000; // Massive health for levels 9-10
} else if (wave >= 11) {
// Levels 11-15: Ultimate boss enemies with exponential health
var ultimateBonus = wave - 10;
zombie.health = 25000 + ultimateBonus * 10000; // Exponential health for levels 11-15
// Add freeze effect for levels 11 and 15
if (wave === 11 || wave === 15) {
zombie.hasFreezeEffect = true;
zombie.freezeEffectUsed = false;
zombie.freezeEffectCooldown = 0;
}
} else {
zombie.health = 2000 + levelBonus * 800; // Extremely high health after level 5 - boss-level
}
zombie.speed = 2.5 + levelBonus * 0.3; // Reduced speed after level 5 - not too fast
zombie.reward = 100 + levelBonus * 50; // Much higher rewards for boss-level enemies
// After level 6, some enemies get speed boost
if (wave > 6) {
var shouldGetSpeedBoost = Math.random() < 0.4; // 40% chance for speed boost
if (shouldGetSpeedBoost) {
zombie.speed *= 1.8; // 80% speed increase for boosted enemies
zombie.hasSpeedBoost = true;
// Flying zombies get even more speed boost
if (zombie.isFlying) {
zombie.speed *= 1.3; // Additional 30% speed for flying zombies
zombie.children[0].tint = 0x00FFAA; // Turquoise tint for fast flying enemies
} else {
zombie.children[0].tint = 0xFF8800; // Orange tint for speed boost
}
// Add speed boost aura effect
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4,
tint: 0xFF8800,
scaleX: 1.8,
scaleY: 1.8
});
}
}
}
zombie.maxHealth = zombie.health;
// Add visual effects for higher levels but keep first level size
if (wave >= 5) {
// Add continuous glowing effect for boss-level enemies
LK.effects.flashObject(zombie, 0xFF0000, 2000);
// Keep zombie size same as first level - no scaling
zombie.children[0].scaleX = 1.0;
zombie.children[0].scaleY = 1.0;
// Different tint for flying zombies
if (zombie.isFlying) {
zombie.children[0].tint = 0x00FFFF; // Cyan tint for flying boss enemies
} else {
zombie.children[0].tint = 0xFF0000; // Deep red tint for boss enemies
}
// Add boss aura effect
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0xFF0000,
scaleX: 2.5,
scaleY: 2.5
});
// Add second layer boss effect for very high levels
if (wave >= 8) {
// Level 8+ enemies are EXTREMELY strong with maximum boss effects
if (wave >= 11) {
zombie.health *= 5.0; // 5x health for levels 11-15 - ultimate bosses
zombie.reward *= 10; // 10x rewards for these ultimate bosses
} else if (wave >= 9) {
zombie.health *= 3.0; // Triple health for levels 9-10 - nearly indestructible
zombie.reward *= 5; // 5x rewards for these ultimate bosses
} else {
zombie.health *= 1.5; // 50% more health on top of base boss health
zombie.reward *= 2; // Double rewards for these ultra-bosses
}
zombie.maxHealth = zombie.health;
// Maximum boss visual effects
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0xFFFF00,
scaleX: 4.0,
scaleY: 4.0
});
// Add third layer ultra-boss effect for level 8+
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4,
tint: 0xFF00FF,
scaleX: 3.5,
scaleY: 3.5
});
// Levels 9-15 get additional intimidating effects
if (wave >= 11) {
// Levels 11-15: Ultimate boss effects with rainbow aura
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
tint: 0xFF00FF,
scaleX: 6.0,
scaleY: 6.0
});
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
tint: 0x00FFFF,
scaleX: 5.5,
scaleY: 5.5
});
zombie.children[0].scaleX = 1.0; // Keep same size as first level
zombie.children[0].scaleY = 1.0; // Keep same size as first level
// Different tint for flying ultimate bosses
if (zombie.isFlying) {
zombie.children[0].tint = 0x00FFFF; // Cyan tint for flying ultimate bosses
// Add extra flying effects for ultimate flying bosses
LK.effects.flashObject(zombie, 0x00FFFF, 600);
} else {
zombie.children[0].tint = 0xFF00FF; // Magenta tint for ultimate bosses
}
// Multiple rainbow effects for ultimate bosses
LK.effects.flashObject(zombie, 0xFF00FF, 800);
LK.effects.flashObject(zombie, 0x00FFFF, 1000);
LK.effects.flashObject(zombie, 0xFFFF00, 1200);
} else if (wave >= 9) {
// Add fourth layer ultimate boss effect for levels 9-10
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
tint: 0x000000,
scaleX: 5.0,
scaleY: 5.0
});
// Add fifth layer ultimate boss effect for levels 9-10
zombie.attachAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7,
tint: 0xFFFFFF,
scaleX: 4.5,
scaleY: 4.5
});
// Keep them same size as first level
zombie.children[0].scaleX = 1.0;
zombie.children[0].scaleY = 1.0;
// Different tint for flying ultimate bosses
if (zombie.isFlying) {
zombie.children[0].tint = 0x00CCFF; // Light blue tint for flying ultimate bosses
} else {
zombie.children[0].tint = 0x000000; // Black tint for ultimate bosses
}
// Multiple continuous pulsing effects for ultimate bosses
LK.effects.flashObject(zombie, 0x000000, 1000);
LK.effects.flashObject(zombie, 0xFFFFFF, 1200);
} else {
// Keep them same size as first level
zombie.children[0].scaleX = 1.0;
zombie.children[0].scaleY = 1.0;
zombie.children[0].tint = 0x8B0000; // Dark red tint for ultra bosses
// Continuous pulsing effect for ultra bosses
LK.effects.flashObject(zombie, 0xFF00FF, 1500);
}
}
}
zombies.push(zombie);
game.addChild(zombie);
zombiesSpawned++;
}
function checkWaveComplete() {
if (!waveActive) return;
var aliveZombies = 0;
for (var i = 0; i < zombies.length; i++) {
if (!zombies[i].isDead) {
aliveZombies++;
}
}
if (zombiesSpawned >= zombiesToSpawn && aliveZombies === 0) {
waveActive = false;
waveCompleted = true;
wave++;
updateWaveDisplay();
currency += 50; // Wave completion bonus
updateCurrencyDisplay();
startWaveBtn.alpha = 1;
// Flash screen green for wave completion
LK.effects.flashScreen(0x44ff44, 1000);
// Check win condition
if (wave > 15) {
LK.showYouWin();
}
}
}
// Start wave button interaction
startWaveBtn.down = function (x, y, obj) {
startWave();
};
// Bomb button interaction
bombBtn.down = function (x, y, obj) {
useBomb();
};
// Sell button interaction
sellBtn.down = function (x, y, obj) {
sellTurret();
};
// Upgrade button interaction
upgradeBtn.down = function (x, y, obj) {
upgradeTurret();
};
// Tower selection highlighting
var selectedTowerBtn = laserTurretBtn;
function highlightSelectedTower() {
// Reset all tower buttons
laserTurretBtn.alpha = selectedTowerType === 'laser' ? 1.0 : 0.7;
machineGunBtn.alpha = selectedTowerType === 'machineGun' ? 1.0 : 0.7;
missileLauncherBtn.alpha = selectedTowerType === 'missile' ? 1.0 : 0.7;
fireDroneBtn.alpha = selectedTowerType === 'fire' ? 1.0 : 0.7;
electricTrapBtn.alpha = selectedTowerType === 'electric' ? 1.0 : 0.7;
fireMachineBtn.alpha = selectedTowerType === 'fireMachine' ? 1.0 : 0.7;
fireTrapBtn.alpha = selectedTowerType === 'fireTrap' ? 1.0 : 0.7;
// Add glow effect to selected tower
if (selectedTowerType === 'laser') {
LK.effects.flashObject(laserTurretBtn, 0x4444FF, 500);
} else if (selectedTowerType === 'machineGun') {
LK.effects.flashObject(machineGunBtn, 0xFF6600, 500);
} else if (selectedTowerType === 'missile') {
LK.effects.flashObject(missileLauncherBtn, 0xFF4444, 500);
} else if (selectedTowerType === 'fire') {
LK.effects.flashObject(fireDroneBtn, 0xFF8800, 500);
} else if (selectedTowerType === 'electric') {
LK.effects.flashObject(electricTrapBtn, 0xFFFF00, 500);
} else if (selectedTowerType === 'fireMachine') {
LK.effects.flashObject(fireMachineBtn, 0xFF2200, 500);
} else if (selectedTowerType === 'fireTrap') {
LK.effects.flashObject(fireTrapBtn, 0xFF4400, 500);
}
}
// Initial highlight
highlightSelectedTower();
// Speed button interactions
speed1xBtn.down = function (x, y, obj) {
speedMultiplier = 1.0;
highlightSelectedSpeed();
};
speed2xBtn.down = function (x, y, obj) {
speedMultiplier = 2.0;
highlightSelectedSpeed();
};
speed3xBtn.down = function (x, y, obj) {
speedMultiplier = 3.0;
highlightSelectedSpeed();
};
function highlightSelectedSpeed() {
// Reset all speed buttons
speed1xBtn.alpha = speedMultiplier === 1.0 ? 1.0 : 0.7;
speed2xBtn.alpha = speedMultiplier === 2.0 ? 1.0 : 0.7;
speed3xBtn.alpha = speedMultiplier === 3.0 ? 1.0 : 0.7;
// Add glow effect to selected speed
if (speedMultiplier === 1.0) {
LK.effects.flashObject(speed1xBtn, 0x00FF00, 500);
} else if (speedMultiplier === 2.0) {
LK.effects.flashObject(speed2xBtn, 0xFFFF00, 500);
} else if (speedMultiplier === 3.0) {
LK.effects.flashObject(speed3xBtn, 0xFF8800, 500);
}
}
// Initial speed highlight
highlightSelectedSpeed();
// Tower menu interactions
laserTurretBtn.down = function (x, y, obj) {
if (currency < 50) return; // Not enough money
selectedTowerType = 'laser';
selectedTowerCost = 50;
placementMode = true;
turretToPlace = {
type: 'laser',
cost: 50
};
highlightSelectedTower();
};
machineGunBtn.down = function (x, y, obj) {
if (currency < 1000) return; // Not enough money
selectedTowerType = 'machineGun';
selectedTowerCost = 1000;
placementMode = true;
turretToPlace = {
type: 'machineGun',
cost: 1000
};
highlightSelectedTower();
};
missileLauncherBtn.down = function (x, y, obj) {
if (currency < 100) return; // Not enough money
selectedTowerType = 'missile';
selectedTowerCost = 100;
placementMode = true;
turretToPlace = {
type: 'missile',
cost: 100
};
highlightSelectedTower();
};
fireDroneBtn.down = function (x, y, obj) {
if (currency < 200) return; // Not enough money
selectedTowerType = 'fire';
selectedTowerCost = 200;
placementMode = true;
turretToPlace = {
type: 'fire',
cost: 200
};
highlightSelectedTower();
};
electricTrapBtn.down = function (x, y, obj) {
if (currency < 300) return; // Not enough money
selectedTowerType = 'electric';
selectedTowerCost = 300;
placementMode = true;
turretToPlace = {
type: 'electric',
cost: 300
};
highlightSelectedTower();
};
fireMachineBtn.down = function (x, y, obj) {
if (currency < 500) return; // Not enough money
selectedTowerType = 'fireMachine';
selectedTowerCost = 500;
placementMode = true;
turretToPlace = {
type: 'fireMachine',
cost: 500
};
highlightSelectedTower();
};
fireTrapBtn.down = function (x, y, obj) {
if (currency < 700) return; // Not enough money
selectedTowerType = 'fireTrap';
selectedTowerCost = 700;
placementMode = true;
turretToPlace = {
type: 'fireTrap',
cost: 700
};
highlightSelectedTower();
};
var selectedTurret = null;
var placementMode = false;
var turretToPlace = null;
var frozenTurrets = [];
var freezeEffectActive = false;
var freezeEffectTimer = 0;
var freezeEffectDuration = 120; // 2 seconds at 60fps
function selectTurret(turret) {
// Deselect previous turret
if (selectedTurret) {
selectedTurret.rangeIndicator.alpha = 0.25;
// Hide cross indicator on previous turret
selectedTurret.crossIndicator.alpha = 0;
}
selectedTurret = turret;
// Highlight selected turret
selectedTurret.rangeIndicator.alpha = 0.5;
// Show cross indicator
selectedTurret.crossIndicator.alpha = 1.0;
sellBtn.alpha = 1.0; // Enable sell button
upgradeBtn.alpha = 1.0; // Enable upgrade button
// Update button texts with prices
sellBtn.setText('SELL\nTURRET\n$' + selectedTurret.sellPrice);
upgradeBtn.setText('UPGRADE\nLv.' + selectedTurret.upgradeLevel + ' → ' + (selectedTurret.upgradeLevel + 1) + '\n$' + selectedTurret.upgradeCost);
LK.effects.flashObject(selectedTurret, 0x00FF00, 300);
}
function deselectTurret() {
if (selectedTurret) {
selectedTurret.rangeIndicator.alpha = 0.25;
// Hide cross indicator
selectedTurret.crossIndicator.alpha = 0;
}
selectedTurret = null;
sellBtn.alpha = 0.5; // Disable sell button
upgradeBtn.alpha = 0.5; // Disable upgrade button
sellBtn.setText('SELL\nTURRET\n$0'); // Reset text
upgradeBtn.setText('UPGRADE\nTURRET\n$0'); // Reset text
}
function sellTurret() {
if (!selectedTurret) return;
// Give money back
currency += selectedTurret.sellPrice;
updateCurrencyDisplay();
// Remove turret from game
for (var i = turrets.length - 1; i >= 0; i--) {
if (turrets[i] === selectedTurret) {
turrets.splice(i, 1);
break;
}
}
selectedTurret.destroy();
// Flash green effect
LK.effects.flashScreen(0x00FF00, 300);
deselectTurret();
}
function upgradeTurret() {
if (!selectedTurret) return;
if (selectedTurret.upgradeLevel >= 5) return; // Max upgrade level
if (currency < selectedTurret.upgradeCost) return; // Not enough money
// Deduct cost
currency -= selectedTurret.upgradeCost;
updateCurrencyDisplay();
// Upgrade turret
selectedTurret.upgradeLevel++;
selectedTurret.updateTowerProperties();
// Update button texts with new prices
sellBtn.setText('SELL\nTURRET\n$' + selectedTurret.sellPrice);
upgradeBtn.setText('UPGRADE\nLv.' + selectedTurret.upgradeLevel + ' → ' + (selectedTurret.upgradeLevel + 1) + '\n$' + selectedTurret.upgradeCost);
// Visual effects
LK.effects.flashObject(selectedTurret, 0x00FFFF, 500);
// Change turret color based on upgrade level
if (selectedTurret.upgradeLevel >= 3) {
selectedTurret.children[0].tint = 0xFFFFFF; // White for high level
} else if (selectedTurret.upgradeLevel >= 2) {
selectedTurret.children[0].tint = 0xFFFF00; // Yellow for mid level
}
}
function activateZombieFreezeEffect() {
if (freezeEffectActive) return; // Already active
if (turrets.length === 0) return; // No turrets to freeze
// Randomly select up to 2 turrets to freeze
var availableTurrets = turrets.slice(); // Copy array
var turretsToFreeze = Math.min(2, availableTurrets.length);
frozenTurrets = [];
for (var i = 0; i < turretsToFreeze; i++) {
var randomIndex = Math.floor(Math.random() * availableTurrets.length);
var turretToFreeze = availableTurrets[randomIndex];
availableTurrets.splice(randomIndex, 1); // Remove from available list
frozenTurrets.push(turretToFreeze);
// Add freeze visual effect
turretToFreeze.isFrozen = true;
turretToFreeze.children[0].tint = 0x00CCFF; // Ice blue tint
// Add ice effect around turret
var iceEffect = turretToFreeze.addChild(LK.getAsset('buildSpot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0x00CCFF,
scaleX: 1.5,
scaleY: 1.5
}));
turretToFreeze.iceEffect = iceEffect;
// Flash effect
LK.effects.flashObject(turretToFreeze, 0x00CCFF, 300);
}
// Activate freeze effect
freezeEffectActive = true;
freezeEffectTimer = 0;
// Screen flash to indicate freeze effect
LK.effects.flashScreen(0x00CCFF, 500);
}
function updateFreezeEffect() {
if (!freezeEffectActive) return;
freezeEffectTimer += speedMultiplier;
if (freezeEffectTimer >= freezeEffectDuration) {
// Remove freeze effect
for (var i = 0; i < frozenTurrets.length; i++) {
var turret = frozenTurrets[i];
if (turret.parent) {
// Check if turret still exists
turret.isFrozen = false;
turret.children[0].tint = 0xFFFFFF; // Reset tint
if (turret.iceEffect) {
turret.iceEffect.destroy();
turret.iceEffect = null;
}
}
}
frozenTurrets = [];
freezeEffectActive = false;
freezeEffectTimer = 0;
}
}
// Game-wide click handler - enable turret placement when in placement mode
game.down = function (x, y, obj) {
// Check if click is in game area (not on UI elements)
if (y > 2300) return; // Don't place on bottom UI
if (placementMode && turretToPlace) {
// Check if position is too close to path
var tooCloseToPath = false;
for (var i = 0; i < gamePath.length - 1; i++) {
var start = gamePath[i];
var end = gamePath[i + 1];
var distance = distanceToLineSegment(x, y, start.x, start.y, end.x, end.y);
if (distance < 80) {
// Minimum distance from path
tooCloseToPath = true;
break;
}
}
if (tooCloseToPath) {
LK.effects.flashScreen(0xFF0000, 200); // Red flash for invalid placement
return;
}
// Check if position overlaps with existing turrets
var tooCloseToTurret = false;
for (var i = 0; i < turrets.length; i++) {
var turret = turrets[i];
var dx = turret.x - x;
var dy = turret.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
// Minimum distance between turrets
tooCloseToTurret = true;
break;
}
}
if (tooCloseToTurret) {
LK.effects.flashScreen(0xFF0000, 200); // Red flash for invalid placement
return;
}
if (turretToPlace.type === 'fireTrap') {
// Place fire trap (can be placed anywhere)
var fireTrap = new FireTrap();
fireTrap.x = x;
fireTrap.y = y;
currency -= turretToPlace.cost;
updateCurrencyDisplay();
fireTraps.push(fireTrap);
game.addChild(fireTrap);
// Flash orange when built
LK.effects.flashObject(fireTrap, 0xFF4400, 500);
} else {
// Place turret
var turret = new Turret();
turret.x = x;
turret.y = y;
turret.towerType = turretToPlace.type;
turret.cost = turretToPlace.cost;
turret.updateTowerProperties();
currency -= turretToPlace.cost;
updateCurrencyDisplay();
turrets.push(turret);
game.addChild(turret);
// Flash green when built
var flashColor = turretToPlace.type === 'laser' ? 0x4444FF : turretToPlace.type === 'machineGun' ? 0xFF6600 : turretToPlace.type === 'missile' ? 0xFF4444 : turretToPlace.type === 'fire' ? 0xFF8800 : turretToPlace.type === 'fireMachine' ? 0xFF2200 : 0xFFFF00;
LK.effects.flashObject(turret, flashColor, 500);
}
// Exit placement mode
placementMode = false;
turretToPlace = null;
} else {
// Deselect turret when clicking empty area
deselectTurret();
}
};
game.update = function () {
// Spawn zombies
if (waveActive && zombiesSpawned < zombiesToSpawn) {
spawnTimer += speedMultiplier;
// Adjust spawn rate based on wave - slower spawning for first level
var currentSpawnRate = wave === 1 ? baseSpawnRate * 1.5 : baseSpawnRate;
if (spawnTimer >= currentSpawnRate) {
spawnZombie();
spawnTimer = 0;
}
}
// Clean up dead zombies
for (var i = zombies.length - 1; i >= 0; i--) {
if (zombies[i].isDead) {
zombies[i].destroy();
zombies.splice(i, 1);
}
}
// Update freeze effect
updateFreezeEffect();
checkWaveComplete();
}; ===================================================================
--- original.js
+++ change.js
@@ -811,17 +811,17 @@
fill: 0xFF6600
});
machineGunBtn.anchor.set(0, 0.5); // Left-aligned anchor
machineGunBtn.x = towerMenuX;
-machineGunBtn.y = towerMenuStartY + towerMenuSpacing * 1;
+machineGunBtn.y = towerMenuStartY + towerMenuSpacing * 5;
game.addChild(machineGunBtn);
var fireTrapBtn = new Text2('Fire Trap\n$700', {
size: 48,
fill: 0xFF4400
});
fireTrapBtn.anchor.set(0, 0.5); // Left-aligned anchor
fireTrapBtn.x = towerMenuX;
-fireTrapBtn.y = towerMenuStartY + towerMenuSpacing * 6;
+fireTrapBtn.y = towerMenuStartY + towerMenuSpacing * 7;
game.addChild(fireTrapBtn);
var waveTxt = new Text2('Level ' + wave, {
size: 80,
fill: 0x44FF44