User prompt
add practice mode
User prompt
MORE SPEED TO ENEMY BRUH
User prompt
make the impossible mode enemy speed to crazy SPEED like 20X
User prompt
tidy up the difficulty choosing
User prompt
add impossible difficulty and their function
User prompt
make the NPC shooting range more easier more far
User prompt
NPC shooting range is more difficult more near and more easier more far
User prompt
every difficulty have their own NPC speed more difficult more slow
User prompt
every difficulty have their own NPC shooting range
User prompt
make the bazooka chance balanced to 100
User prompt
NPC can dead because of bazooka in one hit
User prompt
add bazooka shoot at NPC chance in instruction text
User prompt
update bazooka chance instruction since now bazooka have chance to explode at NPC
User prompt
bazooka now have a chance to shoot at NPC
User prompt
every difficulty have their own NPC bullet
User prompt
npc have limited ammo and they can take supply for themselve (but still have more for player
User prompt
every difficulty have their own enemy health
User prompt
every difficulty have their own NPC health
User prompt
make the enemy focusing to NPC first
User prompt
make the NPC distancing from other NPC
User prompt
make the npc walking to enemy and shoot them
User prompt
"NPC STOP FOLLOW ME" -the player
User prompt
make the NPC 10 and spawn when the game start
User prompt
make NPC that help shooting but they can dead too
User prompt
make a NPC that can shoot too and shape like player
/**** * Plugins ****/ var tween = LK.import("@upit/tween.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 = 15; self.lifetime = 600; // 10 seconds at 60fps self.update = function () { self.lifetime--; // Pulsing effect ammoGraphics.alpha = 0.7 + Math.sin(self.lifetime * 0.2) * 0.3; if (self.lifetime <= 0) { return true; // Should be removed } return false; }; return self; }); var Bazooka = Container.expand(function () { var self = Container.call(this); var bazookaGraphics = self.attachAsset('bazooka', { anchorX: 0.5, anchorY: 0.5 }); self.ammo = 5; self.maxAmmo = 5; self.cooldown = 0; self.lastX = 0; self.lastY = 0; self.update = function () { self.lastX = self.x; self.lastY = self.y; // Reset bazooka usage flag usingBazooka = false; // Always ready to fire pulsing effect bazookaGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.2) * 0.2; }; self.down = function (x, y, obj) { self.fireBazooka(); }; self.fireBazooka = function () { // Get difficulty-based bazooka chances var bazookaChances = [{ target: 0.85, blank: 0.12, explode: 0.03 }, // Easy: 85% target, 12% blank, 3% explode { target: 0.75, blank: 0.15, explode: 0.10 }, // Normal: 75% target, 15% blank, 10% explode { target: 0.65, blank: 0.20, explode: 0.15 }, // Hard: 65% target, 20% blank, 15% explode { target: 0.50, blank: 0.25, explode: 0.25 } // Nightmare: 50% target, 25% blank, 25% explode ]; var chances = bazookaChances[selectedDifficulty - 1]; // Random outcome based on difficulty var randomOutcome = Math.random(); if (randomOutcome < chances.explode) { // 10% chance: Self-explosion and death // Create explosion at bazooka position var explosion = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5 }); explosion.x = self.x; explosion.y = self.y; explosion.alpha = 0.8; game.addChild(explosion); // Animate explosion tween(explosion, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 500, onFinish: function onFinish() { explosion.destroy(); } }); // Play explosion sound LK.getSound('explosion').play(); // Kill player if (player) { player.takeDamage(player.health); // Deal enough damage to kill } // Flash effect LK.effects.flashObject(self, 0xff0000, 300); // Set bazooka usage flag usingBazooka = true; return; } else if (randomOutcome < chances.explode + chances.blank) { // 15% chance: Blank ammo (do nothing) // Play a different sound or visual effect for blank LK.getSound('bazookaShoot').play(); // Flash effect with different color LK.effects.flashObject(self, 0x888888, 300); // Create blank ammo text var blankText = new Text2('blank ammo, try again', { size: 40, fill: 0xffffff }); blankText.anchor.set(0.5, 0.5); blankText.x = self.x; blankText.y = self.y - 60; game.addChild(blankText); // Fade out blank text after 2 seconds tween(blankText, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { blankText.destroy(); } }); // Set bazooka usage flag usingBazooka = true; return; } // 75% chance: Normal behavior - target enemy // Find nearest enemy to target var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } // Target boss if no enemies or boss is closer if (boss) { var dx = boss.x - self.x; var dy = boss.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (!nearestEnemy || distance < nearestDistance) { nearestEnemy = boss; nearestDistance = distance; } } if (nearestEnemy) { var bullet = new BazookaBullet(); bullet.x = self.x; bullet.y = self.y; var dx = nearestEnemy.x - self.x; var dy = nearestEnemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { bullet.directionX = dx / distance; bullet.directionY = dy / distance; } bazookaBullets.push(bullet); game.addChild(bullet); // Play bazooka sound LK.getSound('bazookaShoot').play(); // Flash effect LK.effects.flashObject(self, 0xff8800, 300); // Set bazooka usage flag usingBazooka = true; } }; self.addAmmo = function (amount) { self.ammo = Math.min(self.maxAmmo, self.ammo + amount); }; return self; }); var BazookaBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bazookaBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 200; self.explosionRadius = 300; self.directionX = 0; self.directionY = 0; self.lastX = 0; self.lastY = 0; self.update = function () { self.lastX = self.x; self.lastY = self.y; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; // Remove if out of bounds if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { return true; // Should be removed } return false; }; self.explode = function () { // Create explosion visual effect var explosion = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5 }); explosion.x = self.x; explosion.y = self.y; explosion.alpha = 0.8; game.addChild(explosion); // Animate explosion tween(explosion, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 500, onFinish: function onFinish() { explosion.destroy(); } }); // Play explosion sound LK.getSound('explosion').play(); // Damage all enemies in radius for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.explosionRadius) { enemy.takeDamage(self.damage); } } // Damage boss if in radius if (boss) { var dx = boss.x - self.x; var dy = boss.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.explosionRadius) { boss.takeDamage(self.damage); } } }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, tint: 0x800080 }); self.health = 100000; self.maxHealth = 100000; self.speed = 4; self.damage = 50; self.attackCooldown = 0; self.lastX = 0; self.lastY = 0; self.lastPlayerDistance = 1000; self.update = function () { self.lastX = self.x; self.lastY = self.y; if (self.attackCooldown > 0) { self.attackCooldown--; } // Move towards player if (player) { 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; } // Attack if close enough var currentDistance = distance; if (currentDistance < 100 && self.attackCooldown <= 0) { player.takeDamage(self.damage); self.attackCooldown = 60; } self.lastPlayerDistance = currentDistance; } }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { return true; // Boss died } return false; }; 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 = 12; self.damage = 100; // Ensure one-hit kills self.directionX = 0; self.directionY = 0; self.lastX = 0; self.lastY = 0; self.update = function () { self.lastX = self.x; self.lastY = self.y; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; // Remove if out of bounds if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { return true; // Should be removed } return false; }; return self; }); var DifficultySelectionScreen = Container.expand(function () { var self = Container.call(this); // Dark background var background = self.attachAsset('menuBackground', { x: 0, y: 0 }); // Blood moon effect in top right var moon = self.attachAsset('moonGlow', { x: 1600, y: 300, alpha: 0.7, anchorX: 0.5, anchorY: 0.5 }); // Main title var titleText = new Text2('CHOOSE DIFFICULTY', { size: 80, fill: 0xFF4444, align: 'center' }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; self.addChild(titleText); // Easy var easyText = new Text2('EASY', { size: 60, fill: 0x00FF00, align: 'center' }); easyText.anchor.set(0.5, 0.5); easyText.x = 1024; easyText.y = 900; self.addChild(easyText); var easyDesc = new Text2('Slower enemies, more resources', { size: 50, fill: 0xCCCCCC, align: 'center' }); easyDesc.anchor.set(0.5, 0.5); easyDesc.x = 1024; easyDesc.y = 980; self.addChild(easyDesc); // Normal var normalText = new Text2('NORMAL', { size: 60, fill: 0xFFFF00, align: 'center' }); normalText.anchor.set(0.5, 0.5); normalText.x = 1024; normalText.y = 1200; self.addChild(normalText); var normalDesc = new Text2('Balanced challenge', { size: 50, fill: 0xCCCCCC, align: 'center' }); normalDesc.anchor.set(0.5, 0.5); normalDesc.x = 1024; normalDesc.y = 1280; self.addChild(normalDesc); // Hard var hardText = new Text2('HARD', { size: 60, fill: 0xFF8800, align: 'center' }); hardText.anchor.set(0.5, 0.5); hardText.x = 1024; hardText.y = 1500; self.addChild(hardText); var hardDesc = new Text2('Faster enemies, less resources', { size: 50, fill: 0xCCCCCC, align: 'center' }); hardDesc.anchor.set(0.5, 0.5); hardDesc.x = 1024; hardDesc.y = 1580; self.addChild(hardDesc); // Nightmare var nightmareText = new Text2('NIGHTMARE', { size: 60, fill: 0xFF0000, align: 'center' }); nightmareText.anchor.set(0.5, 0.5); nightmareText.x = 1024; nightmareText.y = 1800; self.addChild(nightmareText); var nightmareDesc = new Text2('For the truly insane', { size: 50, fill: 0xCCCCCC, align: 'center' }); nightmareDesc.anchor.set(0.5, 0.5); nightmareDesc.x = 1024; nightmareDesc.y = 1880; self.addChild(nightmareDesc); // Selection instruction var selectText = new Text2('TAP TO SELECT DIFFICULTY', { size: 40, fill: 0xFF6666, align: 'center' }); selectText.anchor.set(0.5, 0.5); selectText.x = 1024; selectText.y = 2100; self.addChild(selectText); // Pulsing effect self.pulseTimer = 0; self.update = function () { self.pulseTimer += 0.1; selectText.alpha = 0.5 + Math.sin(self.pulseTimer) * 0.3; moon.alpha = 0.5 + Math.sin(self.pulseTimer * 0.5) * 0.2; }; // Handle difficulty selection self.down = function (x, y, obj) { var selectedDifficulty = 2; // Default to normal if (y > 800 && y < 1100) { selectedDifficulty = 1; // Easy } else if (y > 1100 && y < 1400) { selectedDifficulty = 2; // Normal } else if (y > 1400 && y < 1700) { selectedDifficulty = 3; // Hard } else if (y > 1700 && y < 2000) { selectedDifficulty = 4; // Nightmare } self.destroy(); startGameWithModeAndDifficulty(selectedGameMode, selectedDifficulty); }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 50; // Will be one-shot by 100 damage bullets self.speed = 8; self.damage = 20; self.attackCooldown = 0; self.lastX = 0; self.lastY = 0; self.lastPlayerDistance = 1000; self.update = function () { self.lastX = self.x; self.lastY = self.y; if (self.attackCooldown > 0) { self.attackCooldown--; } // Move towards player if (player) { 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; } // Attack if close enough var currentDistance = distance; if (currentDistance < 50 && self.attackCooldown <= 0) { player.takeDamage(self.damage); self.attackCooldown = 60; } self.lastPlayerDistance = currentDistance; } }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { return true; // Enemy died } return false; }; 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.lifetime = 600; // 10 seconds at 60fps self.update = function () { self.lifetime--; // Pulsing effect healthGraphics.alpha = 0.7 + Math.sin(self.lifetime * 0.2) * 0.3; if (self.lifetime <= 0) { return true; // Should be removed } return false; }; return self; }); var MenuScreen = Container.expand(function () { var self = Container.call(this); // Dark background var background = self.attachAsset('menuBackground', { x: 0, y: 0 }); // Blood moon effect in top right var moon = self.attachAsset('moonGlow', { x: 1600, y: 300, alpha: 0.7, anchorX: 0.5, anchorY: 0.5 }); // Blood splatter decorations var splatter1 = self.attachAsset('bloodSplatter', { x: 200, y: 500, alpha: 0.6, anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 1.2 }); var splatter2 = self.attachAsset('bloodSplatter', { x: 1700, y: 1800, alpha: 0.4, anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 0.7 }); // Main title var titleText = new Text2('NIGHT OF THE\nMASSACRE 3', { size: 120, fill: 0xFF4444, align: 'center' }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; self.addChild(titleText); // Subtitle var subtitleText = new Text2('BLOOD MOON RISING', { size: 60, fill: 0xFFFFFF, align: 'center' }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 1000; self.addChild(subtitleText); // Start instruction var startText = new Text2('TAP ANYWHERE TO BEGIN', { size: 40, fill: 0xCCCCCC, align: 'center' }); startText.anchor.set(0.5, 0.5); startText.x = 1024; startText.y = 1800; self.addChild(startText); // Pulsing effect for start text self.pulseTimer = 0; self.update = function () { self.pulseTimer += 0.1; startText.alpha = 0.5 + Math.sin(self.pulseTimer) * 0.3; // Subtle moon glow animation moon.alpha = 0.5 + Math.sin(self.pulseTimer * 0.5) * 0.2; }; // Handle tap to start self.down = function (x, y, obj) { // Transition to game (this will be handled by destroying menu and starting game) self.destroy(); startGame(); }; return self; }); var ModeSelectionScreen = Container.expand(function () { var self = Container.call(this); // Dark background var background = self.attachAsset('menuBackground', { x: 0, y: 0 }); // Blood moon effect in top right var moon = self.attachAsset('moonGlow', { x: 1600, y: 300, alpha: 0.7, anchorX: 0.5, anchorY: 0.5 }); // Main title var titleText = new Text2('CHOOSE YOUR NIGHTMARE', { size: 80, fill: 0xFF4444, align: 'center' }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; self.addChild(titleText); // Mode 1 - Classic Survival var mode1Text = new Text2('CLASSIC SURVIVAL', { size: 60, fill: 0xFFFFFF, align: 'center' }); mode1Text.anchor.set(0.5, 0.5); mode1Text.x = 1024; mode1Text.y = 1000; self.addChild(mode1Text); var mode1Desc = new Text2('Survive until dawn with limited resources', { size: 50, fill: 0xCCCCCC, align: 'center' }); mode1Desc.anchor.set(0.5, 0.5); mode1Desc.x = 1024; mode1Desc.y = 1080; self.addChild(mode1Desc); // Mode 2 - Endless Nightmare var mode2Text = new Text2('ENDLESS NIGHTMARE', { size: 60, fill: 0xFFFFFF, align: 'center' }); mode2Text.anchor.set(0.5, 0.5); mode2Text.x = 1024; mode2Text.y = 1300; self.addChild(mode2Text); var mode2Desc = new Text2('Face endless waves of increasing horror', { size: 50, fill: 0xCCCCCC, align: 'center' }); mode2Desc.anchor.set(0.5, 0.5); mode2Desc.x = 1024; mode2Desc.y = 1380; self.addChild(mode2Desc); // Mode 3 - Blood Eclipse var mode3Text = new Text2('BLOOD ECLIPSE', { size: 60, fill: 0xFFFFFF, align: 'center' }); mode3Text.anchor.set(0.5, 0.5); mode3Text.x = 1024; mode3Text.y = 1600; self.addChild(mode3Text); var mode3Desc = new Text2('Ultimate challenge with eclipse phases', { size: 50, fill: 0xCCCCCC, align: 'center' }); mode3Desc.anchor.set(0.5, 0.5); mode3Desc.x = 1024; mode3Desc.y = 1680; self.addChild(mode3Desc); // Back instruction var backText = new Text2('TAP TO SELECT MODE', { size: 40, fill: 0xFF6666, align: 'center' }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 2000; self.addChild(backText); // Pulsing effect self.pulseTimer = 0; self.update = function () { self.pulseTimer += 0.1; backText.alpha = 0.5 + Math.sin(self.pulseTimer) * 0.3; moon.alpha = 0.5 + Math.sin(self.pulseTimer * 0.5) * 0.2; }; // Handle mode selection self.down = function (x, y, obj) { selectedGameMode = 1; if (y > 1200 && y < 1400) { selectedGameMode = 2; // Endless Nightmare } else if (y > 1500 && y < 1700) { selectedGameMode = 3; // Blood Eclipse } self.destroy(); showDifficultySelection(); }; return self; }); var NPC = Container.expand(function () { var self = Container.call(this); var npcGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ff00 }); self.health = 80; self.maxHealth = 80; self.speed = 6; self.shootCooldown = 0; self.lastX = 0; self.lastY = 0; self.lastPlayerDistance = 1000; self.update = function () { self.lastX = self.x; self.lastY = self.y; if (self.shootCooldown > 0) { self.shootCooldown--; } // Find nearest enemy to move towards var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } // Also consider boss if (boss) { var dx = boss.x - self.x; var dy = boss.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (!nearestEnemy || distance < nearestDistance) { nearestEnemy = boss; nearestDistance = distance; } } // Move towards nearest enemy if (nearestEnemy && nearestDistance > 100) { var dx = nearestEnemy.x - self.x; var dy = nearestEnemy.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; } } // Keep NPC in bounds if (self.x < 40) self.x = 40; if (self.x > 2008) self.x = 2008; if (self.y < 40) self.y = 40; if (self.y > 2692) self.y = 2692; // Auto-shoot at enemies if (self.shootCooldown <= 0) { self.shootAtEnemies(); } }; self.shootAtEnemies = function () { // Find nearest enemy var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance && distance < 400) { // Only shoot at enemies within 400 pixels nearestDistance = distance; nearestEnemy = enemy; } } // Also consider boss if (boss) { var dx = boss.x - self.x; var dy = boss.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if ((!nearestEnemy || distance < nearestDistance) && distance < 400) { nearestEnemy = boss; nearestDistance = distance; } } // Shoot at nearest enemy if (nearestEnemy) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; var dx = nearestEnemy.x - self.x; var dy = nearestEnemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { bullet.directionX = dx / distance; bullet.directionY = dy / distance; } bullets.push(bullet); game.addChild(bullet); self.shootCooldown = 30; // Slower than player LK.getSound('shoot').play(); } }; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { return true; // NPC died } return false; }; 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.ammo = 30; self.maxAmmo = 30; self.speed = 8; self.shootCooldown = 0; self.lastX = 0; self.lastY = 0; self.update = function () { self.lastX = self.x; self.lastY = self.y; if (self.shootCooldown > 0) { self.shootCooldown--; } // Keep player in bounds if (self.x < 40) self.x = 40; if (self.x > 2008) self.x = 2008; if (self.y < 40) self.y = 40; if (self.y > 2692) self.y = 2692; }; self.takeDamage = function (amount) { self.health -= amount; if (self.health <= 0) { self.health = 0; LK.showGameOver(); } LK.effects.flashObject(self, 0xff0000, 500); }; self.heal = function (amount) { self.health = Math.min(self.maxHealth, self.health + amount); }; self.addAmmo = function (amount) { self.ammo = Math.min(self.maxAmmo, self.ammo + amount); }; self.canShoot = function () { return self.ammo > 0 && self.shootCooldown <= 0; }; self.shoot = function () { if (self.canShoot()) { self.ammo--; self.shootCooldown = 15; return true; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0400ff }); /**** * Game Code ****/ var menuScreen = null; var modeSelectionScreen = null; var difficultySelectionScreen = null; var gameStarted = false; var selectedGameMode = 1; var selectedDifficulty = 2; // 1=easy, 2=normal, 3=hard, 4=nightmare // Game variables var player = null; var enemies = []; var bullets = []; var bazookaBullets = []; var bazooka = null; var healthPacks = []; var ammoBoxes = []; var boss = null; var bossSpawned = false; var npcs = []; var gameTimer = 0; var enemySpawnTimer = 0; var waveNumber = 1; var enemiesKilled = 0; var survivalTime = 0; var eclipsePhase = 0; // 0=normal, 1=blood moon, 2=eclipse var eclipseTimer = 0; var usingBazooka = false; // UI elements var healthText = null; var ammoText = null; var waveText = null; var timeText = null; var eclipseText = null; var bossHealthText = null; var bazookaInstructionText = null; function startGame() { // Show mode selection screen instead of starting game directly showModeSelection(); } function showMenu() { if (!menuScreen) { menuScreen = new MenuScreen(); game.addChild(menuScreen); LK.playMusic('menumusic'); } } function showModeSelection() { if (!modeSelectionScreen) { modeSelectionScreen = new ModeSelectionScreen(); game.addChild(modeSelectionScreen); LK.playMusic('menumusic'); } } function showDifficultySelection() { if (!difficultySelectionScreen) { difficultySelectionScreen = new DifficultySelectionScreen(); game.addChild(difficultySelectionScreen); LK.playMusic('menumusic'); } } function startGameWithMode(mode) { selectedGameMode = mode; gameStarted = true; initializeGame(); } function startGameWithModeAndDifficulty(mode, difficulty) { selectedGameMode = mode; selectedDifficulty = difficulty; gameStarted = true; initializeGame(); } function initializeGame() { // Clear game state enemies = []; bullets = []; bazookaBullets = []; healthPacks = []; ammoBoxes = []; npcs = []; boss = null; bossSpawned = false; gameTimer = 0; enemySpawnTimer = 0; waveNumber = 1; enemiesKilled = 0; survivalTime = 0; eclipsePhase = 0; eclipseTimer = 0; // Create player player = new Player(); player.x = 1024; player.y = 1366; game.addChild(player); // Create bazooka bazooka = new Bazooka(); bazooka.x = 1024; bazooka.y = 2000; game.addChild(bazooka); // Create UI healthText = new Text2('Health: 100', { size: 40, fill: 0x00ff00 }); healthText.x = 150; healthText.y = 150; LK.gui.topLeft.addChild(healthText); ammoText = new Text2('Ammo: 30', { size: 40, fill: 0xffff00 }); ammoText.x = 150; ammoText.y = 200; LK.gui.topLeft.addChild(ammoText); timeText = new Text2('Time: 0:00', { size: 40, fill: 0xffffff }); timeText.anchor.set(1, 0); timeText.x = -50; timeText.y = 150; LK.gui.topRight.addChild(timeText); if (selectedGameMode === 3) { eclipseText = new Text2('Phase: Normal', { size: 40, fill: 0xff6666 }); eclipseText.anchor.set(1, 0); eclipseText.x = -50; eclipseText.y = 200; LK.gui.topRight.addChild(eclipseText); } // Spawn 10 NPCs at game start for (var i = 0; i < 10; i++) { spawnNPC(); } // Create bazooka instruction text bazookaInstructionText = new Text2('BAZOOKA, CLICK TO LAUNCH', { size: 50, fill: 0xffaa00 }); bazookaInstructionText.anchor.set(0.5, 0); bazookaInstructionText.x = bazooka.x; bazookaInstructionText.y = bazooka.y + 30; game.addChild(bazookaInstructionText); // Create bazooka description text with difficulty-based percentages var bazookaChances = [{ target: 85, blank: 12, explode: 3 }, // Easy { target: 75, blank: 15, explode: 10 }, // Normal { target: 65, blank: 20, explode: 15 }, // Hard { target: 50, blank: 25, explode: 25 } // Nightmare ]; var chances = bazookaChances[selectedDifficulty - 1]; var bazookaDescriptionText = new Text2(chances.target + '% target enemy, ' + chances.blank + '% blank ammo, ' + chances.explode + '% self explode', { size: 40, fill: 0xffcc66 }); bazookaDescriptionText.anchor.set(0.5, 0); bazookaDescriptionText.x = bazooka.x; bazookaDescriptionText.y = bazooka.y + 80; game.addChild(bazookaDescriptionText); // Fade out instruction text after 3 seconds tween(bazookaInstructionText, { alpha: 0 }, { duration: 3000, onFinish: function onFinish() { if (bazookaInstructionText) { bazookaInstructionText.destroy(); bazookaInstructionText = null; } } }); // Fade out description text after 3 seconds tween(bazookaDescriptionText, { alpha: 0 }, { duration: 3000, onFinish: function onFinish() { if (bazookaDescriptionText) { bazookaDescriptionText.destroy(); bazookaDescriptionText = null; } } }); // Start background music LK.playMusic('bgmusic'); } function spawnEnemy() { var enemy = new Enemy(); // Spawn from random edge var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top enemy.x = Math.random() * 2048; enemy.y = -30; break; case 1: // Right enemy.x = 2078; enemy.y = Math.random() * 2732; break; case 2: // Bottom enemy.x = Math.random() * 2048; enemy.y = 2762; break; case 3: // Left enemy.x = -30; enemy.y = Math.random() * 2732; break; } // Apply difficulty modifiers var difficultyMultipliers = [{ health: 0.7, speed: 0.8, damage: 0.7 }, // Easy { health: 1.0, speed: 1.0, damage: 1.0 }, // Normal { health: 1.3, speed: 1.2, damage: 1.3 }, // Hard { health: 1.6, speed: 1.4, damage: 1.6 } // Nightmare ]; var multiplier = difficultyMultipliers[selectedDifficulty - 1]; enemy.health = Math.floor(enemy.health * multiplier.health); enemy.speed *= multiplier.speed; enemy.damage = Math.floor(enemy.damage * multiplier.damage); // Adjust enemy stats based on mode and wave if (selectedGameMode === 2) { // Endless Nightmare enemy.health += waveNumber * 10; enemy.speed += waveNumber * 0.3; enemy.damage += waveNumber * 5; } else if (selectedGameMode === 3) { // Blood Eclipse enemy.health += waveNumber * 15; enemy.speed += waveNumber * 0.5; enemy.damage += waveNumber * 8; if (eclipsePhase === 1) { // Blood moon enemy.health *= 1.5; enemy.speed *= 1.3; } else if (eclipsePhase === 2) { // Eclipse enemy.health *= 2; enemy.speed *= 1.5; enemy.damage *= 1.5; } } enemies.push(enemy); game.addChild(enemy); } function spawnHealthPack() { var healthPack = new HealthPack(); healthPack.x = 100 + Math.random() * 1848; healthPack.y = 100 + Math.random() * 2532; healthPacks.push(healthPack); game.addChild(healthPack); } function spawnAmmoBox() { var ammoBox = new AmmoBox(); ammoBox.x = 100 + Math.random() * 1848; ammoBox.y = 100 + Math.random() * 2532; ammoBoxes.push(ammoBox); game.addChild(ammoBox); } function spawnNPC() { var npc = new NPC(); // Spawn near player but not too close var angle = Math.random() * Math.PI * 2; var distance = 150 + Math.random() * 100; // 150-250 pixels from player npc.x = player.x + Math.cos(angle) * distance; npc.y = player.y + Math.sin(angle) * distance; // Keep in bounds if (npc.x < 40) npc.x = 40; if (npc.x > 2008) npc.x = 2008; if (npc.y < 40) npc.y = 40; if (npc.y > 2692) npc.y = 2692; npcs.push(npc); game.addChild(npc); } function spawnBoss() { boss = new Boss(); boss.x = 1024; boss.y = 100; bossSpawned = true; game.addChild(boss); // Create boss health UI bossHealthText = new Text2('BOSS: 100000 / 100000', { size: 50, fill: 0xff0000 }); bossHealthText.anchor.set(0.5, 0); LK.gui.top.addChild(bossHealthText); } function fireBullet(targetX, targetY) { if (player && player.shoot() && !usingBazooka) { var bullet = new Bullet(); bullet.x = player.x; bullet.y = player.y; // Find nearest enemy to target var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - player.x; var dy = enemy.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } // If we found an enemy, target it; otherwise use tap location var dx, dy, distance; if (nearestEnemy) { dx = nearestEnemy.x - player.x; dy = nearestEnemy.y - player.y; } else { dx = targetX - player.x; dy = targetY - player.y; } distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { bullet.directionX = dx / distance; bullet.directionY = dy / distance; } bullets.push(bullet); game.addChild(bullet); // Play shooting sound LK.getSound('shoot').play(); } } function updateGameMode() { gameTimer++; survivalTime = Math.floor(gameTimer / 60); // Spawn boss at 06:00 (360 seconds) - but not in endless nightmare mode if (survivalTime >= 360 && !bossSpawned && selectedGameMode !== 2) { spawnBoss(); } // Mode specific logic if (selectedGameMode === 1) { // Classic Survival // Win condition: survive 5 minutes if (survivalTime >= 300) { LK.showYouWin(); return; } // Spawn enemies based on time if (gameTimer % Math.max(30, 120 - survivalTime) === 0) { spawnEnemy(); } // Spawn resources occasionally (adjusted by difficulty) var resourceMultipliers = [0.7, 1.0, 1.4, 2.0]; // Easy, Normal, Hard, Nightmare var resourceDelay = resourceMultipliers[selectedDifficulty - 1]; if (gameTimer % Math.floor(600 * resourceDelay) === 0) spawnHealthPack(); if (gameTimer % Math.floor(900 * resourceDelay) === 0) spawnAmmoBox(); // NPCs already spawned at game start - no additional spawning needed } else if (selectedGameMode === 2) { // Endless Nightmare // New wave every 30 seconds var newWave = Math.floor(survivalTime / 30) + 1; if (newWave > waveNumber) { waveNumber = newWave; } // Spawn enemies more frequently as waves progress var spawnRate = Math.max(10, 60 - waveNumber * 3); if (gameTimer % spawnRate === 0) { spawnEnemy(); } // Spawn resources based on wave (adjusted by difficulty) var resourceMultipliers = [0.7, 1.0, 1.4, 2.0]; // Easy, Normal, Hard, Nightmare var resourceDelay = resourceMultipliers[selectedDifficulty - 1]; if (gameTimer % Math.floor((600 - waveNumber * 20) * resourceDelay) === 0) spawnHealthPack(); if (gameTimer % Math.floor((900 - waveNumber * 30) * resourceDelay) === 0) spawnAmmoBox(); // NPCs already spawned at game start - no additional spawning needed } else if (selectedGameMode === 3) { // Blood Eclipse eclipseTimer++; // Eclipse phases: 90s normal, 60s blood moon, 30s eclipse, repeat var cycleTime = eclipseTimer % (180 * 60); // 3 minutes cycle if (cycleTime < 90 * 60) { eclipsePhase = 0; // Normal } else if (cycleTime < 150 * 60) { eclipsePhase = 1; // Blood moon } else { eclipsePhase = 2; // Eclipse } // Spawn rate increases with phase var spawnRate = [60, 30, 15][eclipsePhase]; if (gameTimer % spawnRate === 0) { spawnEnemy(); } // Resources spawn less during eclipse phases (adjusted by difficulty) var resourceRate = [600, 800, 1200][eclipsePhase]; var resourceMultipliers = [0.7, 1.0, 1.4, 2.0]; // Easy, Normal, Hard, Nightmare var adjustedRate = Math.floor(resourceRate * resourceMultipliers[selectedDifficulty - 1]); if (gameTimer % adjustedRate === 0) spawnHealthPack(); if (gameTimer % Math.floor(adjustedRate * 1.5) === 0) spawnAmmoBox(); // NPCs already spawned at game start - no additional spawning needed } } function updateUI() { if (healthText) { healthText.setText('Health: ' + player.health); healthText.fill = player.health > 30 ? 0x00ff00 : 0xff0000; } if (ammoText) { ammoText.setText('Ammo: ' + player.ammo); ammoText.fill = player.ammo > 5 ? 0xffff00 : 0xff0000; } if (timeText) { var minutes = Math.floor(survivalTime / 60); var seconds = survivalTime % 60; timeText.setText('Time: ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds); } if (eclipseText && selectedGameMode === 3) { var phases = ['Normal', 'Blood Moon', 'Eclipse']; eclipseText.setText('Phase: ' + phases[eclipsePhase]); eclipseText.fill = [0xffffff, 0xff6666, 0x660000][eclipsePhase]; } if (bossHealthText && boss) { bossHealthText.setText('BOSS: ' + boss.health + ' / ' + boss.maxHealth); } } // Show menu on game start showMenu(); game.down = function (x, y, obj) { if (gameStarted && player) { fireBullet(x, y); } }; game.move = function (x, y, obj) { if (gameStarted && player) { player.x = x; player.y = y; } }; game.update = function () { if (!gameStarted) { return; } if (!player) return; // Update game mode logic updateGameMode(); // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].update(); // Check if enemy should be removed if (enemies[i].health <= 0) { enemies[i].destroy(); enemies.splice(i, 1); enemiesKilled++; } } // Update NPCs for (var i = npcs.length - 1; i >= 0; i--) { var npc = npcs[i]; npc.update(); // Check if NPC died if (npc.health <= 0) { npc.destroy(); npcs.splice(i, 1); continue; } // Check NPC-enemy collisions (enemies can attack NPCs) for (var j = 0; j < enemies.length; j++) { var enemy = enemies[j]; var dx = enemy.x - npc.x; var dy = enemy.y - npc.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50 && enemy.attackCooldown <= 0) { npc.takeDamage(enemy.damage); enemy.attackCooldown = 60; break; } } // Check NPC-boss collision if (boss) { var dx = boss.x - npc.x; var dy = boss.y - npc.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100 && boss.attackCooldown <= 0) { npc.takeDamage(boss.damage); boss.attackCooldown = 60; } } } // Update boss if (boss) { boss.update(); // Check if boss died if (boss.health <= 0) { boss.destroy(); boss = null; bossSpawned = false; if (bossHealthText) { bossHealthText.destroy(); bossHealthText = null; } LK.showGameOver(); } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; var shouldRemove = bullet.update(); if (shouldRemove) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check bullet-enemy collisions for (var j = enemies.length - 1; j >= 0; j--) { if (bullet.intersects(enemies[j])) { var enemyDied = enemies[j].takeDamage(bullet.damage); bullet.destroy(); bullets.splice(i, 1); if (enemyDied) { enemies[j].destroy(); enemies.splice(j, 1); enemiesKilled++; } break; } } // Check bullet-boss collision if (boss && bullet.intersects(boss)) { var bossDied = boss.takeDamage(bullet.damage); bullet.destroy(); bullets.splice(i, 1); if (bossDied) { boss.destroy(); boss = null; bossSpawned = false; if (bossHealthText) { bossHealthText.destroy(); bossHealthText = null; } LK.showGameOver(); } break; } } // Update bazooka bullets for (var i = bazookaBullets.length - 1; i >= 0; i--) { var bullet = bazookaBullets[i]; var shouldRemove = bullet.update(); if (shouldRemove) { bullet.explode(); bullet.destroy(); bazookaBullets.splice(i, 1); continue; } // Check bazooka bullet-enemy collisions for (var j = enemies.length - 1; j >= 0; j--) { if (bullet.intersects(enemies[j])) { bullet.explode(); bullet.destroy(); bazookaBullets.splice(i, 1); break; } } // Check bazooka bullet-boss collision if (boss && bullet.intersects(boss)) { bullet.explode(); bullet.destroy(); bazookaBullets.splice(i, 1); break; } } // Update bazooka if (bazooka) { bazooka.update(); } // Update health packs for (var i = healthPacks.length - 1; i >= 0; i--) { var pack = healthPacks[i]; var shouldRemove = pack.update(); if (shouldRemove) { pack.destroy(); healthPacks.splice(i, 1); continue; } // Check player collision if (player.intersects(pack)) { player.heal(pack.healAmount); LK.getSound('heal').play(); pack.destroy(); healthPacks.splice(i, 1); } } // Update ammo boxes for (var i = ammoBoxes.length - 1; i >= 0; i--) { var box = ammoBoxes[i]; var shouldRemove = box.update(); if (shouldRemove) { box.destroy(); ammoBoxes.splice(i, 1); continue; } // Check player collision if (player.intersects(box)) { player.addAmmo(box.ammoAmount); LK.getSound('ammo').play(); box.destroy(); ammoBoxes.splice(i, 1); } } // Update UI updateUI(); };
===================================================================
--- original.js
+++ change.js
@@ -744,9 +744,41 @@
self.lastY = self.y;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
- // NPCs stay in their current position and don't follow player
+ // Find nearest enemy to move towards
+ var nearestEnemy = null;
+ var nearestDistance = Infinity;
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ var dx = enemy.x - self.x;
+ var dy = enemy.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < nearestDistance) {
+ nearestDistance = distance;
+ nearestEnemy = enemy;
+ }
+ }
+ // Also consider boss
+ if (boss) {
+ var dx = boss.x - self.x;
+ var dy = boss.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (!nearestEnemy || distance < nearestDistance) {
+ nearestEnemy = boss;
+ nearestDistance = distance;
+ }
+ }
+ // Move towards nearest enemy
+ if (nearestEnemy && nearestDistance > 100) {
+ var dx = nearestEnemy.x - self.x;
+ var dy = nearestEnemy.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;
+ }
+ }
// Keep NPC in bounds
if (self.x < 40) self.x = 40;
if (self.x > 2008) self.x = 2008;
if (self.y < 40) self.y = 40;