User prompt
change the rpg sprite
User prompt
the rpg does not work when bought from shop
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'shoot')' in or related to this line: 'player.shoot(x, y);' Line Number: 1820
User prompt
change the rpg sprite and when it is shut make it have a explosion that damages everything on the screen besides the player and make the fire pistol not a starter thing and can only be optained by level ups or shops ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make it so when a enemy is hit by the fire pistol upgrade it has a fire effect showing its working and make the shop keeper text boxes far bigger because i can bearly read what im buying and what they do ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'currentGun')' in or related to this line: 'if (isRightClickHeld && player.currentGun === 'rifle') {' Line Number: 1733
User prompt
add a cash system where every enemy you kill is one dollar and put this to the left of the hotbar and every 4 waves theres a shopkeeper and on your screen it shows different things you can buy and one thing he will always sell is the upgrade fire pistol and once you buy it from him you cant buy it again and it will get replaced by somthing random like more hp more damage or some different weapons he will also somtimes sell a RPG that has one shot and when is shot makes a huge explosion that does 40 damage but only 30 on bosses and the rpg cost 30 coins ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make the slowdown button be on the right side and mimic the position of the parry button just on the right side like the opisite
User prompt
make the slowdown button mirror the parry button just for looks
User prompt
make the xp counter go above the hotbar and make it a bar and make each enemy give 50 xp the boss 200 xp and the blue enemys 75 xp and above the xp bar put in noticable letters XP and then make the parry button far bigger and same thing with the slowdown button
User prompt
add a button called slowdown on the right of the screen when the button is clicked it goes on cooldown for 50 seconds but the cooldown gets cut by 5 seconds per enemy killed and when the button is pressed it slows all enemys by 70% and make it so after wave 5 a perentage amount of normal enemys will turn into blue enemys and this scales over every wave ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
@upit/tween.v1 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make a special level up that has a low chance of being a choice called fire pistol where the pistol can deal one damage over time and it stacks but it has a low chance of spawning ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the level up systm different make it so the 3 choices can vairy from one of these +5 max hp +2 damage +Range +1 Piercing
User prompt
make it so when the sniper is out of ammo it deletes itself from the hotbar
User prompt
make the sniper have a 40% chance to drop from normal enemys and 100% from blue enemys
User prompt
add a sniper to the game that piercies through enemys only 3 at a time tough and does 20 damage and the sniper only has 5 shots before it brakes and make the shotgun do more damage it feels to weak
User prompt
add a blue enemy that appers on wave five and will apper on every wave after that this blue enemy has 5 hp unlike the 10 hp normal enemy and he has a shotgun so if he gets close to the player he deals a lot of damage
User prompt
make the player starting hp 10
User prompt
make a bossfight happen every ten rooms the boss is big and purple and cannot be killed by the hammer and can not be stunned by the sword if the boss is parried it takes five damage the the boss has a big healthbar at the top of the screen and has 50 health and gets 50 more health every 10 rooms
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BlueEnemy = Container.expand(function (roomLevel) { var self = Container.call(this); var enemyGraphics = self.attachAsset('blueEnemy', { anchorX: 0.5, anchorY: 0.5 }); // Set blue enemy health to 5 HP self.health = 5; self.speed = Math.min(1.5 + roomLevel * 0.2, 3.5); self.shootTimer = 0; self.shootCooldown = Math.max(90 - roomLevel * 3, 50); self.active = true; self.lastPlayerX = 0; self.lastPlayerY = 0; self.stunned = false; self.stunTimer = 0; self.isBlueEnemy = true; self.update = function () { if (!self.active || !player || isLevelingUp) return; // Handle stunning if (self.stunned) { self.stunTimer--; if (self.stunTimer <= 0) { self.stunned = false; } return; // Don't move or shoot while stunned } // Track last position for intersection detection self.lastPlayerX = player.x; self.lastPlayerY = player.y; // Move aggressively towards player for close range shotgun attack var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var optimalDistance = 120; // Very close for shotgun effectiveness var minDistance = 80; // Get very close if (distance > optimalDistance) { // Move closer aggressively self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else if (distance < minDistance) { // Too close - back away slightly self.x -= dx / distance * self.speed * 0.5; self.y -= dy / distance * self.speed * 0.5; } // Shooting logic - shoots when close to player self.shootTimer++; if (self.shootTimer >= self.shootCooldown && distance < 200) { self.shoot(); self.shootTimer = 0; } }; self.shoot = function () { // Shotgun spread attack - fires 3 bullets in a spread var baseAngle = Math.atan2(player.y - self.y, player.x - self.x); for (var i = -1; i <= 1; i++) { var bullet = new Bullet(false); bullet.direction = baseAngle + i * 0.4; // Wide spread bullet.x = self.x; bullet.y = self.y; bullet.startX = self.x; bullet.startY = self.y; bullet.speed = 12; bullet.damage = 3; // Increased damage per pellet for stronger shotgun enemyBullets.push(bullet); game.addChild(bullet); } }; self.stun = function (duration) { self.stunned = true; self.stunTimer = duration; // Visual feedback for stunned enemy LK.effects.flashObject(self, 0xfff700, duration * 16.67); }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.active = false; LK.setScore(LK.getScore() + 15); // Higher score for blue enemies gainXP(35); // More XP for blue enemies LK.getSound('enemyHit').play(); // 100% chance to drop sniper weapon var sniperPickup = new Pickup('gun', self.x, self.y); sniperPickup.weapon = 'sniper'; // Force it to be sniper pickups.push(sniperPickup); game.addChild(sniperPickup); // 25% chance to drop weapon pickup (higher than normal) if (Math.random() < 0.25) { spawnPickup(self.x, self.y); } // 15% chance to drop shotgun ammo if (Math.random() < 0.15) { var ammoPickup = new ShotgunAmmo(self.x, self.y); shotgunAmmoPickups.push(ammoPickup); game.addChild(ammoPickup); } } }; return self; }); var Boss = Container.expand(function (roomLevel) { var self = Container.call(this); // Create boss graphics - big and purple var bossGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, tint: 0x8e44ad // Purple color }); // Boss stats scale with room level self.maxHealth = 50 + Math.floor((roomLevel - 10) / 10) * 50; self.health = self.maxHealth; self.speed = Math.min(0.8 + roomLevel * 0.1, 2); self.shootTimer = 0; self.shootCooldown = Math.max(90 - roomLevel * 2, 45); self.active = true; self.isBoss = true; self.update = function () { if (!self.active || !player || isLevelingUp) return; // Move towards player but maintain distance var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var optimalDistance = 300; var minDistance = 200; if (distance < minDistance) { self.x -= dx / distance * self.speed; self.y -= dy / distance * self.speed; } else if (distance > optimalDistance + 150) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Shooting logic - bosses shoot more frequently self.shootTimer++; if (self.shootTimer >= self.shootCooldown && distance < 600) { self.shoot(); self.shootTimer = 0; } }; self.shoot = function () { // Bosses shoot 3 bullets in a spread var baseAngle = Math.atan2(player.y - self.y, player.x - self.x); for (var i = -1; i <= 1; i++) { var bullet = new Bullet(false); bullet.direction = baseAngle + i * 0.3; bullet.x = self.x; bullet.y = self.y; bullet.startX = self.x; bullet.startY = self.y; bullet.speed = 10; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); updateBossHealthBar(); if (self.health <= 0) { self.active = false; LK.setScore(LK.getScore() + 100); gainXP(100); LK.getSound('enemyHit').play(); // Hide boss health bar if (bossHealthBarBg) { bossHealthBarBg.alpha = 0; bossHealthBar.alpha = 0; } } }; return self; }); var Bullet = Container.expand(function (isPlayer, gunType) { var self = Container.call(this); self.isPlayer = isPlayer || false; self.gunType = gunType || 'pistol'; var bulletGraphics = self.attachAsset(self.isPlayer ? 'bullet' : 'enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); // Different bullet properties based on gun type if (self.isPlayer) { switch (self.gunType) { case 'pistol': self.speed = 12; self.damage = 5 + damageBonus; self.maxRange = 800 * rangeBonus; // Large range break; case 'rifle': self.speed = 18; self.damage = 2 + damageBonus; self.maxRange = 1000 * rangeBonus; // Large range break; case 'shotgun': self.speed = 10; self.damage = 15 + damageBonus; // Increased from 10 to 15 self.maxRange = 300; // Short range break; case 'sniper': self.speed = 25; self.damage = 20 + damageBonus; self.maxRange = 1200 * rangeBonus; // Very long range self.pierceCount = 0; // Track how many enemies pierced self.maxPierce = 3 + piercingBonus; // Can pierce through 3 + bonus enemies break; } } else { self.speed = 8; self.damage = 1; self.maxRange = 400; } self.direction = 0; self.active = true; self.startX = 0; self.startY = 0; self.distanceTraveled = 0; self.update = function () { if (!self.active) return; self.x += Math.cos(self.direction) * self.speed; self.y += Math.sin(self.direction) * self.speed; // Track distance traveled var dx = self.x - self.startX; var dy = self.y - self.startY; self.distanceTraveled = Math.sqrt(dx * dx + dy * dy); // Check range limit if (self.maxRange && self.distanceTraveled > self.maxRange) { self.active = false; } // Check bounds if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) { self.active = false; } }; return self; }); var Enemy = Container.expand(function (roomLevel) { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Set enemy health to 10 HP self.health = 10; self.speed = Math.min(1 + roomLevel * 0.2, 3); self.shootTimer = 0; self.shootCooldown = Math.max(120 - roomLevel * 5, 60); self.active = true; self.lastPlayerX = 0; self.lastPlayerY = 0; self.stunned = false; self.stunTimer = 0; self.update = function () { if (!self.active || !player || isLevelingUp) return; // Handle stunning if (self.stunned) { self.stunTimer--; if (self.stunTimer <= 0) { self.stunned = false; } return; // Don't move or shoot while stunned } // Track last position for intersection detection self.lastPlayerX = player.x; self.lastPlayerY = player.y; // Move to maintain optimal shooting distance var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var optimalDistance = 250; // Preferred shooting distance var minDistance = 150; // Minimum distance to maintain if (distance < minDistance) { // Too close - back away from player self.x -= dx / distance * self.speed; self.y -= dy / distance * self.speed; } else if (distance > optimalDistance + 100) { // Too far - move closer but stop at optimal distance self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // If between minDistance and optimalDistance+100, stay in place // Shooting logic self.shootTimer++; if (self.shootTimer >= self.shootCooldown && distance < 500) { self.shoot(); self.shootTimer = 0; } }; self.shoot = function () { var bullet = new Bullet(false); var angle = Math.atan2(player.y - self.y, player.x - self.x); bullet.direction = angle; bullet.x = self.x; bullet.y = self.y; bullet.startX = self.x; bullet.startY = self.y; enemyBullets.push(bullet); game.addChild(bullet); }; self.stun = function (duration) { self.stunned = true; self.stunTimer = duration; // Visual feedback for stunned enemy LK.effects.flashObject(self, 0xfff700, duration * 16.67); }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.active = false; LK.setScore(LK.getScore() + 10); gainXP(25); // Gain 25 XP per enemy killed LK.getSound('enemyHit').play(); // 40% chance to drop sniper weapon if (Math.random() < 0.4) { var sniperPickup = new Pickup('gun', self.x, self.y); sniperPickup.weapon = 'sniper'; // Force it to be sniper pickups.push(sniperPickup); game.addChild(sniperPickup); } // 20% chance to drop weapon pickup if (Math.random() < 0.2) { spawnPickup(self.x, self.y); } // 10% chance to drop shotgun ammo if (Math.random() < 0.1) { var ammoPickup = new ShotgunAmmo(self.x, self.y); shotgunAmmoPickups.push(ammoPickup); game.addChild(ammoPickup); } } }; return self; }); var Pickup = Container.expand(function (type, x, y) { var self = Container.call(this); self.type = type; // 'gun' or 'melee' self.x = x; self.y = y; self.active = true; self.bobOffset = Math.random() * Math.PI * 2; self.startY = y; var pickupGraphics = self.attachAsset(type === 'gun' ? 'gunPickup' : 'meleePickup', { anchorX: 0.5, anchorY: 0.5 }); // Determine what weapon this pickup contains if (type === 'gun') { var guns = ['pistol', 'rifle', 'shotgun', 'sniper']; self.weapon = guns[Math.floor(Math.random() * guns.length)]; } else { var melees = ['sword', 'hammer']; self.weapon = melees[Math.floor(Math.random() * melees.length)]; } self.update = function () { if (!self.active) return; // Bobbing animation self.y = self.startY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 5; // Check pickup collision with player if (self.intersects(player)) { self.active = false; if (self.type === 'gun') { if (addWeaponToHotbar(self.weapon, 'gun')) { // Successfully added to hotbar LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 5); } } else { if (addWeaponToHotbar(self.weapon, 'melee')) { // Successfully added to hotbar LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 5); } } self.destroy(); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Gun display var gunGraphics = self.attachAsset('pistol', { anchorX: 0, anchorY: 0.5, x: 20, y: 0 }); // Melee weapon display var meleeGraphics = self.attachAsset('sword', { anchorX: 0.5, anchorY: 1, x: -15, y: -10 }); self.health = 10; self.maxHealth = 10; self.speed = 5; self.shootCooldown = 0; self.parryCooldown = 0; self.parryWindow = 0; self.invincibilityFrames = 0; // Weapon systems self.currentGun = 'pistol'; self.currentMelee = 'sword'; // Ammo system self.shotgunAmmo = 5; self.sniperAmmo = 5; // Gun properties self.gunStats = { pistol: { cooldown: 12, spread: 0 }, rifle: { cooldown: 8, spread: 0.1 }, shotgun: { cooldown: 30, spread: 0.3, pellets: 3 }, sniper: { cooldown: 60, spread: 0, ammo: 5 } }; // Melee properties self.meleeStats = { sword: { parryWindow: 8, cooldown: 25, effect: 'reflect', color: 0x1abc9c }, hammer: { parryWindow: 15, cooldown: 45, effect: 'shockwave', color: 0xe74c3c } }; self.shoot = function (targetX, targetY) { if (self.shootCooldown > 0) return; // Check ammo for shotgun and sniper if (self.currentGun === 'shotgun' && self.shotgunAmmo <= 0) return; if (self.currentGun === 'sniper' && self.sniperAmmo <= 0) { // Remove sniper from hotbar when out of ammo removeWeaponFromHotbar('sniper'); return; } var gunStat = self.gunStats[self.currentGun]; var baseAngle = Math.atan2(targetY - self.y, targetX - self.x); if (self.currentGun === 'shotgun') { // Shotgun fires multiple pellets and consumes ammo self.shotgunAmmo--; for (var i = 0; i < gunStat.pellets; i++) { var bullet = new Bullet(true, self.currentGun); bullet.direction = baseAngle + (Math.random() - 0.5) * gunStat.spread; bullet.x = self.x; bullet.y = self.y; bullet.startX = self.x; bullet.startY = self.y; playerBullets.push(bullet); game.addChild(bullet); } } else if (self.currentGun === 'sniper') { // Sniper fires single high-damage piercing bullet and consumes ammo self.sniperAmmo--; var bullet = new Bullet(true, self.currentGun); bullet.direction = baseAngle + (Math.random() - 0.5) * gunStat.spread; bullet.x = self.x; bullet.y = self.y; bullet.startX = self.x; bullet.startY = self.y; playerBullets.push(bullet); game.addChild(bullet); } else { var bullet = new Bullet(true, self.currentGun); bullet.direction = baseAngle + (Math.random() - 0.5) * gunStat.spread; bullet.x = self.x; bullet.y = self.y; bullet.startX = self.x; bullet.startY = self.y; playerBullets.push(bullet); game.addChild(bullet); } LK.getSound('shoot').play(); self.shootCooldown = gunStat.cooldown; }; self.parry = function () { if (self.parryCooldown > 0) return; var meleeStat = self.meleeStats[self.currentMelee]; self.parryWindow = 180; // 3 seconds at 60fps self.parryCooldown = meleeStat.cooldown; // Visual feedback var parryFX = game.attachAsset('parryEffect', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, alpha: 0.8, tint: meleeStat.color }); tween(parryFX, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 3000, // 3 seconds onFinish: function onFinish() { parryFX.destroy(); } }); LK.getSound('parry').play(); }; self.switchGun = function (newGun) { if (newGun && self.gunStats[newGun]) { self.currentGun = newGun; gunGraphics.destroy(); gunGraphics = self.attachAsset(newGun, { anchorX: 0, anchorY: 0.5, x: 20, y: 0 }); } }; self.switchMelee = function (newMelee) { if (newMelee && self.meleeStats[newMelee]) { self.currentMelee = newMelee; meleeGraphics.destroy(); meleeGraphics = self.attachAsset(newMelee, { anchorX: 0.5, anchorY: 1, x: -15, y: -10 }); } }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xFF0000, 500); LK.getSound('playerHit').play(); if (self.health <= 0) { LK.showGameOver(); } }; self.heal = function (amount) { self.health = Math.min(self.health + amount, self.maxHealth); }; self.update = function () { if (self.shootCooldown > 0) self.shootCooldown--; if (self.parryCooldown > 0) self.parryCooldown--; if (self.invincibilityFrames > 0) self.invincibilityFrames--; if (self.parryWindow > 0) { self.parryWindow--; // Check if parry window just expired without being used if (self.parryWindow === 0) { // Parry was missed, add 2 second cooldown self.parryCooldown = 120; // 2 seconds at 60fps } } }; return self; }); var Room = Container.expand(function (level) { var self = Container.call(this); self.level = level || 1; self.enemies = []; self.pickups = []; self.cleared = false; self.door = null; self.generateRoom = function () { // Create border walls var wallSize = 60; var roomWidth = 2048; var roomHeight = 2732; var wallsX = Math.floor(roomWidth / wallSize); var wallsY = Math.floor(roomHeight / wallSize); // Top and bottom walls for (var i = 0; i < wallsX; i++) { var topWall = self.attachAsset('wall', { x: i * wallSize, y: 0 }); var bottomWall = self.attachAsset('wall', { x: i * wallSize, y: roomHeight - wallSize }); } // Left and right walls for (var j = 1; j < wallsY - 1; j++) { var leftWall = self.attachAsset('wall', { x: 0, y: j * wallSize }); var rightWall = self.attachAsset('wall', { x: roomWidth - wallSize, y: j * wallSize }); } // Check if this is a boss room (every 10 rooms) if (self.level % 10 === 0) { // Boss fight var boss = new Boss(self.level); boss.x = roomWidth / 2; boss.y = roomHeight / 3; self.enemies.push(boss); self.addChild(boss); currentBoss = boss; // Show boss health bar bossHealthBarBg.alpha = 1; bossHealthBar.alpha = 1; bossNameText.alpha = 1; updateBossHealthBar(); } else { // Generate regular enemies var enemyCount = Math.min(2 + self.level, 8); var blueEnemyCount = 0; // Blue enemies appear starting from wave 5 if (self.level >= 5) { blueEnemyCount = Math.min(1 + Math.floor((self.level - 5) / 3), 3); // 1-3 blue enemies enemyCount = Math.max(1, enemyCount - blueEnemyCount); // Reduce regular enemies to maintain balance } // Spawn regular enemies for (var k = 0; k < enemyCount; k++) { var enemy = new Enemy(self.level); enemy.x = 200 + Math.random() * (roomWidth - 400); enemy.y = 200 + Math.random() * (roomHeight - 400); self.enemies.push(enemy); self.addChild(enemy); } // Spawn blue enemies starting from wave 5 for (var b = 0; b < blueEnemyCount; b++) { var blueEnemy = new BlueEnemy(self.level); blueEnemy.x = 200 + Math.random() * (roomWidth - 400); blueEnemy.y = 200 + Math.random() * (roomHeight - 400); self.enemies.push(blueEnemy); self.addChild(blueEnemy); } } // Create exit door (initially locked) self.door = self.attachAsset('door', { anchorX: 0.5, anchorY: 0.5, x: roomWidth / 2, y: wallSize / 2, tint: 0xc0392b }); // Spawn shotgun pickup in room spawnShotgunPickup(); }; self.checkCleared = function () { var activeEnemies = 0; for (var i = 0; i < self.enemies.length; i++) { if (self.enemies[i].active) { activeEnemies++; } } if (activeEnemies === 0 && !self.cleared) { self.cleared = true; // Unlock door if (self.door) { tween(self.door, { tint: 0x27ae60 }, { duration: 500 }); } } return self.cleared; }; return self; }); var ShotgunAmmo = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; self.active = true; self.bobOffset = Math.random() * Math.PI * 2; self.startY = y; var ammoGraphics = self.attachAsset('shotgunAmmo', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (!self.active) return; // Bobbing animation self.y = self.startY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 5; // Check pickup collision with player if (self.intersects(player)) { self.active = false; player.shotgunAmmo += 3; // Give 3 ammo directly LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 2); updateUI(); // Update ammo display self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ var player; var currentRoom; var playerBullets = []; var enemyBullets = []; var pickups = []; var shotgunAmmoPickups = []; var roomLevel = 1; var dragStartX = 0; var dragStartY = 0; var isDragging = false; var draggedWeapon = null; var draggedSlot = null; var trashIcon = null; var selectedWeapon = null; var selectedSlot = null; // XP System var playerXP = 0; var playerLevel = 1; var xpToNextLevel = 100; var isLevelingUp = false; var levelUpChoices = null; var damageBonus = 0; var rangeBonus = 1; var piercingBonus = 0; // UI Elements var scoreText = new Text2('Score: 0', { size: 40, fill: '#ffffff' }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Health bar instead of text var healthBarBg = LK.gui.topRight.attachAsset('wall', { width: 150, height: 20, anchorX: 1, anchorY: 0, tint: 0x7f8c8d }); var healthBar = LK.gui.topRight.attachAsset('wall', { width: 150, height: 20, anchorX: 1, anchorY: 0, tint: 0xe74c3c }); var roomText = new Text2('Room: 1', { size: 30, fill: '#3498db' }); roomText.anchor.set(0, 0); roomText.x = 120; LK.gui.topLeft.addChild(roomText); var gunText = new Text2('Gun: Pistol', { size: 28, fill: '#f39c12' }); gunText.anchor.set(0, 1); LK.gui.bottomLeft.addChild(gunText); var meleeText = new Text2('Melee: Sword', { size: 28, fill: '#9b59b6' }); meleeText.anchor.set(1, 1); LK.gui.bottomRight.addChild(meleeText); // Hotbar system var hotbar = new Container(); hotbar.x = 1024; // Center of screen hotbar.y = 2600; // Bottom of screen game.addChild(hotbar); // Ammo counter to the left of hotbar var ammoText = new Text2('Shotgun: 5', { size: 32, fill: '#f39c12' }); ammoText.anchor.set(1, 0.5); ammoText.x = -300; // Position to the left of hotbar ammoText.y = 0; hotbar.addChild(ammoText); // Sniper ammo counter var sniperAmmoText = new Text2('Sniper: 5', { size: 32, fill: '#8b4513' }); sniperAmmoText.anchor.set(1, 0.5); sniperAmmoText.x = -300; sniperAmmoText.y = -40; hotbar.addChild(sniperAmmoText); // XP and Level display var xpText = new Text2('Level 1 - XP: 0/100', { size: 30, fill: '#e67e22' }); xpText.anchor.set(0.5, 0); xpText.x = 120; xpText.y = 40; LK.gui.topLeft.addChild(xpText); // Boss health bar (initially hidden) var bossHealthBarBg = LK.gui.top.attachAsset('wall', { width: 800, height: 30, anchorX: 0.5, anchorY: 0, y: 60, tint: 0x7f8c8d, alpha: 0 }); var bossHealthBar = LK.gui.top.attachAsset('wall', { width: 800, height: 30, anchorX: 0.5, anchorY: 0, y: 60, tint: 0x8e44ad, alpha: 0 }); var bossNameText = new Text2('BOSS', { size: 36, fill: '#8e44ad' }); bossNameText.anchor.set(0.5, 1); bossNameText.y = 55; bossNameText.alpha = 0; LK.gui.top.addChild(bossNameText); var hotbarSlots = []; var slotWidth = 80; var slotHeight = 80; var slotSpacing = 100; // Create 5 hotbar slots for (var h = 0; h < 5; h++) { var slot = hotbar.attachAsset('wall', { width: slotWidth, height: slotHeight, anchorX: 0.5, anchorY: 0.5, x: (h - 2) * slotSpacing, y: 0, tint: 0x2c3e50 }); slot.slotIndex = h; slot.weapon = null; slot.weaponType = null; // 'gun' or 'melee' // Visual weapon display slot.weaponGraphics = null; slot.down = function (x, y, obj) { if (this.weapon) { // Select weapon and light up trash selectedWeapon = this.weapon; selectedSlot = this; // Highlight the selected slot tween(this, { tint: 0x3498db }, { duration: 100 }); // Light up trash icon tween(trashIcon, { tint: 0xff6b6b }, { duration: 100 }); } }; slot.up = function (x, y, obj) { // Switch to this weapon if it's selected but not the same as current selection if (selectedWeapon && selectedSlot === this) { if (this.weaponType === 'gun') { player.switchGun(this.weapon); } else if (this.weaponType === 'melee') { player.switchMelee(this.weapon); } updateUI(); } }; hotbarSlots.push(slot); } // Create trash icon next to hotbar trashIcon = hotbar.attachAsset('trashIcon', { width: 60, height: 60, anchorX: 0.5, anchorY: 0.5, x: 350, // Position to the right of hotbar y: 0, tint: 0xc0392b }); // Add click handler to trash icon trashIcon.down = function (x, y, obj) { if (selectedWeapon && selectedSlot) { // Delete weapon from selected slot selectedSlot.weapon = null; selectedSlot.weaponType = null; if (selectedSlot.weaponGraphics) { selectedSlot.weaponGraphics.destroy(); selectedSlot.weaponGraphics = null; } // Reset slot color tween(selectedSlot, { tint: 0x2c3e50 }, { duration: 100 }); // Flash trash icon to show deletion tween(trashIcon, { tint: 0xff0000 }, { duration: 200, onFinish: function onFinish() { tween(trashIcon, { tint: 0xc0392b }, { duration: 200 }); } }); // Clear selection selectedWeapon = null; selectedSlot = null; } }; // Add visual indicator for trash (X symbol) var trashX1 = hotbar.attachAsset('wall', { width: 30, height: 4, anchorX: 0.5, anchorY: 0.5, x: 350, y: 0, rotation: Math.PI / 4, tint: 0xffffff }); var trashX2 = hotbar.attachAsset('wall', { width: 30, height: 4, anchorX: 0.5, anchorY: 0.5, x: 350, y: 0, rotation: -Math.PI / 4, tint: 0xffffff }); // Create parry button var parryButton = game.attachAsset('parryButton', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 2500 }); // Add parry button text var parryButtonText = new Text2('PARRY', { size: 24, fill: '#ffffff' }); parryButtonText.anchor.set(0.5, 0.5); parryButtonText.x = 200; parryButtonText.y = 2500; game.addChild(parryButtonText); // Add parry button click handler parryButton.down = function (x, y, obj) { player.parry(); // Visual feedback on button press tween(parryButton, { scaleX: 0.9, scaleY: 0.9, tint: 0x16a085 }, { duration: 100, onFinish: function onFinish() { tween(parryButton, { scaleX: 1, scaleY: 1, tint: 0x1abc9c }, { duration: 100 }); } }); }; // Set initial weapons in hotbar hotbarSlots[0].weapon = 'pistol'; hotbarSlots[0].weaponType = 'gun'; hotbarSlots[0].weaponGraphics = hotbarSlots[0].attachAsset('pistol', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); hotbarSlots[1].weapon = 'sword'; hotbarSlots[1].weaponType = 'melee'; hotbarSlots[1].weaponGraphics = hotbarSlots[1].attachAsset('sword', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); hotbarSlots[2].weapon = 'rifle'; hotbarSlots[2].weaponType = 'gun'; hotbarSlots[2].weaponGraphics = hotbarSlots[2].attachAsset('rifle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); function updateUI() { scoreText.setText('Score: ' + LK.getScore()); // Update health bar var healthPercent = player.health / player.maxHealth; healthBar.width = 150 * healthPercent; roomText.setText('Room: ' + roomLevel); gunText.setText('Gun: ' + player.currentGun.charAt(0).toUpperCase() + player.currentGun.slice(1)); meleeText.setText('Melee: ' + player.currentMelee.charAt(0).toUpperCase() + player.currentMelee.slice(1)); // Update ammo counter ammoText.setText('Shotgun: ' + player.shotgunAmmo); // Update sniper ammo counter sniperAmmoText.setText('Sniper: ' + player.sniperAmmo); // Update XP display xpText.setText('Level ' + playerLevel + ' - XP: ' + playerXP + '/' + xpToNextLevel); } function updateBossHealthBar() { if (currentBoss && currentBoss.active) { var healthPercent = currentBoss.health / currentBoss.maxHealth; bossHealthBar.width = 800 * healthPercent; } } function gainXP(amount) { playerXP += amount; if (playerXP >= xpToNextLevel && !isLevelingUp) { levelUp(); } } function levelUp() { isLevelingUp = true; playerLevel++; playerXP -= xpToNextLevel; xpToNextLevel = Math.floor(xpToNextLevel * 1.5); // Create level up choices overlay showLevelUpChoices(); } function showLevelUpChoices() { // Create overlay background var overlay = game.attachAsset('wall', { width: 2048, height: 2732, anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8, tint: 0x000000 }); // Randomly select 3 different upgrade options var availableUpgrades = [{ id: 'hp', text: '+5 Max HP', color: 0x27ae60 }, { id: 'damage', text: '+2 Damage', color: 0xe74c3c }, { id: 'range', text: '+Range', color: 0x3498db }, { id: 'piercing', text: '+1 Piercing', color: 0xf39c12 }]; // Shuffle and pick 3 random upgrades var selectedUpgrades = []; var tempUpgrades = availableUpgrades.slice(); // Create copy for (var i = 0; i < 3; i++) { var randomIndex = Math.floor(Math.random() * tempUpgrades.length); selectedUpgrades.push(tempUpgrades[randomIndex]); tempUpgrades.splice(randomIndex, 1); } // Create choice buttons var choiceY = 1366; // Center Y var choiceSpacing = 400; var choices = []; var choiceTexts = []; for (var j = 0; j < 3; j++) { var upgrade = selectedUpgrades[j]; var xPos = 1024 + (j - 1) * choiceSpacing; var choice = game.attachAsset('wall', { width: 300, height: 100, anchorX: 0.5, anchorY: 0.5, x: xPos, y: choiceY, tint: upgrade.color }); var choiceText = new Text2(upgrade.text, { size: 36, fill: '#ffffff' }); choiceText.anchor.set(0.5, 0.5); choiceText.x = xPos; choiceText.y = choiceY; game.addChild(choiceText); // Store upgrade id on the choice button choice.upgradeId = upgrade.id; choice.down = function () { chooseLevelUpOption(this.upgradeId); }; choices.push(choice); choiceTexts.push(choiceText); } // Store references for cleanup levelUpChoices = { overlay: overlay, choices: choices, choiceTexts: choiceTexts }; } function chooseLevelUpOption(choice) { if (!isLevelingUp || !levelUpChoices) return; // Apply the chosen upgrade switch (choice) { case 'damage': damageBonus += 2; break; case 'hp': player.maxHealth += 5; player.health += 5; break; case 'range': rangeBonus += 0.2; break; case 'piercing': piercingBonus++; break; } // Clean up level up UI levelUpChoices.overlay.destroy(); for (var i = 0; i < levelUpChoices.choices.length; i++) { levelUpChoices.choices[i].destroy(); levelUpChoices.choiceTexts[i].destroy(); } levelUpChoices = null; isLevelingUp = false; updateUI(); } function spawnPickup(x, y) { var pickupType = Math.random() < 0.6 ? 'gun' : 'melee'; var pickup = new Pickup(pickupType, x, y); pickups.push(pickup); game.addChild(pickup); } function addWeaponToHotbar(weapon, weaponType) { // Find first empty slot for (var i = 0; i < hotbarSlots.length; i++) { var slot = hotbarSlots[i]; if (!slot.weapon) { slot.weapon = weapon; slot.weaponType = weaponType; // Remove old graphics if any if (slot.weaponGraphics) { slot.weaponGraphics.destroy(); } // Add new weapon graphics slot.weaponGraphics = slot.attachAsset(weapon, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); return true; } } return false; // No empty slots } function removeWeaponFromHotbar(weapon) { // Find and remove the weapon from hotbar for (var i = 0; i < hotbarSlots.length; i++) { var slot = hotbarSlots[i]; if (slot.weapon === weapon) { // If this was the current weapon, switch to pistol if (player.currentGun === weapon) { player.switchGun('pistol'); } // Clear the slot slot.weapon = null; slot.weaponType = null; if (slot.weaponGraphics) { slot.weaponGraphics.destroy(); slot.weaponGraphics = null; } // Reset slot color slot.tint = 0x2c3e50; // Clear selection if this weapon was selected if (selectedWeapon === weapon && selectedSlot === slot) { selectedWeapon = null; selectedSlot = null; } updateUI(); return true; } } return false; } // Spawn shotgun pickup in each room function spawnShotgunPickup() { var shotgunPickup = new Pickup('gun', 300 + Math.random() * 1400, 400 + Math.random() * 1800); shotgunPickup.weapon = 'shotgun'; // Force it to be shotgun pickups.push(shotgunPickup); game.addChild(shotgunPickup); } function generateNewRoom() { // Clear current room if (currentRoom) { currentRoom.destroy(); } // Clear boss reference and hide boss health bar currentBoss = null; if (bossHealthBarBg) { bossHealthBarBg.alpha = 0; bossHealthBar.alpha = 0; bossNameText.alpha = 0; } // Clear bullets and pickups for (var i = 0; i < playerBullets.length; i++) { playerBullets[i].destroy(); } for (var j = 0; j < enemyBullets.length; j++) { enemyBullets[j].destroy(); } for (var k = 0; k < pickups.length; k++) { pickups[k].destroy(); } for (var l = 0; l < shotgunAmmoPickups.length; l++) { shotgunAmmoPickups[l].destroy(); } playerBullets = []; enemyBullets = []; pickups = []; shotgunAmmoPickups = []; // Create new room roomLevel++; currentRoom = new Room(roomLevel); currentRoom.generateRoom(); game.addChild(currentRoom); // Reset player position player.x = 1024; player.y = 2400; game.addChild(player); // Regenerate HP when entering new room player.heal(1); // Heal 1 HP when entering a new room updateUI(); } // Game state management var gameStarted = false; var weaponSelectionUI = null; var currentBoss = null; // Show weapon selection screen function showWeaponSelection() { // Create overlay background var overlay = game.attachAsset('wall', { width: 2048, height: 2732, anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.9, tint: 0x2c3e50 }); // Title text var titleText = new Text2('Choose Your Weapon', { size: 60, fill: '#ffffff' }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; game.addChild(titleText); // Create weapon choice buttons var choiceY = 1366; // Center Y var choiceSpacing = 400; // Hammer choice var hammerChoice = game.attachAsset('wall', { width: 300, height: 200, anchorX: 0.5, anchorY: 0.5, x: 1024 - choiceSpacing, y: choiceY, tint: 0x8e44ad }); var hammerIcon = game.attachAsset('hammer', { anchorX: 0.5, anchorY: 0.5, x: 1024 - choiceSpacing, y: choiceY - 20, scaleX: 3, scaleY: 3 }); var hammerText = new Text2('HAMMER', { size: 32, fill: '#ffffff' }); hammerText.anchor.set(0.5, 0.5); hammerText.x = 1024 - choiceSpacing; hammerText.y = choiceY + 50; game.addChild(hammerText); var hammerDesc = new Text2('Kills enemies\nwhen parrying', { size: 24, fill: '#ecf0f1' }); hammerDesc.anchor.set(0.5, 0.5); hammerDesc.x = 1024 - choiceSpacing; hammerDesc.y = choiceY + 80; game.addChild(hammerDesc); // Sword choice var swordChoice = game.attachAsset('wall', { width: 300, height: 200, anchorX: 0.5, anchorY: 0.5, x: 1024 + choiceSpacing, y: choiceY, tint: 0xe67e22 }); var swordIcon = game.attachAsset('sword', { anchorX: 0.5, anchorY: 0.5, x: 1024 + choiceSpacing, y: choiceY - 20, scaleX: 3, scaleY: 3 }); var swordText = new Text2('SWORD', { size: 32, fill: '#ffffff' }); swordText.anchor.set(0.5, 0.5); swordText.x = 1024 + choiceSpacing; swordText.y = choiceY + 50; game.addChild(swordText); var swordDesc = new Text2('Gives invincibility\nframes when parrying', { size: 24, fill: '#ecf0f1' }); swordDesc.anchor.set(0.5, 0.5); swordDesc.x = 1024 + choiceSpacing; swordDesc.y = choiceY + 80; game.addChild(swordDesc); // Store references for cleanup weaponSelectionUI = { overlay: overlay, titleText: titleText, hammerChoice: hammerChoice, hammerIcon: hammerIcon, hammerText: hammerText, hammerDesc: hammerDesc, swordChoice: swordChoice, swordIcon: swordIcon, swordText: swordText, swordDesc: swordDesc }; // Add click handlers hammerChoice.down = function () { chooseWeapon('hammer'); }; swordChoice.down = function () { chooseWeapon('sword'); }; } // Handle weapon selection function chooseWeapon(weaponType) { if (!weaponSelectionUI) return; // Clean up weapon selection UI weaponSelectionUI.overlay.destroy(); weaponSelectionUI.titleText.destroy(); weaponSelectionUI.hammerChoice.destroy(); weaponSelectionUI.hammerIcon.destroy(); weaponSelectionUI.hammerText.destroy(); weaponSelectionUI.hammerDesc.destroy(); weaponSelectionUI.swordChoice.destroy(); weaponSelectionUI.swordIcon.destroy(); weaponSelectionUI.swordText.destroy(); weaponSelectionUI.swordDesc.destroy(); weaponSelectionUI = null; // Start the game with chosen weapon startGameWithWeapon(weaponType); } // Initialize game with chosen weapon function startGameWithWeapon(startingWeapon) { gameStarted = true; // Initialize game currentRoom = new Room(roomLevel); currentRoom.generateRoom(); game.addChild(currentRoom); player = new Player(); player.x = 1024; player.y = 2400; game.addChild(player); // Set the chosen starting weapon player.switchMelee(startingWeapon); // Update hotbar to reflect chosen weapon hotbarSlots[1].weapon = startingWeapon; hotbarSlots[1].weaponType = 'melee'; if (hotbarSlots[1].weaponGraphics) { hotbarSlots[1].weaponGraphics.destroy(); } hotbarSlots[1].weaponGraphics = hotbarSlots[1].attachAsset(startingWeapon, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); updateUI(); } // Show weapon selection at start showWeaponSelection(); // Touch controls game.down = function (x, y, obj) { isDragging = true; dragStartX = x; dragStartY = y; }; game.move = function (x, y, obj) { // Update aim position for rifle full auto if (isRightClickHeld && player.currentGun === 'rifle') { dragStartX = x; dragStartY = y; } }; game.up = function (x, y, obj) { if (isDragging && !isRightClickHeld) { var dx = x - dragStartX; var dy = y - dragStartY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 30) { // Check if this is a potential parry (tap in bottom area of screen or near parry button) var parryButtonDistance = Math.sqrt((x - 200) * (x - 200) + (y - 2500) * (y - 2500)); if (y > 2200 || parryButtonDistance < 120) { // Tap in bottom area or near parry button - parry player.parry(); } else { // Tap elsewhere - shoot player.shoot(x, y); } } } isDragging = false; isRightClickHeld = false; rightClickDetected = false; }; // Double click variables for movement system var lastClickTime = 0; var doubleClickThreshold = 300; // milliseconds var rightClickDetected = false; var isRightClickHeld = false; var fullAutoTimer = 0; var fullAutoInterval = 8; // Fire every 8 ticks for rifle full auto // Function to handle double click movement function handleDoubleClick(x, y) { // Move player to clicked position with smooth movement var targetX = Math.max(80, Math.min(1968, x)); var targetY = Math.max(80, Math.min(2652, y)); // Use tween for smooth movement tween(player, { x: targetX, y: targetY }, { duration: 500 }); } // Override the existing down handler to detect double clicks and right clicks game.down = function (x, y, obj) { var currentTime = Date.now(); // Check for right click (simulate with touch hold detection) // We'll detect right click as a hold that lasts longer than normal tap LK.setTimeout(function () { if (isDragging && !rightClickDetected) { // This is a right click hold isRightClickHeld = true; rightClickDetected = true; fullAutoTimer = 0; } }, 200); // 200ms to detect hold if (currentTime - lastClickTime < doubleClickThreshold) { // Double click detected handleDoubleClick(x, y); lastClickTime = 0; // Reset to prevent triple click } else { // Single click - start drag isDragging = true; dragStartX = x; dragStartY = y; lastClickTime = currentTime; } }; // Main game loop game.update = function () { if (!gameStarted || !player || !currentRoom || isLevelingUp) return; // Update player player.update(); // Update player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; bullet.update(); if (!bullet.active) { bullet.destroy(); playerBullets.splice(i, 1); continue; } // Check collision with enemies for (var j = 0; j < currentRoom.enemies.length; j++) { var enemy = currentRoom.enemies[j]; if (enemy.active && bullet.intersects(enemy)) { enemy.takeDamage(bullet.damage); // Handle sniper piercing if (bullet.gunType === 'sniper' && bullet.pierceCount < bullet.maxPierce) { bullet.pierceCount++; // Continue through enemy, don't destroy bullet } else { bullet.active = false; bullet.destroy(); playerBullets.splice(i, 1); } break; } } } // Update enemy bullets for (var k = enemyBullets.length - 1; k >= 0; k--) { var enemyBullet = enemyBullets[k]; enemyBullet.update(); if (!enemyBullet.active) { enemyBullet.destroy(); enemyBullets.splice(k, 1); continue; } // Check collision with player if (enemyBullet.intersects(player)) { if (player.parryWindow > 0) { // Successful parry - find the enemy that shot this bullet and stun them var bulletShooter = null; var shortestDistance = Infinity; for (var bulletCheck = 0; bulletCheck < currentRoom.enemies.length; bulletCheck++) { var checkEnemy = currentRoom.enemies[bulletCheck]; if (checkEnemy.active) { var checkDx = checkEnemy.x - enemyBullet.x; var checkDy = checkEnemy.y - enemyBullet.y; var checkDistance = Math.sqrt(checkDx * checkDx + checkDy * checkDy); if (checkDistance < shortestDistance) { shortestDistance = checkDistance; bulletShooter = checkEnemy; } } } // Stun the enemy that shot the bullet if (bulletShooter) { if (bulletShooter.isBoss) { // Boss takes 5 damage when parried, cannot be stunned or killed by parry bulletShooter.takeDamage(5); } else if (player.currentMelee === 'hammer') { // Hammer kills the enemy instead of stunning bulletShooter.takeDamage(bulletShooter.health); } else if (player.currentMelee === 'sword') { // Sword stuns enemy for 5 seconds (works on both regular and blue enemies) bulletShooter.stun(300); // Stun for 5 seconds (300 ticks at 60fps) } else { // Other weapons stun the enemy for 2 seconds bulletShooter.stun(120); // Stun for 2 seconds (120 ticks at 60fps) } } var meleeStat = player.meleeStats[player.currentMelee]; // Give sword users 5 seconds of invincibility frames if (player.currentMelee === 'sword') { player.invincibilityFrames = 300; // 5 seconds at 60fps // Visual feedback for invincibility tween(player, { alpha: 0.5 }, { duration: 5000, onFinish: function onFinish() { player.alpha = 1; } }); } if (meleeStat.effect === 'reflect') { // Reflect bullet back var reflectedBullet = new Bullet(true, 'pistol'); reflectedBullet.x = enemyBullet.x; reflectedBullet.y = enemyBullet.y; reflectedBullet.startX = enemyBullet.x; reflectedBullet.startY = enemyBullet.y; reflectedBullet.direction = enemyBullet.direction + Math.PI; reflectedBullet.speed = 15; playerBullets.push(reflectedBullet); game.addChild(reflectedBullet); } else if (meleeStat.effect === 'shockwave') { // Damage nearby enemies for (var l = 0; l < currentRoom.enemies.length; l++) { var nearbyEnemy = currentRoom.enemies[l]; var dx = nearbyEnemy.x - player.x; var dy = nearbyEnemy.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150 && nearbyEnemy.active) { if (nearbyEnemy.isBoss) { // Boss takes 5 damage from shockwave, cannot be killed nearbyEnemy.takeDamage(5); } else if (player.currentMelee === 'hammer') { // Hammer kills nearby enemies (works on both regular and blue enemies) nearbyEnemy.takeDamage(nearbyEnemy.health); } else { // Other weapons damage nearby enemies nearbyEnemy.takeDamage(2); } } } } LK.effects.flashObject(player, meleeStat.color, 300); LK.setScore(LK.getScore() + 3); } else { // Player takes damage (unless they have invincibility frames) if (!player.invincibilityFrames || player.invincibilityFrames <= 0) { player.takeDamage(); } } enemyBullet.active = false; enemyBullet.destroy(); enemyBullets.splice(k, 1); } } // Update enemies for (var m = 0; m < currentRoom.enemies.length; m++) { var enemy = currentRoom.enemies[m]; if (enemy.active) { enemy.update(); } } // Update pickups for (var n = pickups.length - 1; n >= 0; n--) { var pickup = pickups[n]; pickup.update(); if (!pickup.active) { pickups.splice(n, 1); } } // Update shotgun ammo pickups for (var o = shotgunAmmoPickups.length - 1; o >= 0; o--) { var ammoPickup = shotgunAmmoPickups[o]; ammoPickup.update(); if (!ammoPickup.active) { shotgunAmmoPickups.splice(o, 1); } } // Check room completion if (currentRoom.checkCleared()) { // Check if player reaches door if (currentRoom.door && player.intersects(currentRoom.door)) { generateNewRoom(); } } // Reset trash icon when no weapon is selected if (!selectedWeapon && trashIcon.tint !== 0xc0392b) { tween(trashIcon, { tint: 0xc0392b }, { duration: 100 }); } // Handle aimed shooting for rifle while held if (isRightClickHeld && player.currentGun === 'rifle') { fullAutoTimer++; if (fullAutoTimer >= fullAutoInterval) { // Use current mouse/touch position for aiming var currentX = dragStartX; // This gets updated in move handler var currentY = dragStartY; // This gets updated in move handler player.shoot(currentX, currentY); fullAutoTimer = 0; } } // Update UI periodically if (LK.ticks % 30 === 0) { updateUI(); } };
===================================================================
--- original.js
+++ change.js
@@ -210,9 +210,9 @@
self.speed = 25;
self.damage = 20 + damageBonus;
self.maxRange = 1200 * rangeBonus; // Very long range
self.pierceCount = 0; // Track how many enemies pierced
- self.maxPierce = 3; // Can pierce through 3 enemies
+ self.maxPierce = 3 + piercingBonus; // Can pierce through 3 + bonus enemies
break;
}
} else {
self.speed = 8;
@@ -749,8 +749,9 @@
var isLevelingUp = false;
var levelUpChoices = null;
var damageBonus = 0;
var rangeBonus = 1;
+var piercingBonus = 0;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 40,
fill: '#ffffff'
@@ -1076,109 +1077,98 @@
y: 0,
alpha: 0.8,
tint: 0x000000
});
+ // Randomly select 3 different upgrade options
+ var availableUpgrades = [{
+ id: 'hp',
+ text: '+5 Max HP',
+ color: 0x27ae60
+ }, {
+ id: 'damage',
+ text: '+2 Damage',
+ color: 0xe74c3c
+ }, {
+ id: 'range',
+ text: '+Range',
+ color: 0x3498db
+ }, {
+ id: 'piercing',
+ text: '+1 Piercing',
+ color: 0xf39c12
+ }];
+ // Shuffle and pick 3 random upgrades
+ var selectedUpgrades = [];
+ var tempUpgrades = availableUpgrades.slice(); // Create copy
+ for (var i = 0; i < 3; i++) {
+ var randomIndex = Math.floor(Math.random() * tempUpgrades.length);
+ selectedUpgrades.push(tempUpgrades[randomIndex]);
+ tempUpgrades.splice(randomIndex, 1);
+ }
// Create choice buttons
var choiceY = 1366; // Center Y
var choiceSpacing = 400;
- // Damage choice
- var damageChoice = game.attachAsset('wall', {
- width: 300,
- height: 100,
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024 - choiceSpacing,
- y: choiceY,
- tint: 0xe74c3c
- });
- var damageText = new Text2('+1 Damage', {
- size: 36,
- fill: '#ffffff'
- });
- damageText.anchor.set(0.5, 0.5);
- damageText.x = 1024 - choiceSpacing;
- damageText.y = choiceY;
- game.addChild(damageText);
- // HP choice
- var hpChoice = game.attachAsset('wall', {
- width: 300,
- height: 100,
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: choiceY,
- tint: 0x27ae60
- });
- var hpText = new Text2('+1 Max HP', {
- size: 36,
- fill: '#ffffff'
- });
- hpText.anchor.set(0.5, 0.5);
- hpText.x = 1024;
- hpText.y = choiceY;
- game.addChild(hpText);
- // Range choice
- var rangeChoice = game.attachAsset('wall', {
- width: 300,
- height: 100,
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024 + choiceSpacing,
- y: choiceY,
- tint: 0x3498db
- });
- var rangeText = new Text2('+Range', {
- size: 36,
- fill: '#ffffff'
- });
- rangeText.anchor.set(0.5, 0.5);
- rangeText.x = 1024 + choiceSpacing;
- rangeText.y = choiceY;
- game.addChild(rangeText);
+ var choices = [];
+ var choiceTexts = [];
+ for (var j = 0; j < 3; j++) {
+ var upgrade = selectedUpgrades[j];
+ var xPos = 1024 + (j - 1) * choiceSpacing;
+ var choice = game.attachAsset('wall', {
+ width: 300,
+ height: 100,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: xPos,
+ y: choiceY,
+ tint: upgrade.color
+ });
+ var choiceText = new Text2(upgrade.text, {
+ size: 36,
+ fill: '#ffffff'
+ });
+ choiceText.anchor.set(0.5, 0.5);
+ choiceText.x = xPos;
+ choiceText.y = choiceY;
+ game.addChild(choiceText);
+ // Store upgrade id on the choice button
+ choice.upgradeId = upgrade.id;
+ choice.down = function () {
+ chooseLevelUpOption(this.upgradeId);
+ };
+ choices.push(choice);
+ choiceTexts.push(choiceText);
+ }
// Store references for cleanup
levelUpChoices = {
overlay: overlay,
- damageChoice: damageChoice,
- hpChoice: hpChoice,
- rangeChoice: rangeChoice,
- damageText: damageText,
- hpText: hpText,
- rangeText: rangeText
+ choices: choices,
+ choiceTexts: choiceTexts
};
- // Add click handlers
- damageChoice.down = function () {
- chooseLevelUpOption('damage');
- };
- hpChoice.down = function () {
- chooseLevelUpOption('hp');
- };
- rangeChoice.down = function () {
- chooseLevelUpOption('range');
- };
}
function chooseLevelUpOption(choice) {
if (!isLevelingUp || !levelUpChoices) return;
// Apply the chosen upgrade
switch (choice) {
case 'damage':
- damageBonus++;
+ damageBonus += 2;
break;
case 'hp':
- player.maxHealth++;
- player.health++;
+ player.maxHealth += 5;
+ player.health += 5;
break;
case 'range':
rangeBonus += 0.2;
break;
+ case 'piercing':
+ piercingBonus++;
+ break;
}
// Clean up level up UI
levelUpChoices.overlay.destroy();
- levelUpChoices.damageChoice.destroy();
- levelUpChoices.hpChoice.destroy();
- levelUpChoices.rangeChoice.destroy();
- levelUpChoices.damageText.destroy();
- levelUpChoices.hpText.destroy();
- levelUpChoices.rangeText.destroy();
+ for (var i = 0; i < levelUpChoices.choices.length; i++) {
+ levelUpChoices.choices[i].destroy();
+ levelUpChoices.choiceTexts[i].destroy();
+ }
levelUpChoices = null;
isLevelingUp = false;
updateUI();
}