User prompt
add player voice when lose health
User prompt
add zombies voice
User prompt
fix bugs
User prompt
zombie3 less health
User prompt
add zombie4 1.5x health
User prompt
add zombie4 health
User prompt
add zombie4 little health
User prompt
add zombie2 more health
User prompt
add zombie2 2x health
User prompt
Play a sound when firing the pistol.
User prompt
add pistol voice
User prompt
add background music
User prompt
true bullet count
User prompt
remove bullet count color rainbow
User prompt
bullet count is rainbow
User prompt
add bullet count right bottom visible
User prompt
bullets count remove
User prompt
reverse
User prompt
Written on a stop plate. bullets count visible
User prompt
bullets count text Written on a plate.
User prompt
Please fix the bug: 'tween.to is not a function' in or related to this line: 'tween.to(scoreTxt, {' Line Number: 226 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
score color is rainbow
User prompt
bullet count colour is yellow
User prompt
bullet count colour is green
User prompt
bullets count at the right bottom side
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); // Attach bullet asset (yellow box) var bulletSprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 32; self.damage = 1; self.update = function () { self.x += self.speed; }; return self; }); // LootBox class var LootBox = Container.expand(function () { var self = Container.call(this); // Attach lootbox asset (orange ellipse) var lootSprite = self.attachAsset('lootbox', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'ammo'; // 'ammo', 'medkit', 'money' self.value = 1; self.speed = 2.5; self.update = function () { self.x -= self.speed; }; return self; }); // Player class (stationary) var Player = Container.expand(function () { var self = Container.call(this); // Attach player asset (red box) var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Gun barrel position (relative to player) self.getGunPos = function () { // Gun at right edge, center vertically return { x: self.x + playerSprite.width / 2, y: self.y }; }; return self; }); // Zombie class var Zombie = Container.expand(function (style) { var self = Container.call(this); // Default to style 1 if not provided if (typeof style !== "number" || style < 1 || style > 4) style = 1; var zombieAssetId = "zombie" + style; // Attach zombie asset (varied style) var zombieSprite = self.attachAsset(zombieAssetId, { anchorX: 0.5, anchorY: 1 }); // Set up stats self.maxHealth = 1; self.health = 1; self.speed = 2; self.reward = 10; // money for killing // Health bar var healthBar = self.addChild(LK.getAsset('zombieHealthBar', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 10, color: 0xff0000 })); healthBar.y = -zombieSprite.height + 10; // Update health bar self.updateHealthBar = function () { healthBar.width = 60 * (self.health / self.maxHealth); }; // Called every tick self.update = function () { self.x -= self.speed; // Health bar follows self.updateHealthBar(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // --- Asset Initialization --- // Add background image (centered, covers full game area) var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, width: 2048, height: 2732 }); game.addChild(background); // --- Game State --- var player = null; var bullets = []; var zombies = []; var lootboxes = []; var ammo = 10; var maxAmmo = 10; var health = 5; var maxHealth = 5; var level = 1; var zombiesToSpawn = 0; var zombiesSpawned = 0; var zombiesKilled = 0; var spawnTimer = 0; var reloadTimer = 0; var isReloading = false; var weaponIndex = 0; // --- Zombie Speed Scaling --- var zombieBaseSpeedMin = 2.0; var zombieBaseSpeedMax = 2.5; var zombieSpeedIncreasePerMinute = 0.5; // total increase per minute var zombieMaxSpeed = 4.0; // maximum allowed zombie speed var gameStartTick = null; // will be set at game start var weapons = [{ name: "Pistol", damage: 1, ammo: 20, // doubled from 10 reload: 60, bulletSpeed: 18, color: 0xf7e12b }, { name: "SMG", damage: 1, ammo: 40, // doubled from 20 reload: 40, bulletSpeed: 20, color: 0x00bfff }, { name: "Shotgun", damage: 3, ammo: 10, // doubled from 5 reload: 90, bulletSpeed: 14, color: 0xffffff }]; var unlockedWeapons = 1; // Start with 1 weapon // --- UI Elements --- // Weapon name text (top center, above score) var weaponNameTxt = new Text2('', { size: 70, fill: "#fff" }); weaponNameTxt.anchor.set(0.5, 1); weaponNameTxt.x = LK.gui.top.width / 2; weaponNameTxt.y = 0; LK.gui.top.addChild(weaponNameTxt); var scoreTxt = new Text2('Score: 0', { size: 100, fill: "#fff" }); // Place score at true top center scoreTxt.anchor.set(0.5, 0); // Position: top center scoreTxt.x = LK.gui.top.width / 2; scoreTxt.y = 0; LK.gui.top.addChild(scoreTxt); // Money UI removed var ammoTxt = new Text2('Ammo: 10 / 10', { size: 60, fill: "#fff" }); ammoTxt.anchor.set(0, 0); LK.gui.bottomLeft.addChild(ammoTxt); // Bullet count text (numbers) var bulletCountTxt = new Text2('Bullets: 10', { size: 60, fill: "#fff" }); // Anchor bottom right bulletCountTxt.anchor.set(1, 1); // Place at right bottom of the screen (HUD) bulletCountTxt.x = LK.gui.bottomRight.width; bulletCountTxt.y = LK.gui.bottomRight.height; LK.gui.bottomRight.addChild(bulletCountTxt); var healthTxt = new Text2('♥♥♥♥♥', { size: 100, fill: 0xFF4D4D }); healthTxt.anchor.set(0, 1); healthTxt.x = 20; healthTxt.y = -10; LK.gui.bottomLeft.addChild(healthTxt); // --- Helper Functions --- function updateUI() { scoreTxt.setText('Score: ' + zombiesKilled); ammoTxt.setText('Ammo: ' + ammo + ' / ' + maxAmmo); bulletCountTxt.setText('Bullets: ' + ammo); var hearts = ''; for (var i = 0; i < health; i++) hearts += '♥'; for (var i = health; i < maxHealth; i++) hearts += '♡'; healthTxt.setText(hearts); // Show weapon name if (weapons && weapons[weaponIndex]) { weaponNameTxt.setText(weapons[weaponIndex].name); } else { weaponNameTxt.setText(''); } } function startLevel(lvl) { // No level or wave logic needed zombiesKilled = 0; spawnTimer = 0; } function spawnZombie() { // Pick a random zombie style (1-4) var zombieStyle = 1 + Math.floor(Math.random() * 4); var z = new Zombie(zombieStyle); // Position at right edge, random y z.x = 2048 + 80; z.y = 400 + Math.floor(Math.random() * (2732 - 800)); // Set fixed health and slow speed for zombies (health halved) z.maxHealth = 1.5; z.health = z.maxHealth; // --- Calculate elapsed minutes since game start --- var elapsedTicks = gameStartTick !== null ? LK.ticks - gameStartTick : 0; var elapsedMinutes = elapsedTicks / (60 * 60); // 60 ticks per second * 60 seconds // --- Calculate speed increase --- var speedIncrease = zombieSpeedIncreasePerMinute * elapsedMinutes; var minSpeed = zombieBaseSpeedMin + speedIncrease; var maxSpeed = zombieBaseSpeedMax + speedIncrease; // --- Clamp to max speed --- if (minSpeed > zombieMaxSpeed) minSpeed = zombieMaxSpeed; if (maxSpeed > zombieMaxSpeed) maxSpeed = zombieMaxSpeed; // --- Assign speed within range --- z.speed = minSpeed + Math.random() * (maxSpeed - minSpeed); zombies.push(z); game.addChild(z); } function spawnLootBox(x, y) { var loot = new LootBox(); loot.x = x; loot.y = y; // Randomize type var r = Math.random(); if (r < 0.5) { loot.type = 'ammo'; loot.value = 5 + Math.floor(Math.random() * 5); } else { loot.type = 'medkit'; loot.value = 1; } lootboxes.push(loot); game.addChild(loot); } // --- Game Setup --- player = new Player(); player.x = 180; player.y = 2732 / 2; game.addChild(player); // --- Input Handling --- var lastShotTick = 0; var dragNode = null; // Mouse/touch move: aim gun game.move = function (x, y, obj) { // No drag, just aiming // Optionally, could rotate gun sprite, but for now, just use for shooting }; // Mouse/touch down: shoot game.down = function (x, y, obj) { // Only shoot if not reloading if (isReloading) return; if (ammo <= 0) { // Start reload isReloading = true; reloadTimer = 0; return; } // Fire bullet var gunPos = player.getGunPos(); var b = new Bullet(); b.x = gunPos.x; b.y = gunPos.y; // Aim: calculate angle to (x, y) var dx = x - gunPos.x; var dy = y - gunPos.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; b.speed = weapons[weaponIndex].bulletSpeed; b.damage = weapons[weaponIndex].damage; // Set bullet direction b.vx = b.speed * (dx / dist); b.vy = b.speed * (dy / dist); // Overwrite update to use vx/vy b.update = function () { b.x += b.vx; b.y += b.vy; }; bullets.push(b); game.addChild(b); ammo--; updateUI(); }; // Mouse/touch up: nothing game.up = function (x, y, obj) {}; // --- Weapon Switching removed (no weapon name or tap to switch) --- // --- Main Game Loop --- game.update = function () { // --- Spawning zombies continuously --- spawnTimer++; if (spawnTimer > 55) { spawnZombie(); spawnTimer = 0; } // --- Bullets update --- for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); // Remove if off screen if (b.x > 2048 + 100 || b.y < -100 || b.y > 2732 + 100) { b.destroy(); bullets.splice(i, 1); continue; } // Check collision with zombies var bulletDestroyed = false; for (var j = zombies.length - 1; j >= 0; j--) { var z = zombies[j]; if (b.intersects(z)) { z.health -= b.damage; if (z.health <= 0) { // Zombie dies zombiesKilled++; // Only spawn a lootbox 30% of the time if (Math.random() < 0.3) { spawnLootBox(z.x, z.y - 40); } z.destroy(); zombies.splice(j, 1); } b.destroy(); bullets.splice(i, 1); bulletDestroyed = true; break; } } if (bulletDestroyed) continue; // Check collision with lootboxes (shoot to open) for (var k = lootboxes.length - 1; k >= 0; k--) { var l = lootboxes[k]; if (b.intersects(l)) { // Open lootbox and grant reward if (l.type === 'ammo') { ammo += l.value; if (ammo > maxAmmo) ammo = maxAmmo; } else if (l.type === 'medkit') { health += l.value; if (health > maxHealth) health = maxHealth; } // Increase score when shooting and opening a lootbox zombiesKilled++; l.destroy(); lootboxes.splice(k, 1); b.destroy(); bullets.splice(i, 1); bulletDestroyed = true; break; } } if (bulletDestroyed) continue; } // --- Zombies update --- for (var i = zombies.length - 1; i >= 0; i--) { var z = zombies[i]; z.update(); // If zombie reaches player if (z.x < player.x + 60) { // Damage player (reduced by half) health -= 0.5; LK.effects.flashObject(player, 0xff0000, 400); z.destroy(); zombies.splice(i, 1); if (health <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } // --- Lootboxes update --- for (var i = lootboxes.length - 1; i >= 0; i--) { var l = lootboxes[i]; l.update(); // If off screen if (l.x < -100) { l.destroy(); lootboxes.splice(i, 1); continue; } // No automatic pickup; lootboxes must be shot to open } // --- Reloading --- if (isReloading) { reloadTimer++; if (reloadTimer > weapons[weaponIndex].reload) { isReloading = false; ammo = maxAmmo; updateUI(); } } // No level progression or waves updateUI(); }; // --- Start Game --- ammo = weapons[weaponIndex].ammo; maxAmmo = weapons[weaponIndex].ammo; health = maxHealth; zombiesKilled = 0; unlockedWeapons = 1; weaponIndex = 0; gameStartTick = LK.ticks; // Track when the game started for zombie speed scaling startLevel(1); updateUI();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
// Attach bullet asset (yellow box)
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 32;
self.damage = 1;
self.update = function () {
self.x += self.speed;
};
return self;
});
// LootBox class
var LootBox = Container.expand(function () {
var self = Container.call(this);
// Attach lootbox asset (orange ellipse)
var lootSprite = self.attachAsset('lootbox', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'ammo'; // 'ammo', 'medkit', 'money'
self.value = 1;
self.speed = 2.5;
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Player class (stationary)
var Player = Container.expand(function () {
var self = Container.call(this);
// Attach player asset (red box)
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Gun barrel position (relative to player)
self.getGunPos = function () {
// Gun at right edge, center vertically
return {
x: self.x + playerSprite.width / 2,
y: self.y
};
};
return self;
});
// Zombie class
var Zombie = Container.expand(function (style) {
var self = Container.call(this);
// Default to style 1 if not provided
if (typeof style !== "number" || style < 1 || style > 4) style = 1;
var zombieAssetId = "zombie" + style;
// Attach zombie asset (varied style)
var zombieSprite = self.attachAsset(zombieAssetId, {
anchorX: 0.5,
anchorY: 1
});
// Set up stats
self.maxHealth = 1;
self.health = 1;
self.speed = 2;
self.reward = 10; // money for killing
// Health bar
var healthBar = self.addChild(LK.getAsset('zombieHealthBar', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 10,
color: 0xff0000
}));
healthBar.y = -zombieSprite.height + 10;
// Update health bar
self.updateHealthBar = function () {
healthBar.width = 60 * (self.health / self.maxHealth);
};
// Called every tick
self.update = function () {
self.x -= self.speed;
// Health bar follows
self.updateHealthBar();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// --- Asset Initialization ---
// Add background image (centered, covers full game area)
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
game.addChild(background);
// --- Game State ---
var player = null;
var bullets = [];
var zombies = [];
var lootboxes = [];
var ammo = 10;
var maxAmmo = 10;
var health = 5;
var maxHealth = 5;
var level = 1;
var zombiesToSpawn = 0;
var zombiesSpawned = 0;
var zombiesKilled = 0;
var spawnTimer = 0;
var reloadTimer = 0;
var isReloading = false;
var weaponIndex = 0;
// --- Zombie Speed Scaling ---
var zombieBaseSpeedMin = 2.0;
var zombieBaseSpeedMax = 2.5;
var zombieSpeedIncreasePerMinute = 0.5; // total increase per minute
var zombieMaxSpeed = 4.0; // maximum allowed zombie speed
var gameStartTick = null; // will be set at game start
var weapons = [{
name: "Pistol",
damage: 1,
ammo: 20,
// doubled from 10
reload: 60,
bulletSpeed: 18,
color: 0xf7e12b
}, {
name: "SMG",
damage: 1,
ammo: 40,
// doubled from 20
reload: 40,
bulletSpeed: 20,
color: 0x00bfff
}, {
name: "Shotgun",
damage: 3,
ammo: 10,
// doubled from 5
reload: 90,
bulletSpeed: 14,
color: 0xffffff
}];
var unlockedWeapons = 1; // Start with 1 weapon
// --- UI Elements ---
// Weapon name text (top center, above score)
var weaponNameTxt = new Text2('', {
size: 70,
fill: "#fff"
});
weaponNameTxt.anchor.set(0.5, 1);
weaponNameTxt.x = LK.gui.top.width / 2;
weaponNameTxt.y = 0;
LK.gui.top.addChild(weaponNameTxt);
var scoreTxt = new Text2('Score: 0', {
size: 100,
fill: "#fff"
});
// Place score at true top center
scoreTxt.anchor.set(0.5, 0);
// Position: top center
scoreTxt.x = LK.gui.top.width / 2;
scoreTxt.y = 0;
LK.gui.top.addChild(scoreTxt);
// Money UI removed
var ammoTxt = new Text2('Ammo: 10 / 10', {
size: 60,
fill: "#fff"
});
ammoTxt.anchor.set(0, 0);
LK.gui.bottomLeft.addChild(ammoTxt);
// Bullet count text (numbers)
var bulletCountTxt = new Text2('Bullets: 10', {
size: 60,
fill: "#fff"
});
// Anchor bottom right
bulletCountTxt.anchor.set(1, 1);
// Place at right bottom of the screen (HUD)
bulletCountTxt.x = LK.gui.bottomRight.width;
bulletCountTxt.y = LK.gui.bottomRight.height;
LK.gui.bottomRight.addChild(bulletCountTxt);
var healthTxt = new Text2('♥♥♥♥♥', {
size: 100,
fill: 0xFF4D4D
});
healthTxt.anchor.set(0, 1);
healthTxt.x = 20;
healthTxt.y = -10;
LK.gui.bottomLeft.addChild(healthTxt);
// --- Helper Functions ---
function updateUI() {
scoreTxt.setText('Score: ' + zombiesKilled);
ammoTxt.setText('Ammo: ' + ammo + ' / ' + maxAmmo);
bulletCountTxt.setText('Bullets: ' + ammo);
var hearts = '';
for (var i = 0; i < health; i++) hearts += '♥';
for (var i = health; i < maxHealth; i++) hearts += '♡';
healthTxt.setText(hearts);
// Show weapon name
if (weapons && weapons[weaponIndex]) {
weaponNameTxt.setText(weapons[weaponIndex].name);
} else {
weaponNameTxt.setText('');
}
}
function startLevel(lvl) {
// No level or wave logic needed
zombiesKilled = 0;
spawnTimer = 0;
}
function spawnZombie() {
// Pick a random zombie style (1-4)
var zombieStyle = 1 + Math.floor(Math.random() * 4);
var z = new Zombie(zombieStyle);
// Position at right edge, random y
z.x = 2048 + 80;
z.y = 400 + Math.floor(Math.random() * (2732 - 800));
// Set fixed health and slow speed for zombies (health halved)
z.maxHealth = 1.5;
z.health = z.maxHealth;
// --- Calculate elapsed minutes since game start ---
var elapsedTicks = gameStartTick !== null ? LK.ticks - gameStartTick : 0;
var elapsedMinutes = elapsedTicks / (60 * 60); // 60 ticks per second * 60 seconds
// --- Calculate speed increase ---
var speedIncrease = zombieSpeedIncreasePerMinute * elapsedMinutes;
var minSpeed = zombieBaseSpeedMin + speedIncrease;
var maxSpeed = zombieBaseSpeedMax + speedIncrease;
// --- Clamp to max speed ---
if (minSpeed > zombieMaxSpeed) minSpeed = zombieMaxSpeed;
if (maxSpeed > zombieMaxSpeed) maxSpeed = zombieMaxSpeed;
// --- Assign speed within range ---
z.speed = minSpeed + Math.random() * (maxSpeed - minSpeed);
zombies.push(z);
game.addChild(z);
}
function spawnLootBox(x, y) {
var loot = new LootBox();
loot.x = x;
loot.y = y;
// Randomize type
var r = Math.random();
if (r < 0.5) {
loot.type = 'ammo';
loot.value = 5 + Math.floor(Math.random() * 5);
} else {
loot.type = 'medkit';
loot.value = 1;
}
lootboxes.push(loot);
game.addChild(loot);
}
// --- Game Setup ---
player = new Player();
player.x = 180;
player.y = 2732 / 2;
game.addChild(player);
// --- Input Handling ---
var lastShotTick = 0;
var dragNode = null;
// Mouse/touch move: aim gun
game.move = function (x, y, obj) {
// No drag, just aiming
// Optionally, could rotate gun sprite, but for now, just use for shooting
};
// Mouse/touch down: shoot
game.down = function (x, y, obj) {
// Only shoot if not reloading
if (isReloading) return;
if (ammo <= 0) {
// Start reload
isReloading = true;
reloadTimer = 0;
return;
}
// Fire bullet
var gunPos = player.getGunPos();
var b = new Bullet();
b.x = gunPos.x;
b.y = gunPos.y;
// Aim: calculate angle to (x, y)
var dx = x - gunPos.x;
var dy = y - gunPos.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
b.speed = weapons[weaponIndex].bulletSpeed;
b.damage = weapons[weaponIndex].damage;
// Set bullet direction
b.vx = b.speed * (dx / dist);
b.vy = b.speed * (dy / dist);
// Overwrite update to use vx/vy
b.update = function () {
b.x += b.vx;
b.y += b.vy;
};
bullets.push(b);
game.addChild(b);
ammo--;
updateUI();
};
// Mouse/touch up: nothing
game.up = function (x, y, obj) {};
// --- Weapon Switching removed (no weapon name or tap to switch) ---
// --- Main Game Loop ---
game.update = function () {
// --- Spawning zombies continuously ---
spawnTimer++;
if (spawnTimer > 55) {
spawnZombie();
spawnTimer = 0;
}
// --- Bullets update ---
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.x > 2048 + 100 || b.y < -100 || b.y > 2732 + 100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with zombies
var bulletDestroyed = false;
for (var j = zombies.length - 1; j >= 0; j--) {
var z = zombies[j];
if (b.intersects(z)) {
z.health -= b.damage;
if (z.health <= 0) {
// Zombie dies
zombiesKilled++;
// Only spawn a lootbox 30% of the time
if (Math.random() < 0.3) {
spawnLootBox(z.x, z.y - 40);
}
z.destroy();
zombies.splice(j, 1);
}
b.destroy();
bullets.splice(i, 1);
bulletDestroyed = true;
break;
}
}
if (bulletDestroyed) continue;
// Check collision with lootboxes (shoot to open)
for (var k = lootboxes.length - 1; k >= 0; k--) {
var l = lootboxes[k];
if (b.intersects(l)) {
// Open lootbox and grant reward
if (l.type === 'ammo') {
ammo += l.value;
if (ammo > maxAmmo) ammo = maxAmmo;
} else if (l.type === 'medkit') {
health += l.value;
if (health > maxHealth) health = maxHealth;
}
// Increase score when shooting and opening a lootbox
zombiesKilled++;
l.destroy();
lootboxes.splice(k, 1);
b.destroy();
bullets.splice(i, 1);
bulletDestroyed = true;
break;
}
}
if (bulletDestroyed) continue;
}
// --- Zombies update ---
for (var i = zombies.length - 1; i >= 0; i--) {
var z = zombies[i];
z.update();
// If zombie reaches player
if (z.x < player.x + 60) {
// Damage player (reduced by half)
health -= 0.5;
LK.effects.flashObject(player, 0xff0000, 400);
z.destroy();
zombies.splice(i, 1);
if (health <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// --- Lootboxes update ---
for (var i = lootboxes.length - 1; i >= 0; i--) {
var l = lootboxes[i];
l.update();
// If off screen
if (l.x < -100) {
l.destroy();
lootboxes.splice(i, 1);
continue;
}
// No automatic pickup; lootboxes must be shot to open
}
// --- Reloading ---
if (isReloading) {
reloadTimer++;
if (reloadTimer > weapons[weaponIndex].reload) {
isReloading = false;
ammo = maxAmmo;
updateUI();
}
}
// No level progression or waves
updateUI();
};
// --- Start Game ---
ammo = weapons[weaponIndex].ammo;
maxAmmo = weapons[weaponIndex].ammo;
health = maxHealth;
zombiesKilled = 0;
unlockedWeapons = 1;
weaponIndex = 0;
gameStartTick = LK.ticks; // Track when the game started for zombie speed scaling
startLevel(1);
updateUI();