User prompt
make the wave go down 2 pixels
User prompt
Move the health , score and wave to left top corner
User prompt
do it pls
User prompt
they are not symmetrical
User prompt
Make health, Score and Wave section at the top look better
User prompt
Blood harvest is too op and we already have vampire bullets that does the same thing more balanced. Speed boost now upgrades firerate but we already have something ıncares firerate
User prompt
Make lucky shoot bullets look pink, Re work blood harvest because you cant heal while the wave so its useless, Speed boost is useless because our player cant move silly change it ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add all of them! Also make assent for the ones need it ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
dont only make the boom time image bigger also make the explosions effect area bigger
User prompt
Make explosion 2 times bigger every time player picks another "boom time"
User prompt
make a assent and sound for it
User prompt
Bullet time is weak so lets rework it! Name: Boom Time! when taken damage a mini explosion happens and zombies near by takes 1 damage. Every time player take the item again. İt will deal 1 more damage And make the explosion radiud bigger. make explosion assent and sound
User prompt
I want 1 , 4 , 8 , 9
User prompt
make the bloods transparency %50
User prompt
Make transparent zombies blood transparent too
User prompt
make it %95 transparency
User prompt
New zombie: Transparent zombie İts %90 transparent. It has %5 change to replace fast zombie after round 21 make a assent for it
User prompt
Lets add more cards 3 is so less. New card: Fresh Meat: After every wave regen 5 hp. Dont regen if hp is more then 100. It can stack so if you take twice it gonna regen 10 every wave
User prompt
I need to test it so make its happen change %100
User prompt
I want to test it so make it happen at the wave 2
User prompt
No 10x gun jamming!
User prompt
To try can you make it happen at 1 wave
User prompt
LETS MAKE A EXTREMLY RARE WEATHER! VOİD its text will be purple and it will activite all weather with 10x! İt can happen any wave with %0.1 change!
User prompt
Make normal blood moons text red and extra blood moons dark red
User prompt
New zombie! After wave 30 our new mega splitter zombie can replace splitter zombie with %20 change. Mega splitter will have double hp of splitter and when it dies it will split into 2 splitter! make mega splitter green version of splitter
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BloodSplat = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('blood', { anchorX: 0.5, anchorY: 0.5 }); self.lifetime = 300; // 5 seconds at 60fps self.fadeStartTime = 0; self.isFading = false; self.update = function () { self.lifetime--; // Start fading after 10 seconds if (self.lifetime <= 0 && !self.isFading) { self.isFading = true; tween(graphics, { alpha: 0 }, { duration: 3000, onFinish: function onFinish() { self.destroy(); } }); } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 20; self.dx = 0; self.dy = 0; self.active = true; self.bounced = false; self.bounceCount = 0; // Track number of bounces performed self.update = function () { if (!self.active) return; self.x += self.dx; self.y += self.dy; if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.active = false; } }; self.setDirection = function (targetX, targetY) { var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.dx = dx / distance * self.speed; self.dy = dy / distance * self.speed; // Rotate bullet to face direction of travel graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } }; self.bounce = function (hitMonster) { // Increment bounce count first self.bounceCount++; // Check if we've reached the bounce limit if (self.bounceCount >= bouncyBulletCount) { self.active = false; return; } // Find nearest monster regardless of distance var nearestMonster = null; var nearestDistance = Infinity; // No distance limit for (var i = 0; i < monsters.length; i++) { var monster = monsters[i]; if (!monster.active || monster === hitMonster) continue; var dx = monster.x - self.x; var dy = monster.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestMonster = monster; } } if (nearestMonster) { self.bounced = true; self.bounceTarget = nearestMonster; // Store the target self.setDirection(nearestMonster.x, nearestMonster.y); } else { // No target found, deactivate bullet self.active = false; } }; return self; }); var Card = Container.expand(function (powerType) { var self = Container.call(this); // Card background var cardBg = LK.getAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 1.5 }); cardBg.tint = 0x2c3e50; self.addChild(cardBg); // Card title text var titleText = new Text2(getPowerTitle(powerType), { size: 50, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.y = -40; self.addChild(titleText); // Card description text var descText = new Text2(getPowerDescription(powerType), { size: 30, fill: 0xECF0F1 }); descText.anchor.set(0.5, 0.5); descText.y = 20; self.addChild(descText); self.powerType = powerType; // Card selection handler self.down = function (x, y, obj) { selectCard(self.powerType); }; return self; }); var CrayzZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('crayzZombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 25; // Even faster speed for maximum challenge self.health = 1; self.damage = 12; self.active = true; self.lastPlayerDistance = 0; self.spiralAngle = 0; // Angle for spiral movement self.crazyTimer = 0; // Timer for random direction changes self.suddenChangeX = 0; // Sudden movement offset X self.suddenChangeY = 0; // Sudden movement offset Y self.isChangingDirection = false; // Flag for direction change animation // Start with a random crazy movement pattern immediately self.startCrazyMovement = function () { if (self.isChangingDirection) return; self.isChangingDirection = true; // Random sudden movement direction var randomAngle = Math.random() * Math.PI * 2; var randomDistance = 100 + Math.random() * 200; var targetX = Math.cos(randomAngle) * randomDistance; var targetY = Math.sin(randomAngle) * randomDistance; // Animate sudden direction change tween(self, { suddenChangeX: targetX, suddenChangeY: targetY }, { duration: 300 + Math.random() * 400, easing: tween.easeInOut, onFinish: function onFinish() { // Reset and prepare for next crazy movement self.suddenChangeX = 0; self.suddenChangeY = 0; self.isChangingDirection = false; } }); }; self.update = function () { if (!self.active) return; // Screen center coordinates var screenCenterX = 1024; // Half of 2048 var screenCenterY = 1366; // Half of 2732 // Calculate distance from screen center var dxToCenter = screenCenterX - self.x; var dyToCenter = screenCenterY - self.y; var distanceToCenter = Math.sqrt(dxToCenter * dxToCenter + dyToCenter * dyToCenter); // Calculate distance to player for damage detection var dxToPlayer = player.x - self.x; var dyToPlayer = player.y - self.y; var distanceToPlayer = Math.sqrt(dxToPlayer * dxToPlayer + dyToPlayer * dyToPlayer); // Spiral movement around screen center self.spiralAngle += 0.1; // Spiral rotation speed // Calculate current position relative to screen center var currentAngle = Math.atan2(self.y - screenCenterY, self.x - screenCenterX); var currentRadius = distanceToCenter; // Gradually decrease radius to spiral inward var targetRadius = Math.max(50, currentRadius - 1); // Minimum radius of 50 pixels // Calculate new position on the spiral var newAngle = currentAngle + 0.1; // Spiral by rotating around center var newX = screenCenterX + Math.cos(newAngle) * targetRadius; var newY = screenCenterY + Math.sin(newAngle) * targetRadius; // Move toward the new spiral position var dx = newX - self.x; var dy = newY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate zombie to face movement direction graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distanceToPlayer; // CrayzZombie can deal damage when getting close to screen center if (distanceToCenter <= 250) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = distanceToPlayer; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion with spreading effect for (var i = 0; i < 15; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.2; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 300; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 15); // Score between normal and fast zombie LK.getSound('hit').play(); return true; } return false; }; return self; }); var FastZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('fastZombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; // Faster than normal zombie (2) self.health = 1; self.damage = 10; self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion with spreading effect for (var i = 0; i < 15; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.2; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 300; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 10); LK.getSound('hit').play(); return true; } return false; }; return self; }); var MegaSplitterZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('splitterZombie', { anchorX: 0.5, anchorY: 0.5 }); // Green tint to distinguish from regular splitter zombie graphics.tint = 0x44aa44; self.speed = 2; // Same speed as splitter zombie self.health = 4; // Double HP of splitter zombie (2 * 2) self.damage = 12; // Same damage as splitter zombie self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion for (var i = 0; i < 15; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.2; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 300; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } // Spawn 2 splitter zombies for (var s = 0; s < 2; s++) { var splitterZombie = new SplitterZombie(); // Position splitter zombies around the original position var spawnAngle = Math.PI * s + Math.random() * 0.5; var spawnDistance = 100 + Math.random() * 50; splitterZombie.x = self.x + Math.cos(spawnAngle) * spawnDistance; splitterZombie.y = self.y + Math.sin(spawnAngle) * spawnDistance; // Keep within bounds splitterZombie.x = Math.max(125, Math.min(1923, splitterZombie.x)); splitterZombie.y = Math.max(125, Math.min(2607, splitterZombie.y)); monsters.push(splitterZombie); game.addChild(splitterZombie); } LK.setScore(LK.getScore() + 35); // Higher score for mega splitter zombie LK.getSound('hit').play(); return true; } return false; }; return self; }); var MiniZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5 }); // Scale down to make it smaller graphics.scaleX = 0.5; graphics.scaleY = 0.5; // Tint it green to distinguish from normal zombies graphics.tint = 0x44aa44; self.speed = 5; // Fast movement self.health = 1; self.damage = 8; self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create smaller blood explosion for (var i = 0; i < 8; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.2 + Math.random() * 0.8; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 80 + Math.random() * 150; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 200 + Math.random() * 300; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 5); // Lower score for mini zombie LK.getSound('hit').play(); return true; } return false; }; return self; }); var Monster = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.health = 1; self.damage = 10; self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion with spreading effect for (var i = 0; i < 15; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.2; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 300; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 10); LK.getSound('hit').play(); return true; } return false; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.maxHealth = 100; self.fireRate = 30; // Slower initial fire rate self.fireTimer = 0; self.update = function () { if (self.fireTimer > 0) { self.fireTimer--; } }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; LK.showGameOver(); } LK.effects.flashObject(self, 0xff0000, 300); }; self.canFire = function () { return self.fireTimer <= 0; }; self.fire = function () { if (self.canFire()) { self.fireTimer = self.fireRate; return true; } return false; }; return self; }); var Rock = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('rock', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.dx = 0; self.dy = 0; self.active = true; self.damage = 5; self.update = function () { if (!self.active) return; self.x += self.dx; self.y += self.dy; // Remove rock if it goes off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.active = false; } // Check collision with player var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= 85) { // Player radius + rock radius player.takeDamage(self.damage); self.active = false; } }; self.setDirection = function (targetX, targetY) { var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.dx = dx / distance * self.speed; self.dy = dy / distance * self.speed; // Rotate rock to face direction of travel graphics.rotation = Math.atan2(dy, dx); } }; return self; }); var RockThrowerZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('rockThrowerZombie', { anchorX: 0.5, anchorY: 0.5 }); graphics.rotation = Math.PI; // Face downward like other zombies self.speed = 1; // Slower movement speed self.health = 1; self.damage = 0; // Doesn't deal contact damage self.active = true; self.lastPlayerDistance = 0; self.throwCooldown = 0; self.throwRange = 900; // Range to start throwing rocks self.isInRange = false; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move toward player but stop at throwing range if (distance > self.throwRange) { if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate zombie to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } self.isInRange = false; } else { // In range - stop moving and start throwing self.isInRange = true; // Face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } // Throw rocks when in range if (self.isInRange && self.throwCooldown <= 0) { self.throwRock(); self.throwCooldown = 120; // 2 seconds between throws } if (self.throwCooldown > 0) { self.throwCooldown--; } self.lastPlayerDistance = distance; }; self.throwRock = function () { var rock = new Rock(); rock.x = self.x; rock.y = self.y; rock.setDirection(player.x, player.y); rocks.push(rock); game.addChild(rock); // Shake animation when throwing var originalX = self.x; var originalY = self.y; tween(self, { x: originalX + 15, y: originalY + 10 }, { duration: 80, onFinish: function onFinish() { tween(self, { x: originalX - 10, y: originalY - 8 }, { duration: 80, onFinish: function onFinish() { tween(self, { x: originalX, y: originalY }, { duration: 80 }); } }); } }); }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion for (var i = 0; i < 12; i++) { var bloodSplat = new BloodSplat(); bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.0; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; var angle = Math.random() * Math.PI * 2; var distance = 120 + Math.random() * 250; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 18); // Score between tough and splitter LK.getSound('hit').play(); return true; } return false; }; return self; }); var SplitterZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('splitterZombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; // Medium speed self.health = 2; // Same as tough zombie self.damage = 12; // Medium damage self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion for (var i = 0; i < 12; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.0; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 120 + Math.random() * 250; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } // Spawn 2-3 mini zombies var miniCount = 2 + Math.floor(Math.random() * 2); // 2 or 3 mini zombies for (var m = 0; m < miniCount; m++) { var miniZombie = new MiniZombie(); // Position mini zombies around the original position var spawnAngle = Math.PI * 2 / miniCount * m + Math.random() * 0.5; var spawnDistance = 80 + Math.random() * 40; miniZombie.x = self.x + Math.cos(spawnAngle) * spawnDistance; miniZombie.y = self.y + Math.sin(spawnAngle) * spawnDistance; // Keep within bounds miniZombie.x = Math.max(125, Math.min(1923, miniZombie.x)); miniZombie.y = Math.max(125, Math.min(2607, miniZombie.y)); monsters.push(miniZombie); game.addChild(miniZombie); } LK.setScore(LK.getScore() + 25); // Higher score for splitter zombie LK.getSound('hit').play(); return true; } return false; }; return self; }); var ToughZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('toughZombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.5; // Slower than normal zombie self.health = 2; // Much tougher self.damage = 15; // Higher damage self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion with spreading effect for (var i = 0; i < 15; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.2; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 300; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 20); // Higher score for tough zombie LK.getSound('hit').play(); return true; } return false; }; return self; }); var TransparentZombie = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('transparentZombie', { anchorX: 0.5, anchorY: 0.5 }); graphics.alpha = 0.1; // 90% transparent (10% opacity) self.speed = 4; // Same speed as fast zombie self.health = 1; self.damage = 10; self.active = true; self.lastPlayerDistance = 0; self.update = function () { if (!self.active) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate monster to face the player graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } var currentDistance = distance; if (self.lastPlayerDistance > 50 && currentDistance <= 50) { player.takeDamage(self.damage); self.active = false; } self.lastPlayerDistance = currentDistance; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.active = false; // Create blood explosion with spreading effect for (var i = 0; i < 15; i++) { var bloodSplat = new BloodSplat(); // Start at monster position bloodSplat.x = self.x; bloodSplat.y = self.y; bloodSplat.graphics = bloodSplat.children[0]; var scale = 0.3 + Math.random() * 1.2; bloodSplat.graphics.scaleX = scale; bloodSplat.graphics.scaleY = scale; // Calculate random spread destination var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 300; var targetX = self.x + Math.cos(angle) * distance; var targetY = self.y + Math.sin(angle) * distance; // Keep within game bounds targetX = Math.max(50, Math.min(1998, targetX)); targetY = Math.max(50, Math.min(2682, targetY)); // Animate spreading with random delay and duration var delay = Math.random() * 200; var duration = 300 + Math.random() * 400; tween(bloodSplat, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut }); bloodSplats.push(bloodSplat); game.addChild(bloodSplat); } LK.setScore(LK.getScore() + 12); // Score between fast and crayz zombie LK.getSound('hit').play(); return true; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ var player = null; var bullets = []; var monsters = []; var bloodSplats = []; var rocks = []; var waveNumber = 1; var monstersInWave = 5; var monstersSpawned = 0; var monstersKilled = 0; var spawnTimer = 0; var waveDelay = 180; var bulletCooldown = 30; // Start with cooldown to prevent immediate shooting // Secret wave skip variables (hidden from normal players) var secretTapCount = 0; var secretTapTimer = 0; var secretZone = { x: 1900, y: 2600, width: 148, height: 132 }; // Bottom-right corner // Fast zombie spawn chance (starts at 10%, increases 1% per wave, max 80%) var fastZombieChance = 10; // Tough zombie spawn chance (starts at 5% after wave 5, increases 1% per wave, max 90%) var toughZombieChance = 5; // Crayz zombie spawn chance (10% after wave 15 to replace fast zombies) var crayzZombieChance = 10; // Splitter zombie spawn chance (15% after wave 18 to replace tough zombies) var splitterZombieChance = 15; // Mega splitter zombie spawn chance (20% after wave 30 to replace splitter zombies) var megaSplitterZombieChance = 20; // Rock thrower zombie spawn chance (10% after wave 25 to replace normal zombies) var rockThrowerZombieChance = 10; // Weather system variables var currentWeather = null; var weatherActive = false; var weatherChance = 5; // Starting at 5% after wave 10 var weatherText = null; var weatherTypes = ['windy', 'bloodSmell', 'bloodRain', 'unluckyClouds']; var isExtraSpecialWeather = false; var weatherEffects = { windy: false, bloodSmell: false, bloodRain: false, unluckyClouds: false, bloodMoon: false, "void": false }; // Weather utility functions function getWeatherName(weather) { var prefix = isExtraSpecialWeather ? 'EXTRA ' : ''; switch (weather) { case 'windy': return prefix + 'WINDY'; case 'bloodSmell': return prefix + 'BLOOD SMELL'; case 'bloodRain': return prefix + 'BLOOD RAIN'; case 'unluckyClouds': return prefix + 'UNLUCKY CLOUDS'; case 'bloodMoon': return prefix + 'BLOOD MOON'; case 'void': return 'VOID'; default: return ''; } } function getWeatherDescription(weather) { var multiplier = isExtraSpecialWeather ? 2 : 1; switch (weather) { case 'windy': return isExtraSpecialWeather ? 'All zombies are 100% faster' : 'All zombies are 50% faster'; case 'bloodSmell': return isExtraSpecialWeather ? 'Quadruple amount of zombies' : 'Double amount of zombies'; case 'bloodRain': return isExtraSpecialWeather ? 'Every zombie has 4x HP' : 'Every zombie has double HP'; case 'unluckyClouds': return isExtraSpecialWeather ? '40% chance your gun won\'t shoot' : '20% chance your gun won\'t shoot'; case 'bloodMoon': return isExtraSpecialWeather ? 'ALL EXTRA EFFECTS COMBINED!' : 'ALL EFFECTS COMBINED!'; case 'void': return 'ALL EFFECTS WITH 10X INTENSITY!'; default: return ''; } } function applyWeatherEffects(weather) { // Reset all weather effects first weatherEffects.windy = false; weatherEffects.bloodSmell = false; weatherEffects.bloodRain = false; weatherEffects.unluckyClouds = false; weatherEffects.bloodMoon = false; weatherEffects["void"] = false; if (weather === 'void') { // VOID activates all effects with extreme intensity weatherEffects.windy = true; weatherEffects.bloodSmell = true; weatherEffects.bloodRain = true; weatherEffects.unluckyClouds = true; weatherEffects["void"] = true; } else if (weather === 'bloodMoon') { // Blood moon activates all effects weatherEffects.windy = true; weatherEffects.bloodSmell = true; weatherEffects.bloodRain = true; weatherEffects.unluckyClouds = true; weatherEffects.bloodMoon = true; } else if (weather) { weatherEffects[weather] = true; } } function showWeatherAnnouncement(weather) { var weatherName = getWeatherName(weather); var weatherDescription = getWeatherDescription(weather); // Determine color based on weather type and if it's extra special var textColor = 0xFFFFFF; // Default white if (weather === 'void') { textColor = 0x8A2BE2; // Purple for VOID weather } else if (weather === 'bloodMoon') { if (isExtraSpecialWeather) { textColor = 0x8B0000; // Dark red for extra special blood moon } else { textColor = 0xFF0000; // Red for normal blood moon } } else if (isExtraSpecialWeather) { textColor = 0xFFD700; // Golden for extra special weather } // Create weather text at center of screen weatherText = new Text2(weatherName + '\n' + weatherDescription, { size: 120, fill: textColor }); weatherText.anchor.set(0.5, 0.5); weatherText.x = 1024; weatherText.y = 1366; game.addChild(weatherText); // After 3 seconds, shrink and move to bottom middle LK.setTimeout(function () { if (weatherText) { // Change text to only show weather name (remove description) weatherText.setText(weatherName); tween(weatherText, { scaleX: 0.3, scaleY: 0.3, x: 1024, y: 2650 }, { duration: 1000, easing: tween.easeInOut }); } }, 3000); } function checkForWeather() { // Only check for weather after wave 10 if (waveNumber < 10) return; // Calculate current weather chance (5% + 2.5% per wave, max 100%) var currentWeatherChance = Math.min(5 + (waveNumber - 10) * 2.5, 100); if (Math.random() * 100 < currentWeatherChance) { var selectedWeather; // Reset extra special weather flag isExtraSpecialWeather = false; // When weather chance is 100%, check for extra special weather if (currentWeatherChance >= 100) { // Calculate extra special weather chance (30% base + 5% per wave after reaching 100%) // Wave when weather chance first reaches 100% is approximately wave 46: 5 + (46-10) * 2.5 = 95, next wave is 97.5, next is 100 var waveWhenMaxReached = 46; // Approximate wave when weather chance reaches 100% var extraSpecialChance = 30; if (waveNumber > waveWhenMaxReached) { extraSpecialChance = 30 + (waveNumber - waveWhenMaxReached) * 5; } if (Math.random() * 100 < extraSpecialChance) { isExtraSpecialWeather = true; } } // Extremely rare chance for VOID weather (0.1% chance independent of other weather) if (Math.random() * 1000 < 1) { selectedWeather = 'void'; } else if (Math.random() * 100 < 1) { // Very small chance for blood moon (1% of weather events) selectedWeather = 'bloodMoon'; } else { // Equal chance for other weather types selectedWeather = weatherTypes[Math.floor(Math.random() * weatherTypes.length)]; } currentWeather = selectedWeather; weatherActive = true; applyWeatherEffects(selectedWeather); showWeatherAnnouncement(selectedWeather); } } function clearWeather() { currentWeather = null; weatherActive = false; isExtraSpecialWeather = false; weatherEffects["void"] = false; applyWeatherEffects(null); // Remove weather text if it exists if (weatherText) { weatherText.destroy(); weatherText = null; } } // Card system variables var isCardSelectionActive = false; var cardContainer = null; var selectedPower = null; var availablePowers = ['bouncy', 'rapidfire', 'multishot', 'freshMeat']; var activePowers = []; var bouncyBulletCount = 1; // Number of bounces for bouncy bullets var multishotBulletCount = 1; // Number of bullets to fire for multishot var freshMeatStacks = 0; // Number of Fresh Meat cards collected var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var healthText = new Text2('Health: 100', { size: 50, fill: 0xFF4444 }); healthText.anchor.set(0, 0); healthText.x = 120; healthText.y = 20; LK.gui.topLeft.addChild(healthText); var waveText = new Text2('Wave: 1', { size: 50, fill: 0x4A90E2 }); waveText.anchor.set(1, 0); LK.gui.topRight.addChild(waveText); // Power utility functions function getPowerTitle(powerType) { switch (powerType) { case 'bouncy': return 'Bouncy Bullets'; case 'rapidfire': return 'Rapid Fire'; case 'multishot': return 'Multi Shot'; case 'freshMeat': return 'Fresh Meat'; default: return 'Unknown Power'; } } function getPowerDescription(powerType) { switch (powerType) { case 'bouncy': return 'Bullets bounce to nearby enemies'; case 'rapidfire': return 'Faster shooting speed'; case 'multishot': return 'Shoot 3 bullets at once'; case 'freshMeat': return 'Regenerate 5 HP after each wave'; default: return 'Unknown effect'; } } function showCardSelection() { isCardSelectionActive = true; // Create card container cardContainer = new Container(); game.addChild(cardContainer); // Create dark overlay var overlay = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8 }); overlay.tint = 0x000000; cardContainer.addChild(overlay); // Select 3 random powers var shuffledPowers = availablePowers.slice(); for (var i = shuffledPowers.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = shuffledPowers[i]; shuffledPowers[i] = shuffledPowers[j]; shuffledPowers[j] = temp; } var selectedPowers = shuffledPowers.slice(0, 3); // Create cards for (var i = 0; i < 3; i++) { var card = new Card(selectedPowers[i]); card.x = 512 + i * 512; card.y = 1366; cardContainer.addChild(card); // Animate cards in tween(card, { y: 1000 }, { duration: 500, easing: tween.easeOut }); } // Add title text var titleText = new Text2('Choose Your Power!', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; cardContainer.addChild(titleText); } function selectCard(powerType) { if (!isCardSelectionActive) return; // Add power to active powers activePowers.push(powerType); // Apply power effect applyPowerEffect(powerType); // Animate cards out and clean up if (cardContainer) { tween(cardContainer, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (cardContainer) { cardContainer.destroy(); } cardContainer = null; isCardSelectionActive = false; } }); } } function applyPowerEffect(powerType) { switch (powerType) { case 'rapidfire': player.fireRate = Math.max(1, Math.floor(player.fireRate / 2)); break; case 'multishot': // Increase bullet count for multishot multishotBulletCount++; break; case 'bouncy': // Increase bounce count for all future bullets bouncyBulletCount++; break; case 'freshMeat': // Increase Fresh Meat stacks for HP regeneration freshMeatStacks++; break; } } var background = game.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); player = game.addChild(new Player()); player.x = 1024; player.y = 1366; function spawnMonster() { if (monstersSpawned >= monstersInWave) return; // Spawn multiple monsters at once based on wave number - more balanced progression var monstersToSpawn = 1; if (waveNumber >= 3) monstersToSpawn = 2; if (waveNumber >= 6) monstersToSpawn = 3; if (waveNumber >= 10) monstersToSpawn = Math.min(4, Math.floor(waveNumber / 3)); var actualSpawn = Math.min(monstersToSpawn, monstersInWave - monstersSpawned); for (var spawnIndex = 0; spawnIndex < actualSpawn; spawnIndex++) { // Calculate current tough zombie chance (5% base + 1% per wave after wave 10, max 90%) var currentToughZombieChance = waveNumber >= 10 ? Math.min(5 + (waveNumber - 10), 90) : 0; // Determine zombie type with priority: splitter > tough > crayz > fast > rockthrower > normal var randomChance = Math.random() * 100; var monster; if (waveNumber >= 10 && randomChance < currentToughZombieChance) { // 30% chance to spawn splitter zombie instead of tough zombie after wave 25 if (waveNumber >= 25 && Math.random() * 100 < 30) { // 20% chance to spawn mega splitter zombie instead of splitter zombie after wave 30 if (waveNumber >= 30 && Math.random() * 100 < megaSplitterZombieChance) { monster = new MegaSplitterZombie(); } else { monster = new SplitterZombie(); } } else { monster = new ToughZombie(); } } else if (waveNumber >= 15 && randomChance < currentToughZombieChance + crayzZombieChance) { // 10% chance to spawn crayz zombie instead of fast zombie after wave 15 monster = new CrayzZombie(); } else if (waveNumber >= 5 && randomChance < currentToughZombieChance + crayzZombieChance + fastZombieChance) { // 5% chance to spawn transparent zombie instead of fast zombie after wave 21 if (waveNumber >= 21 && Math.random() * 100 < 5) { monster = new TransparentZombie(); } else { monster = new FastZombie(); } } else if (waveNumber >= 25 && randomChance < currentToughZombieChance + crayzZombieChance + fastZombieChance + rockThrowerZombieChance) { // 10% chance to spawn rock thrower zombie after wave 25 monster = new RockThrowerZombie(); } else { monster = new Monster(); } var side = Math.floor(Math.random() * 4); switch (side) { case 0: // Top monster.x = Math.random() * 2048; monster.y = -30; break; case 1: // Right monster.x = 2078; monster.y = Math.random() * 2732; break; case 2: // Bottom monster.x = Math.random() * 2048; monster.y = 2762; break; case 3: // Left monster.x = -30; monster.y = Math.random() * 2732; break; } // Apply weather effects to monster if (weatherEffects.windy) { if (weatherEffects["void"]) { monster.speed *= 11; // 10x effect (1000% faster) } else { monster.speed *= isExtraSpecialWeather ? 2.0 : 1.5; // 100% faster for extra, 50% for normal } } if (weatherEffects.bloodRain) { if (weatherEffects["void"]) { monster.health *= 20; // 10x effect (2000% HP) } else { monster.health *= isExtraSpecialWeather ? 4 : 2; // 4x HP for extra, 2x for normal } } monsters.push(monster); game.addChild(monster); monstersSpawned++; } } function cleanupBullets() { for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (!bullet.active) { bullet.destroy(); bullets.splice(i, 1); } } } function cleanupMonsters() { for (var i = monsters.length - 1; i >= 0; i--) { var monster = monsters[i]; if (!monster.active) { monster.destroy(); monsters.splice(i, 1); monstersKilled++; } } } function cleanupBloodSplats() { for (var i = bloodSplats.length - 1; i >= 0; i--) { var bloodSplat = bloodSplats[i]; if (!bloodSplat.parent) { bloodSplats.splice(i, 1); } } } function cleanupRocks() { for (var i = rocks.length - 1; i >= 0; i--) { var rock = rocks[i]; if (!rock.active) { rock.destroy(); rocks.splice(i, 1); } } } function checkBulletCollisions() { for (var i = 0; i < bullets.length; i++) { var bullet = bullets[i]; if (!bullet.active) continue; for (var j = 0; j < monsters.length; j++) { var monster = monsters[j]; if (!monster.active) continue; if (bullet.intersects(monster)) { monster.takeDamage(1); // Try to bounce bullet if bouncy power is active and bullet hasn't exceeded bounce limit if (bullet.bounceCount < bouncyBulletCount && activePowers.indexOf('bouncy') !== -1) { bullet.bounce(monster); // If bounce was successful (found a target), keep bullet active if (bullet.bounced) { break; // Stop checking other monsters for this bullet this frame } } // Only deactivate bullet if it reached bounce limit or bouncy power is not active if (bullet.bounceCount >= bouncyBulletCount || activePowers.indexOf('bouncy') === -1) { bullet.active = false; } break; } } } } function nextWave() { waveNumber++; // Apply Fresh Meat healing (5 HP per stack, max 100 HP) if (freshMeatStacks > 0 && player.health < 100) { var healAmount = freshMeatStacks * 5; player.health = Math.min(100, player.health + healAmount); } // Check for card selection every 5 waves if (waveNumber % 5 === 0 && waveNumber > 0) { showCardSelection(); return; // Don't start next wave until card is selected } // More balanced wave size progression: slower growth after wave 10 if (waveNumber <= 10) { monstersInWave = 3 + waveNumber * 2; } else { monstersInWave = 23 + Math.floor((waveNumber - 10) / 2); } // Apply blood smell weather effect (double or quadruple monsters) if (weatherEffects.bloodSmell) { if (weatherEffects["void"]) { monstersInWave *= 20; // 10x effect (2000% monsters) } else { monstersInWave *= isExtraSpecialWeather ? 4 : 2; } } monstersSpawned = 0; monstersKilled = 0; spawnTimer = 0; waveDelay = 180; // Increase fast zombie chance by 1% each wave, max 80% fastZombieChance = Math.min(10 + waveNumber, 80); waveText.setText('Wave: ' + waveNumber); // Clear previous weather and check for new weather clearWeather(); checkForWeather(); } game.down = function (x, y, obj) { // Secret wave skip check (bottom-right corner taps) if (x >= secretZone.x && x <= secretZone.x + secretZone.width && y >= secretZone.y && y <= secretZone.y + secretZone.height) { secretTapCount++; secretTapTimer = 120; // 2 seconds to complete sequence if (secretTapCount >= 5) { // Skip 3 waves var skipAmount = 3; // Skip waves instantly for (var skipCount = 0; skipCount < skipAmount; skipCount++) { waveNumber++; } // Calculate wave size using balanced progression if (waveNumber <= 10) { monstersInWave = 3 + waveNumber * 2; } else { monstersInWave = 23 + Math.floor((waveNumber - 10) / 2); } // Update fast zombie chance for the new wave fastZombieChance = Math.min(10 + waveNumber, 80); monstersSpawned = 0; monstersKilled = monstersInWave; // Clear all current monsters for (var i = 0; i < monsters.length; i++) { if (monsters[i].active) { monsters[i].active = false; } } secretTapCount = 0; waveText.setText('Wave: ' + waveNumber); // Visual feedback (brief flash) LK.effects.flashScreen(0x00ff00, 200); } return; } // Check unlucky clouds weather effect (20% or 40% chance gun doesn't shoot) var jamChance = isExtraSpecialWeather ? 40 : 20; // VOID weather does not apply 10x gun jamming to keep the game playable var gunJammed = weatherEffects.unluckyClouds && Math.random() * 100 < jamChance; if (bulletCooldown <= 0 && player.fire() && !gunJammed) { // Check if multishot is active var shotCount = activePowers.indexOf('multishot') !== -1 ? multishotBulletCount : 1; for (var shotIndex = 0; shotIndex < shotCount; shotIndex++) { var bullet = new Bullet(); bullet.x = player.x; bullet.y = player.y; if (shotCount === 1) { // Single shot - aim directly at target bullet.setDirection(x, y); } else { // Multishot - spread bullets var baseAngle = Math.atan2(y - player.y, x - player.x); var spreadAngle = (shotIndex - (shotCount - 1) / 2) * 0.3; // Center the spread var finalAngle = baseAngle + spreadAngle; var targetX = player.x + Math.cos(finalAngle) * 500; var targetY = player.y + Math.sin(finalAngle) * 500; bullet.setDirection(targetX, targetY); } bullets.push(bullet); game.addChild(bullet); } LK.getSound('shoot').play(); bulletCooldown = player.fireRate; } }; LK.playMusic('bgmusic'); game.update = function () { // Pause game during card selection if (isCardSelectionActive) { return; } // Secret wave skip timer if (secretTapTimer > 0) { secretTapTimer--; if (secretTapTimer <= 0) { secretTapCount = 0; // Reset if too slow } } if (bulletCooldown > 0) { bulletCooldown--; } if (waveDelay > 0) { waveDelay--; return; } spawnTimer++; if (spawnTimer >= 60 && monstersSpawned < monstersInWave) { spawnMonster(); spawnTimer = 0; } checkBulletCollisions(); cleanupBullets(); cleanupMonsters(); cleanupBloodSplats(); cleanupRocks(); if (monstersKilled >= monstersInWave && monsters.length === 0) { nextWave(); } scoreText.setText('Score: ' + LK.getScore()); healthText.setText('Health: ' + player.health); };
===================================================================
--- original.js
+++ change.js
@@ -915,8 +915,81 @@
return false;
};
return self;
});
+var TransparentZombie = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('transparentZombie', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ graphics.alpha = 0.1; // 90% transparent (10% opacity)
+ self.speed = 4; // Same speed as fast zombie
+ self.health = 1;
+ self.damage = 10;
+ self.active = true;
+ self.lastPlayerDistance = 0;
+ self.update = function () {
+ if (!self.active) return;
+ var dx = player.x - self.x;
+ var dy = player.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 0) {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ // Rotate monster to face the player
+ graphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
+ }
+ var currentDistance = distance;
+ if (self.lastPlayerDistance > 50 && currentDistance <= 50) {
+ player.takeDamage(self.damage);
+ self.active = false;
+ }
+ self.lastPlayerDistance = currentDistance;
+ };
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ if (self.health <= 0) {
+ self.active = false;
+ // Create blood explosion with spreading effect
+ for (var i = 0; i < 15; i++) {
+ var bloodSplat = new BloodSplat();
+ // Start at monster position
+ bloodSplat.x = self.x;
+ bloodSplat.y = self.y;
+ bloodSplat.graphics = bloodSplat.children[0];
+ var scale = 0.3 + Math.random() * 1.2;
+ bloodSplat.graphics.scaleX = scale;
+ bloodSplat.graphics.scaleY = scale;
+ // Calculate random spread destination
+ var angle = Math.random() * Math.PI * 2;
+ var distance = 150 + Math.random() * 300;
+ var targetX = self.x + Math.cos(angle) * distance;
+ var targetY = self.y + Math.sin(angle) * distance;
+ // Keep within game bounds
+ targetX = Math.max(50, Math.min(1998, targetX));
+ targetY = Math.max(50, Math.min(2682, targetY));
+ // Animate spreading with random delay and duration
+ var delay = Math.random() * 200;
+ var duration = 300 + Math.random() * 400;
+ tween(bloodSplat, {
+ x: targetX,
+ y: targetY
+ }, {
+ duration: duration,
+ easing: tween.easeOut
+ });
+ bloodSplats.push(bloodSplat);
+ game.addChild(bloodSplat);
+ }
+ LK.setScore(LK.getScore() + 12); // Score between fast and crayz zombie
+ LK.getSound('hit').play();
+ return true;
+ }
+ return false;
+ };
+ return self;
+});
/****
* Initialize Game
****/
@@ -1317,9 +1390,14 @@
} else if (waveNumber >= 15 && randomChance < currentToughZombieChance + crayzZombieChance) {
// 10% chance to spawn crayz zombie instead of fast zombie after wave 15
monster = new CrayzZombie();
} else if (waveNumber >= 5 && randomChance < currentToughZombieChance + crayzZombieChance + fastZombieChance) {
- monster = new FastZombie();
+ // 5% chance to spawn transparent zombie instead of fast zombie after wave 21
+ if (waveNumber >= 21 && Math.random() * 100 < 5) {
+ monster = new TransparentZombie();
+ } else {
+ monster = new FastZombie();
+ }
} else if (waveNumber >= 25 && randomChance < currentToughZombieChance + crayzZombieChance + fastZombieChance + rockThrowerZombieChance) {
// 10% chance to spawn rock thrower zombie after wave 25
monster = new RockThrowerZombie();
} else {
Bullet. In-Game asset. 2d. High contrast. No shadows
A extremly basic zombie look from top. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A round drop of blood. In-Game asset. 2d. High contrast. No shadows
Make it simple no blood or object
Make its skin blue and make it smile
A happier version of this zombie but its will be purple
Make it green
small rock. In-Game asset. 2d. High contrast. No shadows
Yellow version of it
make it white
Explosion!. In-Game asset. 2d. High contrast. No shadows
Lightning. In-Game asset. 2d. High contrast. No shadows
Make it rainbow and extremly happy
A cowboy hat from top. In-Game asset. 2d. High contrast. No shadows
Hake his skin red and add horns
A card. In-Game asset. 2d. High contrast. No shadows