User prompt
make powershot no longer instant kill, powershot should now do 5 times normal shot damage
User prompt
increase all zombie move speed by 10% per wave
User prompt
fix enemies stop spawning after a certain wave
User prompt
make upgrade level for fire rate only increase fire rate by 10% per level
User prompt
set initial fire rate to 3 shots per second for normal shots and 25% or that for power shots
User prompt
set fire rate to calculate shots per second not ticks ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fire rate is way to fast
User prompt
do not reset persistent values on game initialization ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
fire rate is not calculating according to upgrades
User prompt
remove Reset all upgrade variables to 0 in game initialization
User prompt
set player fire rate = (1+firerateupgrade level)
User prompt
revert all persistent values to 0 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
reset game save ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
revert
User prompt
initialize all variables including permanent variables ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
set player fire rate = (5+firerateupgrade level)
User prompt
enlarge buttons until fire rate label fits entirely inside yellow button background space
User prompt
label new button in the same style as the max life button have the label say "FIRE RATE"
User prompt
create new button with a yellow background and black outline the same size as max life upgrade button, place it next to max life upgrade button with the same amount of space between them as the space between the maxlife button and the edge of the viewport
User prompt
give healthbar a black outline
User prompt
swap healthbar colors
User prompt
change zombie initial damage to 1
User prompt
make all zombies drop 1 zoin in addition to any other drops
User prompt
make hp/maxhp display occupy 75% of height of the healthbar
User prompt
make zoins autocollect the same as powerups
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AmmoBox = Container.expand(function () {
var self = Container.call(this);
var ammoGraphics = self.attachAsset('ammoBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.ammoAmount = 50;
self.spawnTime = LK.ticks;
self.lifespan = 600; // 10 seconds at 60fps
self.update = function () {
self.rotation += 0.02;
};
return self;
});
var AmmoPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('ammoPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.ammoAmount = 100;
self.spawnTime = LK.ticks;
self.lifespan = 600; // 10 seconds at 60fps
self.update = function () {
self.rotation += 0.02;
// Add pulsing effect
self.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 20;
self.damage = 10;
self.vx = 0;
self.vy = 0;
self.piercing = false;
self.killHit = false;
self.maxDistance = 800;
self.travelDistance = 0;
self.update = function () {
var moveX = self.vx;
var moveY = self.vy;
var distance = Math.sqrt(moveX * moveX + moveY * moveY);
self.travelDistance += distance;
self.x += moveX;
self.y += moveY;
};
return self;
});
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var healthGraphics = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 30;
self.spawnTime = LK.ticks;
self.lifespan = 600; // 10 seconds at 60fps
self.update = function () {
self.rotation += 0.02;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.fireRate = 10;
self.fireCooldown = 0;
self.moveSpeed = 5;
self.invulnerable = 0;
self.takeDamage = function (amount) {
if (self.invulnerable > 0) return;
self.health -= amount;
self.invulnerable = 60;
LK.getSound('playerHurt').play();
LK.effects.flashObject(self, 0xFF0000, 500);
if (self.health <= 0) {
self.health = 0;
return true;
}
return false;
};
self.heal = function (amount) {
self.health = Math.min(self.health + amount, self.maxHealth);
};
self.update = function () {
if (self.fireCooldown > 0) self.fireCooldown--;
if (self.invulnerable > 0) {
self.invulnerable--;
self.alpha = Math.floor(self.invulnerable / 5) % 2 ? 0.5 : 1;
}
};
return self;
});
var TripleShot = Container.expand(function () {
var self = Container.call(this);
var tripleShotGraphics = self.attachAsset('tripleShot', {
anchorX: 0.5,
anchorY: 0.5
});
self.spawnTime = LK.ticks;
self.lifespan = 600; // 10 seconds at 60fps
self.update = function () {
self.rotation += 0.02;
// Add pulsing effect
self.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var Zoin = Container.expand(function () {
var self = Container.call(this);
var zoinGraphics = self.attachAsset('zoin', {
anchorX: 0.5,
anchorY: 0.5
});
self.spawnTime = LK.ticks;
self.lifespan = 600; // 10 seconds at 60fps
self.update = function () {
self.rotation += 0.05;
// Add floating effect
self.y += Math.sin(LK.ticks * 0.1) * 0.3;
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 1.5;
var variation = self.baseSpeed * 0.25; // 25% variation
self.speed = self.baseSpeed + (Math.random() - 0.5) * 2 * variation; // Random between baseSpeed ± 25%
self.health = 20;
self.maxHealth = 20; // Store base health for wave scaling
self.damage = 1;
self.baseDamage = 1; // Store base damage for wave scaling
self.attackCooldown = 0;
self.isDead = false;
self.takeDamage = function (amount) {
if (self.isDead) return false;
self.health -= amount;
if (self.health <= 0) {
self.isDead = true;
LK.getSound('zombieHit').play();
return true;
}
zombieGraphics.tint = 0xFF0000;
tween(zombieGraphics, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
zombieGraphics.tint = 0xFFFFFF;
}
});
return false;
};
self.update = function () {
if (self.isDead) return;
if (self.attackCooldown > 0) self.attackCooldown--;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var player;
var zombies = [];
var bullets = [];
var pickups = [];
var wave = 1;
var zombiesPerWave = 5;
var zombiesSpawned = 0;
var zombiesKilled = 0;
var spawnTimer = 0;
var scoreMultiplier = 1;
var killStreak = 0;
var powerAmmo = 0;
var lastPowerUpSpawn = 0;
var killsSinceLastPowerUp = 0;
var powerUpList = ['ammoPowerUp', 'healthPack', 'ammoBox', 'tripleShot'];
var lastPowerUpType = null;
var hasTripleShot = false;
var tripleShotLevel = 0;
var maxTripleShotLevel = 5;
var zoins = storage.zoins || 0;
// Upgrade costs and levels - loaded from storage
var maxHealthUpgrades = storage.maxHealthUpgrades || 0;
var fireRateUpgrades = storage.fireRateUpgrades || 0;
var damageUpgrades = storage.damageUpgrades || 0;
var moveControl;
var moveStick;
var isDraggingMove = false;
// UI Elements
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0, 0);
waveText.x = 150;
LK.gui.topLeft.addChild(waveText);
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -150;
LK.gui.topRight.addChild(scoreText);
// Health bar black outline
var healthBarOutline = LK.getAsset('ammoBox', {
width: 1849,
height: 81,
anchorX: 0.5,
anchorY: 0
});
healthBarOutline.tint = 0x000000;
healthBarOutline.x = 1024;
healthBarOutline.y = 97;
game.addChildAt(healthBarOutline, 0);
// Health bar background
var healthBarBg = LK.getAsset('ammoBox', {
width: 1843,
height: 75,
anchorX: 0.5,
anchorY: 0
});
healthBarBg.tint = 0xFF0000;
healthBarBg.x = 1024;
healthBarBg.y = 100;
game.addChildAt(healthBarBg, 1);
// Health bar fill
var healthBarFill = LK.getAsset('ammoBox', {
width: 1843,
height: 75,
anchorX: 0.5,
anchorY: 0
});
healthBarFill.tint = 0x444444;
healthBarFill.x = 1024;
healthBarFill.y = 100;
game.addChildAt(healthBarFill, 2);
// Health text display
var healthText = new Text2('100/100', {
size: 56,
fill: 0xFFFFFF
});
healthText.anchor.set(0.5, 0.5);
healthText.x = 1024;
healthText.y = 137.5; // Center of health bar (100 + 75/2)
game.addChildAt(healthText, 3);
var powerAmmoText = new Text2('Power Ammo: 0', {
size: 45,
fill: 0xFFD700
});
powerAmmoText.anchor.set(1, 1);
powerAmmoText.x = -20;
powerAmmoText.y = -80;
LK.gui.bottomRight.addChild(powerAmmoText);
var zoinText = new Text2('Zoins: ' + zoins, {
size: 45,
fill: 0xFFD700
});
zoinText.anchor.set(1, 1);
zoinText.x = -20;
zoinText.y = -140;
LK.gui.bottomRight.addChild(zoinText);
// Initialize player
player = game.addChild(new Player());
player.maxHealth = (maxHealthUpgrades + 1) * 2;
player.health = player.maxHealth;
player.fireRate = 3 * Math.pow(1.1, fireRateUpgrades);
player.x = 1024;
player.y = 1366;
// Initialize controls
moveControl = LK.getAsset('moveControl', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
moveControl.x = 300;
moveControl.y = 2432;
game.addChild(moveControl);
moveStick = LK.getAsset('moveControl', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0
});
moveStick.x = moveControl.x;
moveStick.y = moveControl.y;
game.addChild(moveStick);
// Aim control removed - using automatic targeting
// Helper functions
function resetGame() {
// Reset wave and zombies
wave = 1;
zombiesPerWave = 5;
zombiesSpawned = 0;
zombiesKilled = 0;
spawnTimer = 0;
// Reset score and multipliers
LK.setScore(0);
scoreMultiplier = 1;
killStreak = 0;
killsSinceLastPowerUp = 0;
lastPowerUpSpawn = 0;
lastPowerUpType = null;
// Reset powerups
powerAmmo = 0;
hasTripleShot = false;
tripleShotLevel = 0;
// Reset player state with upgrades
player.maxHealth = (maxHealthUpgrades + 1) * 2;
player.health = player.maxHealth;
player.fireRate = 3 * Math.pow(1.1, fireRateUpgrades);
player.fireCooldown = 0;
player.invulnerable = 0;
player.alpha = 1;
// Clear all game objects
for (var i = zombies.length - 1; i >= 0; i--) {
zombies[i].destroy();
}
zombies = [];
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
bullets = [];
for (var i = pickups.length - 1; i >= 0; i--) {
pickups[i].destroy();
}
pickups = [];
// Update UI
waveText.setText('Wave: ' + wave);
scoreText.setText('Score: ' + LK.getScore());
// Update health bar
var healthPercent = player.health / player.maxHealth;
healthBarFill.width = 1843 * healthPercent;
healthText.setText(player.health + '/' + player.maxHealth);
powerAmmoText.setText('Power Ammo: ' + powerAmmo);
powerAmmoText.visible = false;
// Reset player position
player.x = 1024;
player.y = 1366;
}
function spawnZombie() {
var zombie = new Zombie();
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
zombie.x = Math.random() * 2048;
zombie.y = -50;
break;
case 1:
// Right
zombie.x = 2098;
zombie.y = Math.random() * 2732;
break;
case 2:
// Bottom
zombie.x = Math.random() * 2048;
zombie.y = 2782;
break;
case 3:
// Left
zombie.x = -50;
zombie.y = Math.random() * 2732;
break;
}
zombie.speed = zombie.baseSpeed * (1 + wave * 0.1) + (Math.random() - 0.5) * 2 * (zombie.baseSpeed * 0.25);
zombie.health += wave * 5;
zombie.damage += Math.floor(wave * 2); // Increase damage by 2 per wave
zombie.scaleX = 0;
zombie.scaleY = 0;
zombie.alpha = 0;
zombies.push(zombie);
game.addChild(zombie);
zombiesSpawned++;
// Animate zombie spawn
tween(zombie, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function spawnPickup(x, y) {
var shouldSpawn = false;
var pickup;
var powerUpType;
// Force powerup spawn if 50+ kills without powerup
if (killsSinceLastPowerUp >= 50) {
shouldSpawn = true;
// Create available powerup list excluding last spawned type
var availablePowerUps = powerUpList.slice();
if (lastPowerUpType !== null) {
var index = availablePowerUps.indexOf(lastPowerUpType);
if (index > -1) {
availablePowerUps.splice(index, 1);
}
}
powerUpType = availablePowerUps[Math.floor(Math.random() * availablePowerUps.length)];
if (powerUpType === 'ammoPowerUp') {
pickup = new AmmoPowerUp();
} else if (powerUpType === 'ammoBox') {
pickup = new AmmoBox();
} else if (powerUpType === 'tripleShot') {
pickup = new TripleShot();
} else {
pickup = new HealthPack();
}
lastPowerUpType = powerUpType;
killsSinceLastPowerUp = 0;
if (pickup instanceof AmmoPowerUp) {
lastPowerUpSpawn = LK.ticks;
}
} else if (Math.random() < 0.3) {
shouldSpawn = true;
var rand = Math.random();
if (rand < 0.1 && LK.ticks - lastPowerUpSpawn > 1800) {
pickup = new AmmoPowerUp();
powerUpType = 'ammoPowerUp';
lastPowerUpSpawn = LK.ticks;
killsSinceLastPowerUp = 0;
} else if (rand < 0.15 && LK.ticks - lastPowerUpSpawn > 1800) {
pickup = new TripleShot();
powerUpType = 'tripleShot';
lastPowerUpSpawn = LK.ticks;
killsSinceLastPowerUp = 0;
} else if (rand < 0.6) {
pickup = new AmmoBox();
powerUpType = 'ammoBox';
} else {
pickup = new HealthPack();
powerUpType = 'healthPack';
}
lastPowerUpType = powerUpType;
}
if (shouldSpawn) {
pickup.x = x;
pickup.y = y;
pickup.scaleX = 0;
pickup.scaleY = 0;
pickups.push(pickup);
game.addChild(pickup);
// Animate pickup spawn with bounce effect
tween(pickup, {
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.elasticOut
});
}
}
function fireBullet() {
// Convert shots per second to ticks between shots (60 ticks = 1 second)
var shotsPerSecond = powerAmmo > 0 ? player.fireRate * 0.25 : player.fireRate; // Power ammo shoots at 25% of normal rate
var ticksBetweenShots = Math.max(1, Math.floor(60 / shotsPerSecond)); // Ensure at least 1 tick between shots
if (player.fireCooldown > 0) return;
// Find closest zombie in range
var closestZombie = null;
var closestDistance = 500; // Maximum firing range
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
if (!zombie || zombie.isDead) continue;
var dx = zombie.x - player.x;
var dy = zombie.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestZombie = zombie;
}
}
// Only fire if there's a zombie in range
if (!closestZombie) return;
var dx = closestZombie.x - player.x;
var dy = closestZombie.y - player.y;
var angle = Math.atan2(dy, dx);
player.rotation = angle; // Rotate player to face target
// Create bullets based on triple shot level
var bulletCount = hasTripleShot ? 1 + tripleShotLevel * 2 : 1;
var angleOffsets = [0]; // Always include center bullet
if (hasTripleShot) {
// Add bullets in pairs at increasing angles
for (var level = 1; level <= tripleShotLevel; level++) {
var angleOffset = level * 10 * Math.PI / 180;
angleOffsets.push(-angleOffset); // Left bullet
angleOffsets.push(angleOffset); // Right bullet
}
}
for (var b = 0; b < bulletCount; b++) {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y;
bullet.damage = 10 + damageUpgrades * 5;
var bulletAngle = angle + angleOffsets[b];
bullet.vx = Math.cos(bulletAngle) * bullet.speed;
bullet.vy = Math.sin(bulletAngle) * bullet.speed;
bullet.rotation = bulletAngle;
if (powerAmmo > 0) {
bullet.piercing = true;
bullet.maxDistance = 1600; // 2x distance
bullet.damage = (10 + damageUpgrades * 5) * 5; // 5x normal damage
if (b === 0) powerAmmo--; // Only consume one power ammo per shot
// Visual effect for power bullet
tween(bullet, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100
});
bullet.tint = 0xFFD700;
} else {
bullet.maxDistance = 800;
}
bullets.push(bullet);
game.addChild(bullet);
}
player.fireCooldown = ticksBetweenShots;
LK.getSound('shoot').play();
}
;
// Event handlers
game.down = function (x, y, obj) {
// Prevent control stick activation in bottom 1/4 of viewport (below y = 2049)
if (y > 2049) return;
isDraggingMove = true;
// Move moveControl to click position
moveControl.x = x;
moveControl.y = y;
// Move moveStick to the same position (center of control)
moveStick.x = x;
moveStick.y = y;
// Show control stick with smooth animation
tween(moveControl, {
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
tween(moveStick, {
alpha: 0.6
}, {
duration: 200,
easing: tween.easeOut
});
};
game.move = function (x, y, obj) {
if (isDraggingMove) {
moveStick.x = Math.max(moveControl.x - 150, Math.min(moveControl.x + 150, x));
moveStick.y = Math.max(moveControl.y - 150, Math.min(moveControl.y + 150, y));
}
};
game.up = function (x, y, obj) {
if (isDraggingMove) {
isDraggingMove = false;
moveStick.x = moveControl.x;
moveStick.y = moveControl.y;
// Hide control stick with smooth animation
tween(moveControl, {
alpha: 0
}, {
duration: 150,
easing: tween.easeIn
});
tween(moveStick, {
alpha: 0
}, {
duration: 150,
easing: tween.easeIn
});
}
};
// Main game loop
game.update = function () {
// Player movement
if (isDraggingMove) {
var moveX = (moveStick.x - moveControl.x) / 150;
var moveY = (moveStick.y - moveControl.y) / 150;
player.x += moveX * player.moveSpeed;
player.y += moveY * player.moveSpeed;
player.x = Math.max(40, Math.min(2008, player.x));
player.y = Math.max(40, Math.min(2692, player.y));
}
// Auto-fire (fireBullet now handles range checking internally)
fireBullet();
// Spawn zombies
if (zombiesSpawned < zombiesPerWave) {
spawnTimer++;
if (spawnTimer > 60) {
spawnZombie();
spawnTimer = 0;
}
} else if (zombies.length === 0) {
// Force spawn a powerup if none spawned this wave
var powerupSpawnedThisWave = false;
for (var p = 0; p < pickups.length; p++) {
var pickup = pickups[p];
if (pickup instanceof AmmoPowerUp || pickup instanceof HealthPack || pickup instanceof AmmoBox || pickup instanceof TripleShot) {
powerupSpawnedThisWave = true;
break;
}
}
if (!powerupSpawnedThisWave) {
// Spawn a guaranteed powerup at a random location near the center
var guaranteedX = 1024 + (Math.random() - 0.5) * 800;
var guaranteedY = 1366 + (Math.random() - 0.5) * 800;
spawnPickup(guaranteedX, guaranteedY);
}
// Next wave
wave++;
zombiesPerWave = Math.min(5 + wave * 2, 30); // Cap at 30 zombies per wave to prevent performance issues
zombiesSpawned = 0;
zombiesKilled = 0;
spawnTimer = 0; // Reset spawn timer for new wave
waveText.setText('Wave: ' + wave);
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var zombie = zombies[i];
// Skip if zombie is undefined or dead
if (!zombie || zombie.isDead) continue;
// Move towards player
var dx = player.x - zombie.x;
var dy = player.y - zombie.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
zombie.x += dx / dist * zombie.speed;
zombie.y += dy / dist * zombie.speed;
zombie.rotation = Math.atan2(dy, dx);
}
// Check collision with player
if (zombie.intersects(player) && zombie.attackCooldown === 0) {
if (player.takeDamage(zombie.damage)) {
LK.showGameOver();
}
zombie.attackCooldown = 60;
killStreak = 0;
scoreMultiplier = 1;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet is off screen or traveled max distance
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782 || bullet.travelDistance > bullet.maxDistance) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with zombies
var bulletDestroyed = false;
for (var j = zombies.length - 1; j >= 0; j--) {
var zombie = zombies[j];
if (!zombie || zombie.isDead) continue;
if (bullet.intersects(zombie)) {
if (zombie.takeDamage(bullet.damage)) {
// Zombie died - add death animation
spawnPickup(zombie.x, zombie.y);
// Always drop 1 zoin when zombie dies
var zoin = new Zoin();
zoin.x = zombie.x;
zoin.y = zombie.y;
zoin.scaleX = 0;
zoin.scaleY = 0;
pickups.push(zoin);
game.addChild(zoin);
// Animate zoin spawn
tween(zoin, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
var zombieToRemove = zombie; // Capture zombie reference for closure
var zombieIndex = j; // Capture index for closure
tween(zombie, {
scaleX: 0,
scaleY: 0,
alpha: 0,
rotation: zombie.rotation + Math.PI
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
zombieToRemove.destroy();
// Remove from zombies array after animation
var currentIndex = zombies.indexOf(zombieToRemove);
if (currentIndex !== -1) {
zombies.splice(currentIndex, 1);
}
}
});
zombiesKilled++;
killStreak++;
killsSinceLastPowerUp++;
if (killStreak % 5 === 0) {
scoreMultiplier = Math.min(scoreMultiplier + 1, 5);
}
LK.setScore(LK.getScore() + 10 * scoreMultiplier);
scoreText.setText('Score: ' + LK.getScore());
}
if (!bullet.piercing) {
bullet.destroy();
bullets.splice(i, 1);
bulletDestroyed = true;
break;
}
}
}
if (bulletDestroyed) continue;
}
// Update pickups
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
// Check if pickup has expired (10 seconds) - auto pickup regardless of distance
var age = LK.ticks - pickup.spawnTime;
if (age >= pickup.lifespan) {
// Auto pickup all items when expiring
if (pickup instanceof HealthPack) {
player.heal(pickup.healAmount);
} else if (pickup instanceof AmmoBox) {
powerAmmo += pickup.ammoAmount;
LK.effects.flashObject(player, 0x228b22, 500);
} else if (pickup instanceof AmmoPowerUp) {
powerAmmo += pickup.ammoAmount;
LK.effects.flashObject(player, 0xFFD700, 500);
} else if (pickup instanceof TripleShot) {
if (!hasTripleShot) {
hasTripleShot = true;
tripleShotLevel = 1;
} else if (tripleShotLevel < maxTripleShotLevel) {
tripleShotLevel++;
}
LK.effects.flashObject(player, 0x00FF00, 500);
} else if (pickup instanceof Zoin) {
zoins++;
storage.zoins = zoins; // Persist zoin count
zoinText.setText('Zoins: ' + zoins);
LK.effects.flashObject(player, 0xFFD700, 300);
}
LK.getSound('pickup').play();
// Animate pickup collection
tween(pickup, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
pickup.destroy();
}
});
pickups.splice(i, 1);
continue;
}
// Manual pickup when touching
if (pickup.intersects(player)) {
if (pickup instanceof HealthPack) {
player.heal(pickup.healAmount);
} else if (pickup instanceof AmmoBox) {
powerAmmo += pickup.ammoAmount;
LK.effects.flashObject(player, 0x228b22, 500);
} else if (pickup instanceof AmmoPowerUp) {
powerAmmo += pickup.ammoAmount;
LK.effects.flashObject(player, 0xFFD700, 500);
} else if (pickup instanceof TripleShot) {
if (!hasTripleShot) {
hasTripleShot = true;
tripleShotLevel = 1;
} else if (tripleShotLevel < maxTripleShotLevel) {
tripleShotLevel++;
}
LK.effects.flashObject(player, 0x00FF00, 500);
} else if (pickup instanceof Zoin) {
zoins++;
storage.zoins = zoins; // Persist zoin count
zoinText.setText('Zoins: ' + zoins);
LK.effects.flashObject(player, 0xFFD700, 300);
}
LK.getSound('pickup').play();
// Animate pickup collection
tween(pickup, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
pickup.destroy();
}
});
pickups.splice(i, 1);
}
}
// Update UI
// Update health bar
var healthPercent = player.health / player.maxHealth;
healthBarFill.width = 1843 * healthPercent;
healthText.setText(player.health + '/' + player.maxHealth);
powerAmmoText.setText('Power Ammo: ' + powerAmmo);
// Hide/show power ammo counter based on availability
powerAmmoText.visible = powerAmmo > 0;
// Update button state based on zoin availability
var currentPrice = (1 + maxHealthUpgrades) * 2;
if (zoins < currentPrice) {
bottomLeftButton.alpha = 0.5; // Dim button when unaffordable
lifeLabel.alpha = 0.5;
priceLabel.alpha = 0.5;
} else {
bottomLeftButton.alpha = 1.0; // Full opacity when affordable
lifeLabel.alpha = 1.0;
priceLabel.alpha = 1.0;
}
// Update fire rate button state based on zoin availability
var fireRateCurrentPrice = (1 + fireRateUpgrades) * 3;
if (zoins < fireRateCurrentPrice) {
secondButton.alpha = 0.5; // Dim button when unaffordable
fireRateLabel.alpha = 0.5;
fireRatePriceLabel.alpha = 0.5;
} else {
secondButton.alpha = 1.0; // Full opacity when affordable
fireRateLabel.alpha = 1.0;
fireRatePriceLabel.alpha = 1.0;
}
// Despawn distant pickups
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
var dx = player.x - pickup.x;
var dy = player.y - pickup.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 2000) {
pickup.destroy();
pickups.splice(i, 1);
}
}
};
// Create bottom left button
var bottomLeftButton = LK.getAsset('ammoBox', {
width: 250,
height: 100,
anchorX: 0,
anchorY: 1
});
bottomLeftButton.tint = 0xFF0000; // Red background
bottomLeftButton.x = 20;
bottomLeftButton.y = -20;
LK.gui.bottomLeft.addChild(bottomLeftButton);
// Create black outline for button
var buttonOutline = LK.getAsset('ammoBox', {
width: 256,
height: 106,
anchorX: 0,
anchorY: 1
});
buttonOutline.tint = 0x000000; // Black outline
buttonOutline.x = 17;
buttonOutline.y = -17;
LK.gui.bottomLeft.addChildAt(buttonOutline, 0); // Add behind the button
// Create LIFE label for button
var lifeLabel = new Text2('LIFE', {
size: 36,
fill: 0xFFFFFF,
font: "'Arial Black'"
});
lifeLabel.anchor.set(0.5, 0.5);
lifeLabel.x = 145; // Center of button (250/2 + 20 offset for button position)
lifeLabel.y = -70; // Center of button (100/2 + 20 offset for button position)
LK.gui.bottomLeft.addChild(lifeLabel);
// Create price label for button with dynamic pricing
var maxLifePrice = (1 + maxHealthUpgrades) * 2;
var priceLabel = new Text2(maxLifePrice + ' Zoin' + (maxLifePrice === 1 ? '' : 's'), {
size: 24,
fill: 0xFFD700
});
priceLabel.anchor.set(0.5, 1);
priceLabel.x = 145; // Center of button horizontally
priceLabel.y = -25; // Bottom of button
LK.gui.bottomLeft.addChild(priceLabel);
// Make button interactive
bottomLeftButton.buttonMode = true;
// Add button click handlers
bottomLeftButton.down = function (x, y, obj) {
var currentPrice = (1 + maxHealthUpgrades) * 2;
if (zoins < currentPrice) {
return; // Don't allow clicking if insufficient zoins
}
// Change to white when pressed
tween(bottomLeftButton, {
tint: 0xFFFFFF
}, {
duration: 100,
easing: tween.easeOut
});
};
bottomLeftButton.up = function (x, y, obj) {
var currentPrice = (1 + maxHealthUpgrades) * 2;
if (zoins < currentPrice) {
return; // Don't allow clicking if insufficient zoins
}
// Deduct cost from zoins
zoins = zoins - currentPrice;
storage.zoins = zoins; // Persist updated zoin count
zoinText.setText('Zoins: ' + zoins);
// Increment upgrade level
maxHealthUpgrades++;
storage.maxHealthUpgrades = maxHealthUpgrades; // Persist upgrade level
// Update player max health
player.maxHealth = (maxHealthUpgrades + 1) * 2;
player.health = player.maxHealth; // Full heal on upgrade
// Update health bar to reflect new maximum
var healthPercent = player.health / player.maxHealth;
healthBarFill.width = 1843 * healthPercent;
healthText.setText(player.health + '/' + player.maxHealth);
// Update price label with new cost
var newPrice = (1 + maxHealthUpgrades) * 2;
priceLabel.setText(newPrice + ' Zoin' + (newPrice === 1 ? '' : 's'));
// Change back to red when released
tween(bottomLeftButton, {
tint: 0xFF0000
}, {
duration: 100,
easing: tween.easeOut
});
};
// Create second button next to the max life button
var secondButton = LK.getAsset('ammoBox', {
width: 250,
height: 100,
anchorX: 0,
anchorY: 1
});
secondButton.tint = 0xFFFF00; // Yellow background
secondButton.x = 290; // Position next to max life button (20 + 250 + 20 space = 290)
secondButton.y = -20;
LK.gui.bottomLeft.addChild(secondButton);
// Create black outline for second button
var secondButtonOutline = LK.getAsset('ammoBox', {
width: 256,
height: 106,
anchorX: 0,
anchorY: 1
});
secondButtonOutline.tint = 0x000000; // Black outline
secondButtonOutline.x = 287; // Position outline behind second button
secondButtonOutline.y = -17;
LK.gui.bottomLeft.addChildAt(secondButtonOutline, 0); // Add behind the button
// Create FIRE RATE label for second button
var fireRateLabel = new Text2('FIRE RATE', {
size: 36,
fill: 0xFFFFFF,
font: "'Arial Black'"
});
fireRateLabel.anchor.set(0.5, 0.5);
fireRateLabel.x = 415; // Center of second button (250/2 + 290 offset for button position)
fireRateLabel.y = -70; // Center of button (100/2 + 20 offset for button position)
LK.gui.bottomLeft.addChild(fireRateLabel);
// Create price label for second button with dynamic pricing
var fireRatePrice = (1 + fireRateUpgrades) * 3;
var fireRatePriceLabel = new Text2(fireRatePrice + ' Zoin' + (fireRatePrice === 1 ? '' : 's'), {
size: 24,
fill: 0xFFD700
});
fireRatePriceLabel.anchor.set(0.5, 1);
fireRatePriceLabel.x = 415; // Center of second button horizontally
fireRatePriceLabel.y = -25; // Bottom of button
LK.gui.bottomLeft.addChild(fireRatePriceLabel);
// Make second button interactive
secondButton.buttonMode = true;
// Add second button click handlers
secondButton.down = function (x, y, obj) {
var currentPrice = (1 + fireRateUpgrades) * 3;
if (zoins < currentPrice) {
return; // Don't allow clicking if insufficient zoins
}
// Change to white when pressed
tween(secondButton, {
tint: 0xFFFFFF
}, {
duration: 100,
easing: tween.easeOut
});
};
secondButton.up = function (x, y, obj) {
var currentPrice = (1 + fireRateUpgrades) * 3;
if (zoins < currentPrice) {
return; // Don't allow clicking if insufficient zoins
}
// Deduct cost from zoins
zoins = zoins - currentPrice;
storage.zoins = zoins; // Persist updated zoin count
zoinText.setText('Zoins: ' + zoins);
// Increment upgrade level
fireRateUpgrades++;
storage.fireRateUpgrades = fireRateUpgrades; // Persist upgrade level
// Update player fire rate
player.fireRate = 3 * Math.pow(1.1, fireRateUpgrades);
// Update price label with new cost
var newPrice = (1 + fireRateUpgrades) * 3;
fireRatePriceLabel.setText(newPrice + ' Zoin' + (newPrice === 1 ? '' : 's'));
// Change back to yellow when released
tween(secondButton, {
tint: 0xFFFF00
}, {
duration: 100,
easing: tween.easeOut
});
};
// Start music
LK.playMusic('battleMusic');
; ===================================================================
--- original.js
+++ change.js
@@ -533,11 +533,10 @@
bullet.vy = Math.sin(bulletAngle) * bullet.speed;
bullet.rotation = bulletAngle;
if (powerAmmo > 0) {
bullet.piercing = true;
- bullet.killHit = true;
bullet.maxDistance = 1600; // 2x distance
- bullet.damage = 1000; // 1 hit kill
+ bullet.damage = (10 + damageUpgrades * 5) * 5; // 5x normal damage
if (b === 0) powerAmmo--; // Only consume one power ammo per shot
// Visual effect for power bullet
tween(bullet, {
scaleX: 1.5,