User prompt
make lasers less deadly
User prompt
My character's hitbox should be smaller
User prompt
bossun özellikleri arasındaki zaman farkını kısalt
User prompt
lazerlerin bir ucu bossta olsun,diğer uçları dışarı dönük olsun ve silahların genişliğini ve boyunu arttır
User prompt
lazerlereri boss kendi elinden ateşlemeli,bossun canını çok arttırki hemen ölmesin ve bir can barı olsun
User prompt
The boss should have more health and be able to attack us with weapons, but his weapons should be different, he should have 3 different weapons, one should shoot bullets like our weapon but the bullets should be bigger and should go everywhere, the other weapon should be a laser weapon and should fire deadly lasers randomly everywhere, the last weapon should be a flamethrower, it should spray flames randomly everywhere
User prompt
There should be a boss at the end of each room.
User prompt
add more room
User prompt
more monster in every room
User prompt
make 10 rooms
User prompt
I don't want my character to be square, I want it to be more human-like.
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'healthText.style.fill = player.health > 50 ? "#00ff00" : player.health > 25 ? "#ffff00" : "#ff0000";' Line Number: 399
Code edit (1 edits merged)
Please save this source code
User prompt
Vault Crawler
Initial prompt
Make me a game with different vault rooms and different creatures (skeleton, zombie, spider) in each room and different weapons coming out of a chest after destroying the creatures in each room, let my character be in pixelart form and only have a gun to start the game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Boss = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'skeleton'; var assetName = self.type; var graphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, // Make boss bigger scaleY: 1.5 }); // Boss has much higher stats switch (self.type) { case 'skeleton': self.health = 500 + currentRoom * 100; self.speed = 1; self.damage = 18; break; case 'zombie': self.health = 600 + currentRoom * 120; self.speed = 0.8; self.damage = 24; break; case 'spider': self.health = 400 + currentRoom * 80; self.speed = 1.5; self.damage = 15; break; } self.maxHealth = self.health; self.lastHealthPercent = 1.0; // Track last health percentage for half health detection self.halfHealthOrbSpawned = false; // Prevent multiple orb spawns // Create health bar self.healthBarBg = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 0.2, y: -80 }); self.healthBarBg.tint = 0x666666; self.healthBar = self.attachAsset('wall', { anchorX: 0, anchorY: 0.5, scaleX: 2, scaleY: 0.15, x: -64, y: -80 }); self.healthBar.tint = 0x00ff00; self.lastAttack = 0; self.attackRate = 45; // Faster attack rate self.isBoss = true; // Boss special attack timer self.specialAttackTimer = 0; self.specialAttackCooldown = 120; // 2 seconds at 60fps self.takeDamage = function (damage) { self.health -= damage; // Update health bar var healthPercent = self.health / self.maxHealth; self.healthBar.scaleX = 2 * healthPercent; // Check if boss health dropped to half (50% or below) for the first time if (self.lastHealthPercent > 0.5 && healthPercent <= 0.5 && !self.halfHealthOrbSpawned) { // Spawn health orb at random location var healthOrb = new HealthOrb(); healthOrb.x = 300 + Math.random() * (2048 - 600); // Random x position avoiding walls healthOrb.y = 400 + Math.random() * (2000 - 400); // Random y position avoiding walls healthOrbs.push(healthOrb); game.addChild(healthOrb); self.halfHealthOrbSpawned = true; // Mark as spawned to prevent duplicates } // Update last health percentage for next comparison self.lastHealthPercent = healthPercent; // Change health bar color based on health if (healthPercent > 0.6) { self.healthBar.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { self.healthBar.tint = 0xffff00; // Yellow } else { self.healthBar.tint = 0xff0000; // Red } // Flash red when taking damage (different color for boss) tween(graphics, { tint: 0xFF4444 }, { duration: 150, onFinish: function onFinish() { tween(graphics, { tint: 0xFFFFFF }, { duration: 150 }); } }); if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('enemyDeath').play(); enemiesKilled++; bossKilled = true; // Remove from enemies array for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); }; self.moveTowardsPlayer = function () { 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; } }; self.canAttack = function () { return LK.ticks - self.lastAttack >= self.attackRate; }; self.attackPlayer = function () { if (self.canAttack()) { player.takeDamage(self.damage); self.lastAttack = LK.ticks; } }; self.weaponMode = 0; // 0 = scatter, 1 = laser, 2 = flamethrower self.weaponTimer = 0; self.weaponSwitchInterval = 120; // Switch weapons every 2 seconds self.scatterAttack = function () { // Shoot bigger bullets in all directions var directions = 12; for (var i = 0; i < directions; i++) { var angle = i / directions * Math.PI * 2; var bossBullet = new BossBullet(); bossBullet.x = self.x; bossBullet.y = self.y; bossBullet.velocityX = Math.cos(angle) * 4; bossBullet.velocityY = Math.sin(angle) * 4; bossBullets.push(bossBullet); game.addChild(bossBullet); } }; self.laserAttack = function () { // Create deadly lasers fired from boss position outward in different directions for (var i = 0; i < 8; i++) { var laser = new Laser(); laser.angle = i / 8 * Math.PI * 2; // Spread lasers in 8 directions // Position laser at boss location laser.x = self.x; laser.y = self.y; // Set laser rotation to point outward from boss laser.rotation = laser.angle; // Move laser outward from boss by half its length so one end stays at boss var offsetDistance = 200; // Half of laser length (400/2) laser.x += Math.cos(laser.angle) * offsetDistance; laser.y += Math.sin(laser.angle) * offsetDistance; lasers.push(laser); game.addChild(laser); } }; self.flamethrowerAttack = function () { // Spray flames randomly everywhere for (var i = 0; i < 8; i++) { var flame = new Flame(); flame.x = self.x; flame.y = self.y; var angle = Math.random() * Math.PI * 2; var speed = 2 + Math.random() * 3; flame.velocityX = Math.cos(angle) * speed; flame.velocityY = Math.sin(angle) * speed; flames.push(flame); game.addChild(flame); } }; self.specialAttack = function () { switch (self.weaponMode) { case 0: self.scatterAttack(); break; case 1: self.laserAttack(); break; case 2: self.flamethrowerAttack(); break; } self.specialAttackTimer = 0; }; self.update = function () { self.moveTowardsPlayer(); // Regular attack when close var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 80) { self.attackPlayer(); } // Weapon switching timer self.weaponTimer++; if (self.weaponTimer >= self.weaponSwitchInterval) { self.weaponMode = (self.weaponMode + 1) % 3; // Cycle through 0, 1, 2 self.weaponTimer = 0; } // Special attack timer self.specialAttackTimer++; if (self.specialAttackTimer >= self.specialAttackCooldown) { self.specialAttack(); } }; return self; }); var BossBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bossBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); self.velocityX = 0; self.velocityY = 0; self.damage = 12; self.lifetime = 300; // 5 seconds at 60fps self.age = 0; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.age++; // Remove if lifetime exceeded or off screen if (self.age >= self.lifetime || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.removeBullet(); } }; self.removeBullet = function () { for (var i = bossBullets.length - 1; i >= 0; i--) { if (bossBullets[i] === self) { bossBullets.splice(i, 1); break; } } 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.velocityX = 0; self.velocityY = 0; self.damage = 25; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Remove if off screen if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.removeBullet(); } }; self.removeBullet = function () { for (var i = bullets.length - 1; i >= 0; i--) { if (bullets[i] === self) { bullets.splice(i, 1); break; } } self.destroy(); }; return self; }); var Chest = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('chest', { anchorX: 0.5, anchorY: 0.5 }); self.opened = false; self.open = function () { if (self.opened) return; self.opened = true; graphics.tint = 0x8B4513; // Darken to show it's opened LK.getSound('chestOpen').play(); // Spawn weapon var weapon = new Weapon(); weapon.x = self.x; weapon.y = self.y - 50; weapons.push(weapon); game.addChild(weapon); }; return self; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'skeleton'; var assetName = self.type; var graphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); // Set properties based on enemy type switch (self.type) { case 'skeleton': self.health = 30; self.speed = 1.5; self.damage = 15; break; case 'zombie': self.health = 50; self.speed = 1; self.damage = 20; break; case 'spider': self.health = 20; self.speed = 2.5; self.damage = 10; break; } self.maxHealth = self.health; self.lastAttack = 0; self.attackRate = 60; // frames between attacks self.takeDamage = function (damage) { self.health -= damage; // Flash white when taking damage tween(graphics, { tint: 0xFFFFFF }, { duration: 100, onFinish: function onFinish() { tween(graphics, { tint: 0xFFFFFF }, { duration: 100 }); } }); if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('enemyDeath').play(); enemiesKilled++; // Remove from enemies array for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); }; self.moveTowardsPlayer = function () { 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; } }; self.canAttack = function () { return LK.ticks - self.lastAttack >= self.attackRate; }; self.attackPlayer = function () { if (self.canAttack()) { player.takeDamage(self.damage); self.lastAttack = LK.ticks; } }; self.update = function () { self.moveTowardsPlayer(); // Check if close enough to attack player var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 60) { self.attackPlayer(); } }; return self; }); var Flame = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('flame', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7 }); self.velocityX = 0; self.velocityY = 0; self.damage = 5; self.lifetime = 180; // 3 seconds at 60fps self.age = 0; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.age++; // Add random movement for flame effect self.velocityX += (Math.random() - 0.5) * 0.5; self.velocityY += (Math.random() - 0.5) * 0.5; // Fade out over time graphics.alpha = 1 - self.age / self.lifetime; // Random scale variation var scale = 0.5 + Math.random() * 0.5; graphics.scaleX = scale; graphics.scaleY = scale; // Remove if lifetime exceeded if (self.age >= self.lifetime) { self.removeFlame(); } }; self.removeFlame = function () { for (var i = flames.length - 1; i >= 0; i--) { if (flames[i] === self) { flames.splice(i, 1); break; } } self.destroy(); }; return self; }); var HealthOrb = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('healthOrb', { anchorX: 0.5, anchorY: 0.5 }); self.healAmount = 30; self.pickup = function () { // Restore player health player.health = Math.min(player.maxHealth, player.health + self.healAmount); LK.getSound('weaponPickup').play(); // Reuse weapon pickup sound // Remove from healthOrbs array for (var i = healthOrbs.length - 1; i >= 0; i--) { if (healthOrbs[i] === self) { healthOrbs.splice(i, 1); break; } } self.destroy(); }; return self; }); var Laser = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); self.damage = 6; self.lifetime = 60; // 1 second at 60fps self.age = 0; self.lastDamage = 0; // Track when damage was last dealt self.damageCooldown = 30; // 0.5 seconds between damage self.update = function () { self.age++; // Pulse effect var pulse = Math.sin(self.age * 0.3) * 0.3 + 0.7; graphics.alpha = pulse; // Remove after lifetime if (self.age >= self.lifetime) { self.removeLaser(); } }; self.removeLaser = function () { for (var i = lasers.length - 1; i >= 0; i--) { if (lasers[i] === self) { lasers.splice(i, 1); break; } } self.destroy(); }; return self; }); var PistolBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); self.velocityX = 0; self.velocityY = 0; self.damage = 25; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Remove if off screen if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.removeBullet(); } }; self.removeBullet = function () { for (var i = pistolBullets.length - 1; i >= 0; i--) { if (pistolBullets[i] === self) { pistolBullets.splice(i, 1); break; } } self.destroy(); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var legs = self.attachAsset('floor', { anchorX: 0.5, anchorY: 0, x: 0, y: 67, scaleX: 0.8, scaleY: 0.6 }); var body = self.attachAsset('playerBody', { anchorX: 0.5, anchorY: 0.5 }); var head = self.attachAsset('playerHead', { anchorX: 0.5, anchorY: 1.0, x: 0, y: -40 }); var graphics = body; // Keep reference for damage effects // Add weapon graphics to player var pistolGraphic = self.attachAsset('pistol', { anchorX: 0, anchorY: 0.5, x: 40, y: 0, scaleX: 2, scaleY: 2 }); var shotgunGraphic = self.attachAsset('shotgun', { anchorX: 0, anchorY: 0.5, x: 40, y: 0, scaleX: 2, scaleY: 2 }); var sniperGraphic = self.attachAsset('sniper', { anchorX: 0, anchorY: 0.5, x: 40, y: 0, scaleX: 2, scaleY: 2 }); // Create smaller hitbox for collision detection self.hitbox = self.attachAsset('playerBody', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, alpha: 0 // Make invisible }); self.health = 100; self.maxHealth = 100; self.speed = 4; self.weapon = 'pistol'; // Start with pistol self.currentWeaponIndex = 0; self.weapons = ['pistol', 'shotgun', 'sniper']; self.fireRate = 15; // frames between shots self.lastShot = 0; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; LK.showGameOver(); } // Flash red when taking damage tween(graphics, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(graphics, { tint: 0xFFFFFF }, { duration: 200 }); } }); }; self.moveTowards = function (targetX, targetY) { var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 10) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Keep player within room bounds self.x = Math.max(128, Math.min(2048 - 128, self.x)); self.y = Math.max(200, Math.min(2400, self.y)); } // Update weapon rotation to face target direction var angle = Math.atan2(dy, dx); pistolGraphic.rotation = angle; shotgunGraphic.rotation = angle; sniperGraphic.rotation = angle; }; self.canShoot = function () { return LK.ticks - self.lastShot >= self.fireRate; }; self.shoot = function (targetX, targetY) { if (!self.canShoot()) return; var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var normalizedX = dx / distance; var normalizedY = dy / distance; if (self.weapon === 'pistol') { var bullet = new PistolBullet(); bullet.x = self.x; bullet.y = self.y; bullet.velocityX = normalizedX * 8; bullet.velocityY = normalizedY * 8; pistolBullets.push(bullet); game.addChild(bullet); self.fireRate = 30; } else if (self.weapon === 'shotgun') { // Fire 3 bullets in spread pattern for (var i = 0; i < 3; i++) { var bullet = new ShotgunBullet(); bullet.x = self.x; bullet.y = self.y; // Add spread to the shots var spreadAngle = (i - 1) * 0.3; // -0.3, 0, 0.3 radians spread var angle = Math.atan2(dy, dx) + spreadAngle; bullet.velocityX = Math.cos(angle) * 6; bullet.velocityY = Math.sin(angle) * 6; shotgunBullets.push(bullet); game.addChild(bullet); } self.fireRate = 120; // 2 second cooldown } else if (self.weapon === 'sniper') { var bullet = new SniperBullet(); bullet.x = self.x; bullet.y = self.y; bullet.velocityX = normalizedX * 12; // Faster bullet bullet.velocityY = normalizedY * 12; sniperBullets.push(bullet); game.addChild(bullet); self.fireRate = 180; // 3 second cooldown } self.lastShot = LK.ticks; LK.getSound('shoot').play(); }; self.updateWeaponGraphics = function () { // Hide all weapons first pistolGraphic.alpha = 0; shotgunGraphic.alpha = 0; sniperGraphic.alpha = 0; // Show current weapon switch (self.weapon) { case 'pistol': pistolGraphic.alpha = 1; break; case 'shotgun': shotgunGraphic.alpha = 1; break; case 'sniper': sniperGraphic.alpha = 1; break; } }; self.switchWeapon = function () { self.currentWeaponIndex = (self.currentWeaponIndex + 1) % self.weapons.length; self.weapon = self.weapons[self.currentWeaponIndex]; // Update weapon indicator weaponText.setText('Weapon: ' + self.weapon.charAt(0).toUpperCase() + self.weapon.slice(1)); // Update weapon graphics self.updateWeaponGraphics(); }; // Override intersects method to use smaller hitbox self.intersects = function (other) { return self.hitbox.intersects(other); }; // Initialize weapon graphics self.updateWeaponGraphics(); return self; }); var ShotgunBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); self.velocityX = 0; self.velocityY = 0; self.damage = 15; self.distanceTraveled = 0; self.maxDistance = 300; // Shotgun has limited range self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.distanceTraveled += Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY); // Remove if off screen or max distance reached if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732 || self.distanceTraveled > self.maxDistance) { self.removeBullet(); } }; self.removeBullet = function () { for (var i = shotgunBullets.length - 1; i >= 0; i--) { if (shotgunBullets[i] === self) { shotgunBullets.splice(i, 1); break; } } self.destroy(); }; return self; }); var SniperBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); graphics.tint = 0xffd700; // Golden color for sniper bullets self.velocityX = 0; self.velocityY = 0; self.damage = 60; // High damage for long range self.distanceTraveled = 0; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.distanceTraveled += Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY); // Remove if off screen if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.removeBullet(); } }; self.removeBullet = function () { for (var i = sniperBullets.length - 1; i >= 0; i--) { if (sniperBullets[i] === self) { sniperBullets.splice(i, 1); break; } } self.destroy(); }; return self; }); var Weapon = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('weapon', { anchorX: 0.5, anchorY: 0.5 }); self.weaponType = 'rifle'; self.pickup = function () { player.weapon = self.weaponType; player.fireRate = Math.max(5, player.fireRate - 3); // Faster firing LK.getSound('weaponPickup').play(); // Update weapon indicator weaponText.setText('Weapon: ' + self.weaponType.charAt(0).toUpperCase() + self.weaponType.slice(1)); // Update weapon graphics player.updateWeaponGraphics(); // Remove from weapons array for (var i = weapons.length - 1; i >= 0; i--) { if (weapons[i] === self) { weapons.splice(i, 1); break; } } self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Game variables var player; var enemies = []; var bullets = []; var pistolBullets = []; var shotgunBullets = []; var sniperBullets = []; var bossBullets = []; var lasers = []; var flames = []; var weapons = []; var healthOrbs = []; var chest; var currentRoom = 1; var enemiesKilled = 0; var totalEnemiesInRoom = 0; var roomCleared = false; var targetX = 1024; var targetY = 1366; var bossSpawned = false; var bossKilled = false; // UI elements var scoreText = new Text2('Room: 1', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var healthText = new Text2('Health: 100', { size: 50, fill: 0x00FF00 }); healthText.anchor.set(0, 0); healthText.x = 20; healthText.y = 20; LK.gui.topLeft.addChild(healthText); // Weapon indicator in top right var weaponText = new Text2('Weapon: Pistol', { size: 50, fill: 0xFFFFFF }); weaponText.anchor.set(1, 0); weaponText.y = 20; LK.gui.topRight.addChild(weaponText); // Visual weapon icons var pistolIcon = LK.getAsset('pistol', { anchorX: 1, anchorY: 0, x: -20, y: 80 }); var shotgunIcon = LK.getAsset('shotgun', { anchorX: 1, anchorY: 0, x: -20, y: 120 }); var sniperIcon = LK.getAsset('sniper', { anchorX: 1, anchorY: 0, x: -20, y: 160 }); LK.gui.topRight.addChild(pistolIcon); LK.gui.topRight.addChild(shotgunIcon); LK.gui.topRight.addChild(sniperIcon); // Function to update weapon icon highlights function updateWeaponIcons() { pistolIcon.alpha = player.weapon === 'pistol' ? 1.0 : 0.5; shotgunIcon.alpha = player.weapon === 'shotgun' ? 1.0 : 0.5; sniperIcon.alpha = player.weapon === 'sniper' ? 1.0 : 0.5; } // Create floor tiles function createRoom() { // Clear existing room elements roomCleared = false; enemiesKilled = 0; // Create floor for (var x = 0; x < 32; x++) { for (var y = 3; y < 38; y++) { var floor = game.addChild(LK.getAsset('floor', { x: x * 64, y: y * 64 })); } } // Create walls around the room for (var x = 0; x < 32; x++) { // Top wall var topWall = game.addChild(LK.getAsset('wall', { x: x * 64, y: 2 * 64 })); // Bottom wall var bottomWall = game.addChild(LK.getAsset('wall', { x: x * 64, y: 38 * 64 })); } for (var y = 2; y < 39; y++) { // Left wall var leftWall = game.addChild(LK.getAsset('wall', { x: 0, y: y * 64 })); // Right wall var rightWall = game.addChild(LK.getAsset('wall', { x: 31 * 64, y: y * 64 })); } } function getRoomType() { if (currentRoom <= 20) return "Tutorial"; if (currentRoom <= 40) return "Swarm"; if (currentRoom <= 60) return "Elite"; if (currentRoom <= 80) return "Nightmare"; return "Hell"; } function spawnEnemiesForRoomType() { var roomType = getRoomType(); bossSpawned = false; bossKilled = false; switch (roomType) { case "Tutorial": spawnTutorialEnemies(); break; case "Swarm": spawnSwarmEnemies(); break; case "Elite": spawnEliteEnemies(); break; case "Nightmare": spawnNightmareEnemies(); break; case "Hell": spawnHellEnemies(); break; } } function spawnTutorialEnemies() { var enemyTypes = ['skeleton', 'zombie', 'spider']; var numEnemies = Math.min(5 + currentRoom * 2, 15); totalEnemiesInRoom = numEnemies; for (var i = 0; i < numEnemies; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); // Random position in room, avoiding walls enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } } function spawnSwarmEnemies() { // Rooms 21-40: More enemies, faster movement var enemyTypes = ['skeleton', 'zombie', 'spider']; var numEnemies = Math.min(8 + (currentRoom - 20) * 3, 25); totalEnemiesInRoom = numEnemies; for (var i = 0; i < numEnemies; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); // Boost stats for swarm section enemy.speed *= 1.5; enemy.health = Math.floor(enemy.health * 0.7); // Less health but more enemies enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } } function spawnEliteEnemies() { // Rooms 41-60: Fewer but much stronger enemies var enemyTypes = ['skeleton', 'zombie', 'spider']; var numEnemies = Math.min(3 + Math.floor((currentRoom - 40) / 2), 8); totalEnemiesInRoom = numEnemies; for (var i = 0; i < numEnemies; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); // Elite stats - much stronger enemy.health *= 3; enemy.maxHealth = enemy.health; enemy.damage *= 2; enemy.speed *= 1.2; // Make them visually bigger to show they're elite enemy.scaleX = 1.5; enemy.scaleY = 1.5; enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } } function spawnNightmareEnemies() { // Rooms 61-80: Mix of swarm and elite + boss every 5 rooms var enemyTypes = ['skeleton', 'zombie', 'spider']; var numRegular = Math.min(6 + Math.floor((currentRoom - 60) / 3), 12); var numElite = Math.min(2 + Math.floor((currentRoom - 60) / 5), 4); totalEnemiesInRoom = numRegular + numElite; // Spawn regular enemies for (var i = 0; i < numRegular; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); enemy.speed *= 1.3; enemy.health *= 1.5; enemy.maxHealth = enemy.health; enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } // Spawn elite enemies for (var i = 0; i < numElite; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); enemy.health *= 4; enemy.maxHealth = enemy.health; enemy.damage *= 2.5; enemy.speed *= 1.4; enemy.scaleX = 1.8; enemy.scaleY = 1.8; enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } } function spawnHellEnemies() { // Rooms 81-100: Ultimate challenge - everything is maxed var enemyTypes = ['skeleton', 'zombie', 'spider']; var numRegular = Math.min(10 + (currentRoom - 80), 20); var numElite = Math.min(3 + Math.floor((currentRoom - 80) / 2), 6); var numBosses = currentRoom % 10 === 0 ? 2 : 1; // Double boss every 10th room totalEnemiesInRoom = numRegular + numElite + numBosses; bossSpawned = true; // Always spawn boss in hell mode bossKilled = false; // Spawn regular enemies for (var i = 0; i < numRegular; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); enemy.speed *= 2; enemy.health *= 2; enemy.maxHealth = enemy.health; enemy.damage *= 1.5; enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } // Spawn elite enemies for (var i = 0; i < numElite; i++) { var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var enemy = new Enemy(enemyType); enemy.health *= 6; enemy.maxHealth = enemy.health; enemy.damage *= 3; enemy.speed *= 1.8; enemy.scaleX = 2; enemy.scaleY = 2; enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = 300 + Math.random() * (2200 - 400); enemies.push(enemy); game.addChild(enemy); } // Spawn boss(es) for (var i = 0; i < numBosses; i++) { var bossType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var boss = new Boss(bossType); // Hell mode boss gets extra stats boss.health *= 2; boss.maxHealth = boss.health; boss.damage *= 1.5; boss.speed *= 1.3; boss.scaleX = 2.5; boss.scaleY = 2.5; boss.x = 1024 + (i * 200 - 100); // Spread multiple bosses boss.y = 1000; enemies.push(boss); game.addChild(boss); } } function spawnEnemies() { spawnTutorialEnemies(); } function spawnBoss() { if (!bossSpawned) { var enemyTypes = ['skeleton', 'zombie', 'spider']; var bossType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; var boss = new Boss(bossType); // Scale boss based on room type var roomType = getRoomType(); if (roomType === "Elite") { boss.health *= 1.5; boss.maxHealth = boss.health; boss.damage *= 1.3; } else if (roomType === "Nightmare") { boss.health *= 2; boss.maxHealth = boss.health; boss.damage *= 1.5; boss.speed *= 1.2; } else if (roomType === "Hell") { boss.health *= 3; boss.maxHealth = boss.health; boss.damage *= 2; boss.speed *= 1.5; boss.scaleX = 2; boss.scaleY = 2; } // Spawn boss in center of room boss.x = 1024; boss.y = 1000; enemies.push(boss); game.addChild(boss); bossSpawned = true; totalEnemiesInRoom++; // Add boss to total count } } function spawnChest() { chest = new Chest(); chest.x = 1024; chest.y = 1366; game.addChild(chest); // Spawn health orb at random location in room var healthOrb = new HealthOrb(); healthOrb.x = 300 + Math.random() * (2048 - 600); // Random x position avoiding walls healthOrb.y = 400 + Math.random() * (2000 - 400); // Random y position avoiding walls healthOrbs.push(healthOrb); game.addChild(healthOrb); } function nextRoom() { currentRoom++; if (currentRoom > 100) { // Player has completed all 100 rooms - show victory LK.showYouWin(); return; } scoreText.setText('Room: ' + currentRoom + ' - ' + getRoomType()); // Clear current enemies and bullets for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); } enemies = []; for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].destroy(); } bullets = []; // Clear pistol bullets for (var i = pistolBullets.length - 1; i >= 0; i--) { pistolBullets[i].destroy(); } pistolBullets = []; // Clear shotgun bullets for (var i = shotgunBullets.length - 1; i >= 0; i--) { shotgunBullets[i].destroy(); } shotgunBullets = []; // Clear sniper bullets for (var i = sniperBullets.length - 1; i >= 0; i--) { sniperBullets[i].destroy(); } sniperBullets = []; // Clear boss projectiles for (var i = bossBullets.length - 1; i >= 0; i--) { bossBullets[i].destroy(); } bossBullets = []; for (var i = lasers.length - 1; i >= 0; i--) { lasers[i].destroy(); } lasers = []; for (var i = flames.length - 1; i >= 0; i--) { flames[i].destroy(); } flames = []; // Remove chest if exists if (chest) { chest.destroy(); chest = null; } // Clear health orbs for (var i = healthOrbs.length - 1; i >= 0; i--) { healthOrbs[i].destroy(); } healthOrbs = []; // Spawn enemies based on room type spawnEnemiesForRoomType(); } // Initialize first room createRoom(); // Create player player = new Player(); player.x = 1024; player.y = 2000; game.addChild(player); // Spawn initial enemies spawnEnemies(); // Initialize weapon icons updateWeaponIcons(); // Touch controls game.move = function (x, y, obj) { targetX = x; targetY = y; }; // Right mouse button support for weapon switching game.rightDown = function (x, y, obj) { // Right click - switch weapon player.switchWeapon(); updateWeaponIcons(); }; var touchStartTime = 0; var touchHoldThreshold = 60; // 1 second hold at 60fps game.down = function (x, y, obj) { targetX = x; targetY = y; touchStartTime = LK.ticks; // Record when touch started }; game.up = function (x, y, obj) { var touchDuration = LK.ticks - touchStartTime; // Check if it was a long press (hold for 1+ seconds) if (touchDuration >= touchHoldThreshold) { // Long press - switch weapon player.switchWeapon(); updateWeaponIcons(); } else { // Short tap - shoot towards touch point player.shoot(x, y); } }; // Main game loop game.update = function () { // Update health display healthText.setText('Health: ' + player.health); healthText.fill = player.health > 50 ? "#00ff00" : player.health > 25 ? "#ffff00" : "#ff0000"; // Move player towards target player.moveTowards(targetX, targetY); // Check pistol bullet collisions with enemies for (var i = pistolBullets.length - 1; i >= 0; i--) { var bullet = pistolBullets[i]; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { enemy.takeDamage(bullet.damage); bullet.removeBullet(); break; } } } // Check shotgun bullet collisions with enemies (close range = high damage, far range = low damage) for (var i = shotgunBullets.length - 1; i >= 0; i--) { var bullet = shotgunBullets[i]; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { // Calculate damage based on distance traveled (closer = more damage) var damageMultiplier = Math.max(0.5, 1 - bullet.distanceTraveled / bullet.maxDistance); var actualDamage = Math.floor(bullet.damage * damageMultiplier * 4); // Up to 4x damage at close range enemy.takeDamage(actualDamage); bullet.removeBullet(); break; } } } // Check sniper bullet collisions with enemies (far range = high damage, close range = lower damage) for (var i = sniperBullets.length - 1; i >= 0; i--) { var bullet = sniperBullets[i]; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { // Calculate damage based on distance traveled (farther = more damage) var damageMultiplier = Math.min(2, 0.5 + bullet.distanceTraveled / 400); // Up to 2x damage at long range var actualDamage = Math.floor(bullet.damage * damageMultiplier); enemy.takeDamage(actualDamage); bullet.removeBullet(); break; } } } // Check old bullet collisions with enemies (keep for compatibility) for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; var hitEnemy = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { enemy.takeDamage(bullet.damage); bullet.removeBullet(); hitEnemy = true; break; } } } // Check boss bullet collisions with player for (var i = bossBullets.length - 1; i >= 0; i--) { var bossBullet = bossBullets[i]; if (bossBullet.intersects(player)) { player.takeDamage(bossBullet.damage); bossBullet.removeBullet(); } } // Check laser collisions with player for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; if (laser.intersects(player)) { // Only damage if cooldown has passed if (LK.ticks - laser.lastDamage >= laser.damageCooldown) { player.takeDamage(laser.damage); laser.lastDamage = LK.ticks; } } } // Check flame collisions with player for (var i = flames.length - 1; i >= 0; i--) { var flame = flames[i]; if (flame.intersects(player)) { player.takeDamage(flame.damage); } } // Spawn boss when most enemies are killed (except in Hell mode where boss spawns immediately) var roomType = getRoomType(); if (!bossSpawned && roomType !== "Hell") { var spawnThreshold = roomType === "Tutorial" ? 0.8 : roomType === "Swarm" ? 0.9 : 0.7; if (enemiesKilled >= Math.floor(totalEnemiesInRoom * spawnThreshold)) { spawnBoss(); } } // Check if room is cleared (including boss) if (enemies.length === 0 && totalEnemiesInRoom > 0 && !roomCleared && bossKilled) { roomCleared = true; spawnChest(); } // Check chest interaction if (chest && !chest.opened && player.intersects(chest)) { chest.open(); } // Check weapon pickup for (var i = weapons.length - 1; i >= 0; i--) { var weapon = weapons[i]; if (player.intersects(weapon)) { weapon.pickup(); } } // Check health orb pickup for (var i = healthOrbs.length - 1; i >= 0; i--) { var healthOrb = healthOrbs[i]; if (player.intersects(healthOrb)) { healthOrb.pickup(); } } // Auto advance to next room after chest is opened and weapon picked up if (roomCleared && chest && chest.opened && weapons.length === 0) { if (LK.ticks % 180 === 0) { // Wait 3 seconds nextRoom(); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'skeleton';
var assetName = self.type;
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
// Make boss bigger
scaleY: 1.5
});
// Boss has much higher stats
switch (self.type) {
case 'skeleton':
self.health = 500 + currentRoom * 100;
self.speed = 1;
self.damage = 18;
break;
case 'zombie':
self.health = 600 + currentRoom * 120;
self.speed = 0.8;
self.damage = 24;
break;
case 'spider':
self.health = 400 + currentRoom * 80;
self.speed = 1.5;
self.damage = 15;
break;
}
self.maxHealth = self.health;
self.lastHealthPercent = 1.0; // Track last health percentage for half health detection
self.halfHealthOrbSpawned = false; // Prevent multiple orb spawns
// Create health bar
self.healthBarBg = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.2,
y: -80
});
self.healthBarBg.tint = 0x666666;
self.healthBar = self.attachAsset('wall', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.15,
x: -64,
y: -80
});
self.healthBar.tint = 0x00ff00;
self.lastAttack = 0;
self.attackRate = 45; // Faster attack rate
self.isBoss = true;
// Boss special attack timer
self.specialAttackTimer = 0;
self.specialAttackCooldown = 120; // 2 seconds at 60fps
self.takeDamage = function (damage) {
self.health -= damage;
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = 2 * healthPercent;
// Check if boss health dropped to half (50% or below) for the first time
if (self.lastHealthPercent > 0.5 && healthPercent <= 0.5 && !self.halfHealthOrbSpawned) {
// Spawn health orb at random location
var healthOrb = new HealthOrb();
healthOrb.x = 300 + Math.random() * (2048 - 600); // Random x position avoiding walls
healthOrb.y = 400 + Math.random() * (2000 - 400); // Random y position avoiding walls
healthOrbs.push(healthOrb);
game.addChild(healthOrb);
self.halfHealthOrbSpawned = true; // Mark as spawned to prevent duplicates
}
// Update last health percentage for next comparison
self.lastHealthPercent = healthPercent;
// Change health bar color based on health
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xffff00; // Yellow
} else {
self.healthBar.tint = 0xff0000; // Red
}
// Flash red when taking damage (different color for boss)
tween(graphics, {
tint: 0xFF4444
}, {
duration: 150,
onFinish: function onFinish() {
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('enemyDeath').play();
enemiesKilled++;
bossKilled = true;
// Remove from enemies array
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
};
self.moveTowardsPlayer = function () {
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;
}
};
self.canAttack = function () {
return LK.ticks - self.lastAttack >= self.attackRate;
};
self.attackPlayer = function () {
if (self.canAttack()) {
player.takeDamage(self.damage);
self.lastAttack = LK.ticks;
}
};
self.weaponMode = 0; // 0 = scatter, 1 = laser, 2 = flamethrower
self.weaponTimer = 0;
self.weaponSwitchInterval = 120; // Switch weapons every 2 seconds
self.scatterAttack = function () {
// Shoot bigger bullets in all directions
var directions = 12;
for (var i = 0; i < directions; i++) {
var angle = i / directions * Math.PI * 2;
var bossBullet = new BossBullet();
bossBullet.x = self.x;
bossBullet.y = self.y;
bossBullet.velocityX = Math.cos(angle) * 4;
bossBullet.velocityY = Math.sin(angle) * 4;
bossBullets.push(bossBullet);
game.addChild(bossBullet);
}
};
self.laserAttack = function () {
// Create deadly lasers fired from boss position outward in different directions
for (var i = 0; i < 8; i++) {
var laser = new Laser();
laser.angle = i / 8 * Math.PI * 2; // Spread lasers in 8 directions
// Position laser at boss location
laser.x = self.x;
laser.y = self.y;
// Set laser rotation to point outward from boss
laser.rotation = laser.angle;
// Move laser outward from boss by half its length so one end stays at boss
var offsetDistance = 200; // Half of laser length (400/2)
laser.x += Math.cos(laser.angle) * offsetDistance;
laser.y += Math.sin(laser.angle) * offsetDistance;
lasers.push(laser);
game.addChild(laser);
}
};
self.flamethrowerAttack = function () {
// Spray flames randomly everywhere
for (var i = 0; i < 8; i++) {
var flame = new Flame();
flame.x = self.x;
flame.y = self.y;
var angle = Math.random() * Math.PI * 2;
var speed = 2 + Math.random() * 3;
flame.velocityX = Math.cos(angle) * speed;
flame.velocityY = Math.sin(angle) * speed;
flames.push(flame);
game.addChild(flame);
}
};
self.specialAttack = function () {
switch (self.weaponMode) {
case 0:
self.scatterAttack();
break;
case 1:
self.laserAttack();
break;
case 2:
self.flamethrowerAttack();
break;
}
self.specialAttackTimer = 0;
};
self.update = function () {
self.moveTowardsPlayer();
// Regular attack when close
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
self.attackPlayer();
}
// Weapon switching timer
self.weaponTimer++;
if (self.weaponTimer >= self.weaponSwitchInterval) {
self.weaponMode = (self.weaponMode + 1) % 3; // Cycle through 0, 1, 2
self.weaponTimer = 0;
}
// Special attack timer
self.specialAttackTimer++;
if (self.specialAttackTimer >= self.specialAttackCooldown) {
self.specialAttack();
}
};
return self;
});
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 12;
self.lifetime = 300; // 5 seconds at 60fps
self.age = 0;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.age++;
// Remove if lifetime exceeded or off screen
if (self.age >= self.lifetime || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
self.removeBullet();
}
};
self.removeBullet = function () {
for (var i = bossBullets.length - 1; i >= 0; i--) {
if (bossBullets[i] === self) {
bossBullets.splice(i, 1);
break;
}
}
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.velocityX = 0;
self.velocityY = 0;
self.damage = 25;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if off screen
if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
self.removeBullet();
}
};
self.removeBullet = function () {
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Chest = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('chest', {
anchorX: 0.5,
anchorY: 0.5
});
self.opened = false;
self.open = function () {
if (self.opened) return;
self.opened = true;
graphics.tint = 0x8B4513; // Darken to show it's opened
LK.getSound('chestOpen').play();
// Spawn weapon
var weapon = new Weapon();
weapon.x = self.x;
weapon.y = self.y - 50;
weapons.push(weapon);
game.addChild(weapon);
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'skeleton';
var assetName = self.type;
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Set properties based on enemy type
switch (self.type) {
case 'skeleton':
self.health = 30;
self.speed = 1.5;
self.damage = 15;
break;
case 'zombie':
self.health = 50;
self.speed = 1;
self.damage = 20;
break;
case 'spider':
self.health = 20;
self.speed = 2.5;
self.damage = 10;
break;
}
self.maxHealth = self.health;
self.lastAttack = 0;
self.attackRate = 60; // frames between attacks
self.takeDamage = function (damage) {
self.health -= damage;
// Flash white when taking damage
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('enemyDeath').play();
enemiesKilled++;
// Remove from enemies array
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
};
self.moveTowardsPlayer = function () {
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;
}
};
self.canAttack = function () {
return LK.ticks - self.lastAttack >= self.attackRate;
};
self.attackPlayer = function () {
if (self.canAttack()) {
player.takeDamage(self.damage);
self.lastAttack = LK.ticks;
}
};
self.update = function () {
self.moveTowardsPlayer();
// Check if close enough to attack player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 60) {
self.attackPlayer();
}
};
return self;
});
var Flame = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('flame', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 5;
self.lifetime = 180; // 3 seconds at 60fps
self.age = 0;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.age++;
// Add random movement for flame effect
self.velocityX += (Math.random() - 0.5) * 0.5;
self.velocityY += (Math.random() - 0.5) * 0.5;
// Fade out over time
graphics.alpha = 1 - self.age / self.lifetime;
// Random scale variation
var scale = 0.5 + Math.random() * 0.5;
graphics.scaleX = scale;
graphics.scaleY = scale;
// Remove if lifetime exceeded
if (self.age >= self.lifetime) {
self.removeFlame();
}
};
self.removeFlame = function () {
for (var i = flames.length - 1; i >= 0; i--) {
if (flames[i] === self) {
flames.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var HealthOrb = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('healthOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 30;
self.pickup = function () {
// Restore player health
player.health = Math.min(player.maxHealth, player.health + self.healAmount);
LK.getSound('weaponPickup').play(); // Reuse weapon pickup sound
// Remove from healthOrbs array
for (var i = healthOrbs.length - 1; i >= 0; i--) {
if (healthOrbs[i] === self) {
healthOrbs.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
self.damage = 6;
self.lifetime = 60; // 1 second at 60fps
self.age = 0;
self.lastDamage = 0; // Track when damage was last dealt
self.damageCooldown = 30; // 0.5 seconds between damage
self.update = function () {
self.age++;
// Pulse effect
var pulse = Math.sin(self.age * 0.3) * 0.3 + 0.7;
graphics.alpha = pulse;
// Remove after lifetime
if (self.age >= self.lifetime) {
self.removeLaser();
}
};
self.removeLaser = function () {
for (var i = lasers.length - 1; i >= 0; i--) {
if (lasers[i] === self) {
lasers.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var PistolBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 25;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if off screen
if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
self.removeBullet();
}
};
self.removeBullet = function () {
for (var i = pistolBullets.length - 1; i >= 0; i--) {
if (pistolBullets[i] === self) {
pistolBullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var legs = self.attachAsset('floor', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 67,
scaleX: 0.8,
scaleY: 0.6
});
var body = self.attachAsset('playerBody', {
anchorX: 0.5,
anchorY: 0.5
});
var head = self.attachAsset('playerHead', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -40
});
var graphics = body; // Keep reference for damage effects
// Add weapon graphics to player
var pistolGraphic = self.attachAsset('pistol', {
anchorX: 0,
anchorY: 0.5,
x: 40,
y: 0,
scaleX: 2,
scaleY: 2
});
var shotgunGraphic = self.attachAsset('shotgun', {
anchorX: 0,
anchorY: 0.5,
x: 40,
y: 0,
scaleX: 2,
scaleY: 2
});
var sniperGraphic = self.attachAsset('sniper', {
anchorX: 0,
anchorY: 0.5,
x: 40,
y: 0,
scaleX: 2,
scaleY: 2
});
// Create smaller hitbox for collision detection
self.hitbox = self.attachAsset('playerBody', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0 // Make invisible
});
self.health = 100;
self.maxHealth = 100;
self.speed = 4;
self.weapon = 'pistol'; // Start with pistol
self.currentWeaponIndex = 0;
self.weapons = ['pistol', 'shotgun', 'sniper'];
self.fireRate = 15; // frames between shots
self.lastShot = 0;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
LK.showGameOver();
}
// Flash red when taking damage
tween(graphics, {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
};
self.moveTowards = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Keep player within room bounds
self.x = Math.max(128, Math.min(2048 - 128, self.x));
self.y = Math.max(200, Math.min(2400, self.y));
}
// Update weapon rotation to face target direction
var angle = Math.atan2(dy, dx);
pistolGraphic.rotation = angle;
shotgunGraphic.rotation = angle;
sniperGraphic.rotation = angle;
};
self.canShoot = function () {
return LK.ticks - self.lastShot >= self.fireRate;
};
self.shoot = function (targetX, targetY) {
if (!self.canShoot()) return;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var normalizedX = dx / distance;
var normalizedY = dy / distance;
if (self.weapon === 'pistol') {
var bullet = new PistolBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = normalizedX * 8;
bullet.velocityY = normalizedY * 8;
pistolBullets.push(bullet);
game.addChild(bullet);
self.fireRate = 30;
} else if (self.weapon === 'shotgun') {
// Fire 3 bullets in spread pattern
for (var i = 0; i < 3; i++) {
var bullet = new ShotgunBullet();
bullet.x = self.x;
bullet.y = self.y;
// Add spread to the shots
var spreadAngle = (i - 1) * 0.3; // -0.3, 0, 0.3 radians spread
var angle = Math.atan2(dy, dx) + spreadAngle;
bullet.velocityX = Math.cos(angle) * 6;
bullet.velocityY = Math.sin(angle) * 6;
shotgunBullets.push(bullet);
game.addChild(bullet);
}
self.fireRate = 120; // 2 second cooldown
} else if (self.weapon === 'sniper') {
var bullet = new SniperBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = normalizedX * 12; // Faster bullet
bullet.velocityY = normalizedY * 12;
sniperBullets.push(bullet);
game.addChild(bullet);
self.fireRate = 180; // 3 second cooldown
}
self.lastShot = LK.ticks;
LK.getSound('shoot').play();
};
self.updateWeaponGraphics = function () {
// Hide all weapons first
pistolGraphic.alpha = 0;
shotgunGraphic.alpha = 0;
sniperGraphic.alpha = 0;
// Show current weapon
switch (self.weapon) {
case 'pistol':
pistolGraphic.alpha = 1;
break;
case 'shotgun':
shotgunGraphic.alpha = 1;
break;
case 'sniper':
sniperGraphic.alpha = 1;
break;
}
};
self.switchWeapon = function () {
self.currentWeaponIndex = (self.currentWeaponIndex + 1) % self.weapons.length;
self.weapon = self.weapons[self.currentWeaponIndex];
// Update weapon indicator
weaponText.setText('Weapon: ' + self.weapon.charAt(0).toUpperCase() + self.weapon.slice(1));
// Update weapon graphics
self.updateWeaponGraphics();
};
// Override intersects method to use smaller hitbox
self.intersects = function (other) {
return self.hitbox.intersects(other);
};
// Initialize weapon graphics
self.updateWeaponGraphics();
return self;
});
var ShotgunBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 15;
self.distanceTraveled = 0;
self.maxDistance = 300; // Shotgun has limited range
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.distanceTraveled += Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
// Remove if off screen or max distance reached
if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732 || self.distanceTraveled > self.maxDistance) {
self.removeBullet();
}
};
self.removeBullet = function () {
for (var i = shotgunBullets.length - 1; i >= 0; i--) {
if (shotgunBullets[i] === self) {
shotgunBullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var SniperBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
graphics.tint = 0xffd700; // Golden color for sniper bullets
self.velocityX = 0;
self.velocityY = 0;
self.damage = 60; // High damage for long range
self.distanceTraveled = 0;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.distanceTraveled += Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
// Remove if off screen
if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
self.removeBullet();
}
};
self.removeBullet = function () {
for (var i = sniperBullets.length - 1; i >= 0; i--) {
if (sniperBullets[i] === self) {
sniperBullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Weapon = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('weapon', {
anchorX: 0.5,
anchorY: 0.5
});
self.weaponType = 'rifle';
self.pickup = function () {
player.weapon = self.weaponType;
player.fireRate = Math.max(5, player.fireRate - 3); // Faster firing
LK.getSound('weaponPickup').play();
// Update weapon indicator
weaponText.setText('Weapon: ' + self.weaponType.charAt(0).toUpperCase() + self.weaponType.slice(1));
// Update weapon graphics
player.updateWeaponGraphics();
// Remove from weapons array
for (var i = weapons.length - 1; i >= 0; i--) {
if (weapons[i] === self) {
weapons.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var bullets = [];
var pistolBullets = [];
var shotgunBullets = [];
var sniperBullets = [];
var bossBullets = [];
var lasers = [];
var flames = [];
var weapons = [];
var healthOrbs = [];
var chest;
var currentRoom = 1;
var enemiesKilled = 0;
var totalEnemiesInRoom = 0;
var roomCleared = false;
var targetX = 1024;
var targetY = 1366;
var bossSpawned = false;
var bossKilled = false;
// UI elements
var scoreText = new Text2('Room: 1', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var healthText = new Text2('Health: 100', {
size: 50,
fill: 0x00FF00
});
healthText.anchor.set(0, 0);
healthText.x = 20;
healthText.y = 20;
LK.gui.topLeft.addChild(healthText);
// Weapon indicator in top right
var weaponText = new Text2('Weapon: Pistol', {
size: 50,
fill: 0xFFFFFF
});
weaponText.anchor.set(1, 0);
weaponText.y = 20;
LK.gui.topRight.addChild(weaponText);
// Visual weapon icons
var pistolIcon = LK.getAsset('pistol', {
anchorX: 1,
anchorY: 0,
x: -20,
y: 80
});
var shotgunIcon = LK.getAsset('shotgun', {
anchorX: 1,
anchorY: 0,
x: -20,
y: 120
});
var sniperIcon = LK.getAsset('sniper', {
anchorX: 1,
anchorY: 0,
x: -20,
y: 160
});
LK.gui.topRight.addChild(pistolIcon);
LK.gui.topRight.addChild(shotgunIcon);
LK.gui.topRight.addChild(sniperIcon);
// Function to update weapon icon highlights
function updateWeaponIcons() {
pistolIcon.alpha = player.weapon === 'pistol' ? 1.0 : 0.5;
shotgunIcon.alpha = player.weapon === 'shotgun' ? 1.0 : 0.5;
sniperIcon.alpha = player.weapon === 'sniper' ? 1.0 : 0.5;
}
// Create floor tiles
function createRoom() {
// Clear existing room elements
roomCleared = false;
enemiesKilled = 0;
// Create floor
for (var x = 0; x < 32; x++) {
for (var y = 3; y < 38; y++) {
var floor = game.addChild(LK.getAsset('floor', {
x: x * 64,
y: y * 64
}));
}
}
// Create walls around the room
for (var x = 0; x < 32; x++) {
// Top wall
var topWall = game.addChild(LK.getAsset('wall', {
x: x * 64,
y: 2 * 64
}));
// Bottom wall
var bottomWall = game.addChild(LK.getAsset('wall', {
x: x * 64,
y: 38 * 64
}));
}
for (var y = 2; y < 39; y++) {
// Left wall
var leftWall = game.addChild(LK.getAsset('wall', {
x: 0,
y: y * 64
}));
// Right wall
var rightWall = game.addChild(LK.getAsset('wall', {
x: 31 * 64,
y: y * 64
}));
}
}
function getRoomType() {
if (currentRoom <= 20) return "Tutorial";
if (currentRoom <= 40) return "Swarm";
if (currentRoom <= 60) return "Elite";
if (currentRoom <= 80) return "Nightmare";
return "Hell";
}
function spawnEnemiesForRoomType() {
var roomType = getRoomType();
bossSpawned = false;
bossKilled = false;
switch (roomType) {
case "Tutorial":
spawnTutorialEnemies();
break;
case "Swarm":
spawnSwarmEnemies();
break;
case "Elite":
spawnEliteEnemies();
break;
case "Nightmare":
spawnNightmareEnemies();
break;
case "Hell":
spawnHellEnemies();
break;
}
}
function spawnTutorialEnemies() {
var enemyTypes = ['skeleton', 'zombie', 'spider'];
var numEnemies = Math.min(5 + currentRoom * 2, 15);
totalEnemiesInRoom = numEnemies;
for (var i = 0; i < numEnemies; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
// Random position in room, avoiding walls
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
}
function spawnSwarmEnemies() {
// Rooms 21-40: More enemies, faster movement
var enemyTypes = ['skeleton', 'zombie', 'spider'];
var numEnemies = Math.min(8 + (currentRoom - 20) * 3, 25);
totalEnemiesInRoom = numEnemies;
for (var i = 0; i < numEnemies; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
// Boost stats for swarm section
enemy.speed *= 1.5;
enemy.health = Math.floor(enemy.health * 0.7); // Less health but more enemies
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
}
function spawnEliteEnemies() {
// Rooms 41-60: Fewer but much stronger enemies
var enemyTypes = ['skeleton', 'zombie', 'spider'];
var numEnemies = Math.min(3 + Math.floor((currentRoom - 40) / 2), 8);
totalEnemiesInRoom = numEnemies;
for (var i = 0; i < numEnemies; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
// Elite stats - much stronger
enemy.health *= 3;
enemy.maxHealth = enemy.health;
enemy.damage *= 2;
enemy.speed *= 1.2;
// Make them visually bigger to show they're elite
enemy.scaleX = 1.5;
enemy.scaleY = 1.5;
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
}
function spawnNightmareEnemies() {
// Rooms 61-80: Mix of swarm and elite + boss every 5 rooms
var enemyTypes = ['skeleton', 'zombie', 'spider'];
var numRegular = Math.min(6 + Math.floor((currentRoom - 60) / 3), 12);
var numElite = Math.min(2 + Math.floor((currentRoom - 60) / 5), 4);
totalEnemiesInRoom = numRegular + numElite;
// Spawn regular enemies
for (var i = 0; i < numRegular; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
enemy.speed *= 1.3;
enemy.health *= 1.5;
enemy.maxHealth = enemy.health;
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn elite enemies
for (var i = 0; i < numElite; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
enemy.health *= 4;
enemy.maxHealth = enemy.health;
enemy.damage *= 2.5;
enemy.speed *= 1.4;
enemy.scaleX = 1.8;
enemy.scaleY = 1.8;
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
}
function spawnHellEnemies() {
// Rooms 81-100: Ultimate challenge - everything is maxed
var enemyTypes = ['skeleton', 'zombie', 'spider'];
var numRegular = Math.min(10 + (currentRoom - 80), 20);
var numElite = Math.min(3 + Math.floor((currentRoom - 80) / 2), 6);
var numBosses = currentRoom % 10 === 0 ? 2 : 1; // Double boss every 10th room
totalEnemiesInRoom = numRegular + numElite + numBosses;
bossSpawned = true; // Always spawn boss in hell mode
bossKilled = false;
// Spawn regular enemies
for (var i = 0; i < numRegular; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
enemy.speed *= 2;
enemy.health *= 2;
enemy.maxHealth = enemy.health;
enemy.damage *= 1.5;
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn elite enemies
for (var i = 0; i < numElite; i++) {
var enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var enemy = new Enemy(enemyType);
enemy.health *= 6;
enemy.maxHealth = enemy.health;
enemy.damage *= 3;
enemy.speed *= 1.8;
enemy.scaleX = 2;
enemy.scaleY = 2;
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 300 + Math.random() * (2200 - 400);
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn boss(es)
for (var i = 0; i < numBosses; i++) {
var bossType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var boss = new Boss(bossType);
// Hell mode boss gets extra stats
boss.health *= 2;
boss.maxHealth = boss.health;
boss.damage *= 1.5;
boss.speed *= 1.3;
boss.scaleX = 2.5;
boss.scaleY = 2.5;
boss.x = 1024 + (i * 200 - 100); // Spread multiple bosses
boss.y = 1000;
enemies.push(boss);
game.addChild(boss);
}
}
function spawnEnemies() {
spawnTutorialEnemies();
}
function spawnBoss() {
if (!bossSpawned) {
var enemyTypes = ['skeleton', 'zombie', 'spider'];
var bossType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
var boss = new Boss(bossType);
// Scale boss based on room type
var roomType = getRoomType();
if (roomType === "Elite") {
boss.health *= 1.5;
boss.maxHealth = boss.health;
boss.damage *= 1.3;
} else if (roomType === "Nightmare") {
boss.health *= 2;
boss.maxHealth = boss.health;
boss.damage *= 1.5;
boss.speed *= 1.2;
} else if (roomType === "Hell") {
boss.health *= 3;
boss.maxHealth = boss.health;
boss.damage *= 2;
boss.speed *= 1.5;
boss.scaleX = 2;
boss.scaleY = 2;
}
// Spawn boss in center of room
boss.x = 1024;
boss.y = 1000;
enemies.push(boss);
game.addChild(boss);
bossSpawned = true;
totalEnemiesInRoom++; // Add boss to total count
}
}
function spawnChest() {
chest = new Chest();
chest.x = 1024;
chest.y = 1366;
game.addChild(chest);
// Spawn health orb at random location in room
var healthOrb = new HealthOrb();
healthOrb.x = 300 + Math.random() * (2048 - 600); // Random x position avoiding walls
healthOrb.y = 400 + Math.random() * (2000 - 400); // Random y position avoiding walls
healthOrbs.push(healthOrb);
game.addChild(healthOrb);
}
function nextRoom() {
currentRoom++;
if (currentRoom > 100) {
// Player has completed all 100 rooms - show victory
LK.showYouWin();
return;
}
scoreText.setText('Room: ' + currentRoom + ' - ' + getRoomType());
// Clear current enemies and bullets
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
bullets = [];
// Clear pistol bullets
for (var i = pistolBullets.length - 1; i >= 0; i--) {
pistolBullets[i].destroy();
}
pistolBullets = [];
// Clear shotgun bullets
for (var i = shotgunBullets.length - 1; i >= 0; i--) {
shotgunBullets[i].destroy();
}
shotgunBullets = [];
// Clear sniper bullets
for (var i = sniperBullets.length - 1; i >= 0; i--) {
sniperBullets[i].destroy();
}
sniperBullets = [];
// Clear boss projectiles
for (var i = bossBullets.length - 1; i >= 0; i--) {
bossBullets[i].destroy();
}
bossBullets = [];
for (var i = lasers.length - 1; i >= 0; i--) {
lasers[i].destroy();
}
lasers = [];
for (var i = flames.length - 1; i >= 0; i--) {
flames[i].destroy();
}
flames = [];
// Remove chest if exists
if (chest) {
chest.destroy();
chest = null;
}
// Clear health orbs
for (var i = healthOrbs.length - 1; i >= 0; i--) {
healthOrbs[i].destroy();
}
healthOrbs = [];
// Spawn enemies based on room type
spawnEnemiesForRoomType();
}
// Initialize first room
createRoom();
// Create player
player = new Player();
player.x = 1024;
player.y = 2000;
game.addChild(player);
// Spawn initial enemies
spawnEnemies();
// Initialize weapon icons
updateWeaponIcons();
// Touch controls
game.move = function (x, y, obj) {
targetX = x;
targetY = y;
};
// Right mouse button support for weapon switching
game.rightDown = function (x, y, obj) {
// Right click - switch weapon
player.switchWeapon();
updateWeaponIcons();
};
var touchStartTime = 0;
var touchHoldThreshold = 60; // 1 second hold at 60fps
game.down = function (x, y, obj) {
targetX = x;
targetY = y;
touchStartTime = LK.ticks; // Record when touch started
};
game.up = function (x, y, obj) {
var touchDuration = LK.ticks - touchStartTime;
// Check if it was a long press (hold for 1+ seconds)
if (touchDuration >= touchHoldThreshold) {
// Long press - switch weapon
player.switchWeapon();
updateWeaponIcons();
} else {
// Short tap - shoot towards touch point
player.shoot(x, y);
}
};
// Main game loop
game.update = function () {
// Update health display
healthText.setText('Health: ' + player.health);
healthText.fill = player.health > 50 ? "#00ff00" : player.health > 25 ? "#ffff00" : "#ff0000";
// Move player towards target
player.moveTowards(targetX, targetY);
// Check pistol bullet collisions with enemies
for (var i = pistolBullets.length - 1; i >= 0; i--) {
var bullet = pistolBullets[i];
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.takeDamage(bullet.damage);
bullet.removeBullet();
break;
}
}
}
// Check shotgun bullet collisions with enemies (close range = high damage, far range = low damage)
for (var i = shotgunBullets.length - 1; i >= 0; i--) {
var bullet = shotgunBullets[i];
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Calculate damage based on distance traveled (closer = more damage)
var damageMultiplier = Math.max(0.5, 1 - bullet.distanceTraveled / bullet.maxDistance);
var actualDamage = Math.floor(bullet.damage * damageMultiplier * 4); // Up to 4x damage at close range
enemy.takeDamage(actualDamage);
bullet.removeBullet();
break;
}
}
}
// Check sniper bullet collisions with enemies (far range = high damage, close range = lower damage)
for (var i = sniperBullets.length - 1; i >= 0; i--) {
var bullet = sniperBullets[i];
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Calculate damage based on distance traveled (farther = more damage)
var damageMultiplier = Math.min(2, 0.5 + bullet.distanceTraveled / 400); // Up to 2x damage at long range
var actualDamage = Math.floor(bullet.damage * damageMultiplier);
enemy.takeDamage(actualDamage);
bullet.removeBullet();
break;
}
}
}
// Check old bullet collisions with enemies (keep for compatibility)
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.takeDamage(bullet.damage);
bullet.removeBullet();
hitEnemy = true;
break;
}
}
}
// Check boss bullet collisions with player
for (var i = bossBullets.length - 1; i >= 0; i--) {
var bossBullet = bossBullets[i];
if (bossBullet.intersects(player)) {
player.takeDamage(bossBullet.damage);
bossBullet.removeBullet();
}
}
// Check laser collisions with player
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
if (laser.intersects(player)) {
// Only damage if cooldown has passed
if (LK.ticks - laser.lastDamage >= laser.damageCooldown) {
player.takeDamage(laser.damage);
laser.lastDamage = LK.ticks;
}
}
}
// Check flame collisions with player
for (var i = flames.length - 1; i >= 0; i--) {
var flame = flames[i];
if (flame.intersects(player)) {
player.takeDamage(flame.damage);
}
}
// Spawn boss when most enemies are killed (except in Hell mode where boss spawns immediately)
var roomType = getRoomType();
if (!bossSpawned && roomType !== "Hell") {
var spawnThreshold = roomType === "Tutorial" ? 0.8 : roomType === "Swarm" ? 0.9 : 0.7;
if (enemiesKilled >= Math.floor(totalEnemiesInRoom * spawnThreshold)) {
spawnBoss();
}
}
// Check if room is cleared (including boss)
if (enemies.length === 0 && totalEnemiesInRoom > 0 && !roomCleared && bossKilled) {
roomCleared = true;
spawnChest();
}
// Check chest interaction
if (chest && !chest.opened && player.intersects(chest)) {
chest.open();
}
// Check weapon pickup
for (var i = weapons.length - 1; i >= 0; i--) {
var weapon = weapons[i];
if (player.intersects(weapon)) {
weapon.pickup();
}
}
// Check health orb pickup
for (var i = healthOrbs.length - 1; i >= 0; i--) {
var healthOrb = healthOrbs[i];
if (player.intersects(healthOrb)) {
healthOrb.pickup();
}
}
// Auto advance to next room after chest is opened and weapon picked up
if (roomCleared && chest && chest.opened && weapons.length === 0) {
if (LK.ticks % 180 === 0) {
// Wait 3 seconds
nextRoom();
}
}
};
pixelart bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixel art gray weepon. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart skeleton. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart cave spider. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart zombies. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart fire. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart ıce bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart powerfull laser. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart sniper. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart sniper. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart human head. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixelart military armor. In-Game asset. 2d. High contrast. No shadows
pixel art green orb. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat