User prompt
Skeleton model, after you unlock it, after you click you want to use it, it's the model of the player and you switch it with whatever player model you're using. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'if (typeof storage !== "undefined" && storage.getItem("upgradedKnifeUnlocked")) {' Line Number: 320
User prompt
add skeleton player model when on the unlock section and to unlock it you need to get you need to finish normal mode by getting 900 kills ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
okay when you unlock the the player with 250 make it change the player model from the minecart to the player so the character turns into that
User prompt
Please fix the bug: 'ReferenceError: playerUnlocked is not defined' in or related to this line: 'if (game._superHardMode && !playerUnlocked) {' Line Number: 887
User prompt
Add the player in the unlock section and to unlock it you need to get at least 250 kills in super hard mode
User prompt
Super hard mode, spawn you at the same spot where you spawn in normal mode.
User prompt
Make super hard mode a little bit easier
User prompt
And I'm do it when you beat super hard mode when you click on the unlocked things do It says do you want to use this and then if you click yes, then the upgraded knife will be used
User prompt
Add a section on the main menu called Unlocked, so then you can unlock the upgraded knife.
User prompt
to beat super hard mode you have to reach the score of 1000 and then when you do it you will unlock the upgraded knife
Code edit (1 edits merged)
Please save this source code
User prompt
do, so if you complete the game, well in super hard mode, you unlock the upgraded knife in normal mode, so it is going to be really hard, and when to complete it, you get a knife.
User prompt
Make the buttons pressable.
User prompt
When you click normal mode, it takes you on to the game from before.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'toLocal')' in or related to this line: 'var local = mainMenuOverlay.toLocal({' Line Number: 358
User prompt
When you click normal mode it takes you on to the game from before But when you click super hard mode and then I make a new level with completely different
User prompt
Add a kind of main menu screen where it has two options, normal mode and super hard mode.
User prompt
Add Upgraded Gun Into Game
User prompt
Remove the main menu screen.
User prompt
scale it to there, and you know what, just fix the main menu screen because that's what's doing it, I think.
User prompt
The error is still there, it says, read properties of null, reading invincible.
User prompt
It's still there.
User prompt
Please fix the error.
User prompt
There's a bug. Can you fix it? It's error L505.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Bullet var Bullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.width = bullet.width; self.height = bullet.height; self.speed = -36; // Upwards self.power = 1; // Default bullet power self.angle = 0; // For spread self.update = function () { if (self.angle !== 0) { // Move in angle for spread self.x += Math.sin(self.angle) * 12; self.y += Math.cos(self.angle) * self.speed; } else { self.y += self.speed; } }; return self; }); // Enemy base class var Enemy = Container.expand(function () { var self = Container.call(this); self.type = 'enemy'; self.hp = 1; self.speed = 8; self.scoreValue = 1; self.update = function () {}; return self; }); // Skeleton enemy var Skeleton = Enemy.expand(function () { var self = Enemy.call(this); var skeleton = self.attachAsset('enemy_skeleton', { anchorX: 0.5, anchorY: 0.5 }); // Make skeleton bigger skeleton.scaleX = 1.7; skeleton.scaleY = 1.7; self.width = skeleton.width * 1.7; self.height = skeleton.height * 1.7; self.hp = 1; // Make skeleton slower self.speed = 6 + Math.random() * 2.5; self.scoreValue = 2; self.update = function () { self.y += self.speed; }; return self; }); // Goblin enemy var Goblin = Enemy.expand(function () { var self = Enemy.call(this); var goblin = self.attachAsset('enemy_goblin', { anchorX: 0.5, anchorY: 0.5 }); // Make goblin bigger goblin.scaleX = 1.7; goblin.scaleY = 1.7; self.width = goblin.width * 1.7; self.height = goblin.height * 1.7; self.hp = 2; // Make goblin slower self.speed = 5 + Math.random() * 2; self.scoreValue = 3; self.update = function () { self.y += self.speed; }; return self; }); // Ginger enemy var Ginger = Enemy.expand(function () { var self = Enemy.call(this); // Use goblin as base, but with different color and stats var ginger = self.attachAsset('enemy_goblin', { anchorX: 0.5, anchorY: 0.5 }); // Tint to orange/ginger color ginger.tint = 0xffa14e; ginger.scaleX = 1.7; ginger.scaleY = 1.7; self.width = ginger.width * 1.7; self.height = ginger.height * 1.7; self.hp = 3; self.speed = 7 + Math.random() * 2; self.scoreValue = 7; self.update = function () { self.y += self.speed; }; return self; }); // Bat enemy var Bat = Enemy.expand(function () { var self = Enemy.call(this); var bat = self.attachAsset('enemy_bat', { anchorX: 0.5, anchorY: 0.5 }); // Make bat much bigger so it stands out bat.scaleX = 3.5; bat.scaleY = 3.5; self.width = bat.width * 3.5; self.height = bat.height * 3.5; // Make bat very hard to kill self.hp = 30; // Make bat slower self.speed = 7 + Math.random() * 2.5; // Bat is worth 1000 coins self.scoreValue = 1000; self.update = function () { self.y += self.speed; self.x += Math.sin(LK.ticks / 12 + self._batWobble) * 8; }; self._batWobble = Math.random() * Math.PI * 2; return self; }); // Player Minecart var Minecart = Container.expand(function () { var self = Container.call(this); // Use selected player model from storage or default based on unlocks var assetId = 'minecart'; var selectedModel = storage.selectedPlayerModel || 'default'; if (selectedModel === 'skeleton' && typeof skeletonPlayerUnlocked !== 'undefined' && skeletonPlayerUnlocked) { assetId = 'Skeletonmodel'; } else if (selectedModel === 'player' && typeof playerUnlocked !== 'undefined' && playerUnlocked) { assetId = 'Player'; } else if (typeof skeletonPlayerUnlocked !== 'undefined' && skeletonPlayerUnlocked && selectedModel === 'default') { assetId = 'Skeletonmodel'; } else if (typeof playerUnlocked !== 'undefined' && playerUnlocked && selectedModel === 'default') { assetId = 'Player'; } var cart = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.width = cart.width; self.height = cart.height; self.weapon = 'gun'; // 'gun' or 'knife' self.weaponLevel = 1; // Upgrades increase this self.invincible = false; self.invincibleTimer = 0; self.attackCooldown = 0; self.knifeSwinging = false; self.knife = null; // Flash minecart when hit self.flash = function () { self.invincible = true; self.invincibleTimer = 60; // 1 second at 60fps tween(self, { alpha: 0.5 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 100 }); } }); }; // Switch weapon self.setWeapon = function (type) { self.weapon = type; }; // Upgrade weapon self.upgradeWeapon = function () { self.weaponLevel += 1; if (self.weaponLevel > 3) { self.weaponLevel = 3; } }; // Knife attack animation self.swingKnife = function () { if (self.knifeSwinging) { return; } self.knifeSwinging = true; if (!self.knife) { self.knife = self.attachAsset('knife', { anchorX: 0.1, anchorY: 0.5, x: self.width / 2 + 20, y: 0, rotation: 0 }); } self.knife.visible = true; self.knife.rotation = -0.7; tween(self.knife, { rotation: 0.7 }, { duration: 180, easing: tween.cubicOut, onFinish: function onFinish() { self.knife.visible = false; self.knifeSwinging = false; self.knife.rotation = -0.7; } }); }; return self; }); // Obstacle (rock) var Obstacle = Container.expand(function () { var self = Container.call(this); var rock = self.attachAsset('obstacle_rock', { anchorX: 0.5, anchorY: 0.5 }); self.width = rock.width; self.height = rock.height; self.speed = 14 + Math.random() * 6; self.update = function () { self.y += self.speed; }; return self; }); // Upgrade (gun or knife) var Upgrade = Container.expand(function () { var self = Container.call(this); self.kind = Math.random() < 0.5 ? 'gun' : 'knife'; var assetId = self.kind === 'gun' ? 'upgrade_gun' : 'upgrade_knife'; var upg = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.width = upg.width; self.height = upg.height; self.speed = 10 + Math.random() * 4; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Game constants // Minecart (player) // Player's knife // Player's bullet // Enemy: Bat // Enemy: Goblin // Enemy: Skeleton // Obstacle: Rock // Upgrade: Gun // Upgrade: Knife // Maze background image (replace with your maze image asset id) var GAME_W = 2048; var GAME_H = 2732; var TRACK_LEFT = 300; var TRACK_RIGHT = GAME_W - 300; var PLAYER_Y = GAME_H - 350; // Game state var minecart = null; var bullets = []; var enemies = []; var obstacles = []; var upgrades = []; var dragNode = null; var lastTouchX = 0; var lastTouchY = 0; var scoreTxt = null; var lastScore = 0; var gameOver = false; var spawnTimer = 0; var obstacleTimer = 0; var upgradeTimer = 0; var difficulty = 1; var knifeHitEnemies = []; var lastKnifeSwingTick = -100; // Track if player has unlocked the upgraded knife by beating super hard mode var upgradedKnifeUnlocked = false; // Track if player has chosen to use upgraded knife in normal mode (set via menu) var useUpgradedKnifeNextGame = false; // Track if player has unlocked the player (250 kills in super hard mode) var playerUnlocked = false; var playerKills = 0; // Track skeleton player unlock (900 kills in normal mode) var skeletonPlayerUnlocked = storage.skeletonPlayerUnlocked || false; var normalModeKills = storage.normalModeKills || 0; // Try to load from persistent storage if available if (typeof storage !== "undefined" && storage.upgradedKnifeUnlocked) { upgradedKnifeUnlocked = true; } if (typeof storage !== "undefined" && storage.playerUnlocked) { playerUnlocked = true; } if (typeof storage !== "undefined" && storage.playerKills) { playerKills = parseInt(storage.playerKills, 10) || 0; } // Always reset useUpgradedKnifeNextGame on load useUpgradedKnifeNextGame = false; // --- Main Menu Overlay --- var mainMenuOverlay = null; var mainMenuTitle = null; var normalBtn = null; var hardBtn = null; var menuActive = true; function showMainMenu() { menuActive = true; // Overlay container mainMenuOverlay = new Container(); // Semi-transparent dark background var bg = LK.getAsset('maze_bg', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: GAME_W, height: GAME_H }); bg.alpha = 0.82; mainMenuOverlay.addChild(bg); // Title mainMenuTitle = new Text2("Boneshaft 1: UPGRADED", { size: 180, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); mainMenuTitle.anchor.set(0.5, 0.5); mainMenuTitle.x = GAME_W / 2; mainMenuTitle.y = 600; mainMenuOverlay.addChild(mainMenuTitle); // Normal Mode Button var normalLabel = "Normal Mode"; if (upgradedKnifeUnlocked) { normalLabel += " (Upgraded Knife!)"; } normalBtn = new Text2(normalLabel, { size: 120, fill: 0x44FF44, font: "Impact, Arial Black, Tahoma" }); normalBtn.anchor.set(0.5, 0.5); normalBtn.x = GAME_W / 2; normalBtn.y = 1100; mainMenuOverlay.addChild(normalBtn); // Super Hard Mode Button hardBtn = new Text2("Super Hard Mode", { size: 120, fill: 0xFF4444, font: "Impact, Arial Black, Tahoma" }); hardBtn.anchor.set(0.5, 0.5); hardBtn.x = GAME_W / 2; hardBtn.y = 1350; mainMenuOverlay.addChild(hardBtn); // --- Unlocked Section --- var unlockedTitle = new Text2("Unlocked", { size: 90, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); unlockedTitle.anchor.set(0.5, 0.5); unlockedTitle.x = GAME_W / 2; unlockedTitle.y = 1550; mainMenuOverlay.addChild(unlockedTitle); var unlockedKnifeText, unlockedKnifeIcon; var unlockedPlayerText, unlockedPlayerIcon; var playerUnlocked = false; var playerKills = 0; // Try to load from persistent storage if available if (typeof storage !== "undefined" && storage.playerUnlocked) { playerUnlocked = true; } if (typeof storage !== "undefined" && storage.playerKills) { playerKills = parseInt(storage.playerKills, 10) || 0; } if (upgradedKnifeUnlocked) { var showKnifeConfirmDialog = function showKnifeConfirmDialog() { if (knifeConfirmDialog) return; knifeConfirmDialog = new Container(); // Dialog background var dialogBg = LK.getAsset('maze_bg', { anchorX: 0, anchorY: 0, x: GAME_W / 2 - 400, y: 1200, width: 800, height: 400 }); dialogBg.alpha = 0.93; knifeConfirmDialog.addChild(dialogBg); // Dialog text var dialogText = new Text2("Use Upgraded Knife in Normal Mode?", { size: 60, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); dialogText.anchor.set(0.5, 0.5); dialogText.x = GAME_W / 2; dialogText.y = 1320; knifeConfirmDialog.addChild(dialogText); // Yes button var yesBtn = new Text2("Yes", { size: 90, fill: 0x44FF44, font: "Impact, Arial Black, Tahoma" }); yesBtn.anchor.set(0.5, 0.5); yesBtn.x = GAME_W / 2 - 140; yesBtn.y = 1450; knifeConfirmDialog.addChild(yesBtn); // No button var noBtn = new Text2("No", { size: 90, fill: 0xFF4444, font: "Impact, Arial Black, Tahoma" }); noBtn.anchor.set(0.5, 0.5); noBtn.x = GAME_W / 2 + 140; noBtn.y = 1450; knifeConfirmDialog.addChild(noBtn); // Button handlers yesBtn.interactive = true; noBtn.interactive = true; yesBtn.down = function () { // Set a global flag to use upgraded knife in normal mode useUpgradedKnifeNextGame = true; // Remove dialog if (knifeConfirmDialog) { knifeConfirmDialog.destroy(); knifeConfirmDialog = null; } }; noBtn.down = function () { // Just close dialog if (knifeConfirmDialog) { knifeConfirmDialog.destroy(); knifeConfirmDialog = null; } }; yesBtn.on('down', yesBtn.down); noBtn.on('down', noBtn.down); mainMenuOverlay.addChild(knifeConfirmDialog); }; // Handler for both icon and text var unlockedKnifeDownHandler = function unlockedKnifeDownHandler() { showKnifeConfirmDialog(); }; unlockedKnifeText = new Text2("Upgraded Knife", { size: 80, fill: 0xFFD700, font: "Impact, Arial Black, Tahoma" }); unlockedKnifeIcon = LK.getAsset('upgrade_knife', { anchorX: 0.5, anchorY: 0.5, x: GAME_W / 2 - 120, y: 1650 }); unlockedKnifeText.anchor.set(0, 0.5); unlockedKnifeText.x = GAME_W / 2 - 60; unlockedKnifeText.y = 1650; mainMenuOverlay.addChild(unlockedKnifeIcon); mainMenuOverlay.addChild(unlockedKnifeText); // Make the unlocked knife section pressable unlockedKnifeText.interactive = true; unlockedKnifeIcon.interactive = true; // Confirmation dialog container (created on demand) var knifeConfirmDialog = null; unlockedKnifeText.down = unlockedKnifeDownHandler; unlockedKnifeIcon.down = unlockedKnifeDownHandler; unlockedKnifeText.on('down', unlockedKnifeDownHandler); unlockedKnifeIcon.on('down', unlockedKnifeDownHandler); } else { unlockedKnifeText = new Text2("??? (Beat Super Hard Mode to unlock)", { size: 70, fill: 0x888888, font: "Impact, Arial Black, Tahoma" }); unlockedKnifeText.anchor.set(0.5, 0.5); unlockedKnifeText.x = GAME_W / 2; unlockedKnifeText.y = 1650; mainMenuOverlay.addChild(unlockedKnifeText); } // --- Player Unlock Section --- var playerSectionY = 1800; if (playerUnlocked) { unlockedPlayerText = new Text2("Player (Unlocked!)", { size: 80, fill: 0x00BFFF, font: "Impact, Arial Black, Tahoma" }); unlockedPlayerIcon = LK.getAsset('Player', { anchorX: 0.5, anchorY: 0.5, x: GAME_W / 2 - 120, y: playerSectionY }); unlockedPlayerText.anchor.set(0, 0.5); unlockedPlayerText.x = GAME_W / 2 - 60; unlockedPlayerText.y = playerSectionY; mainMenuOverlay.addChild(unlockedPlayerIcon); mainMenuOverlay.addChild(unlockedPlayerText); // Make player section interactive to switch model var playerDownHandler = function playerDownHandler() { // Set player model as selected player model storage.selectedPlayerModel = 'player'; }; unlockedPlayerText.interactive = true; unlockedPlayerIcon.interactive = true; unlockedPlayerText.down = playerDownHandler; unlockedPlayerIcon.down = playerDownHandler; unlockedPlayerText.on('down', playerDownHandler); unlockedPlayerIcon.on('down', playerDownHandler); } else { var killsNeeded = 250 - playerKills; if (killsNeeded < 0) killsNeeded = 0; unlockedPlayerText = new Text2("??? (Get 250 kills in Super Hard Mode to unlock)\nKills: " + playerKills + " / 250", { size: 60, fill: 0x888888, font: "Impact, Arial Black, Tahoma" }); unlockedPlayerText.anchor.set(0.5, 0.5); unlockedPlayerText.x = GAME_W / 2; unlockedPlayerText.y = playerSectionY; mainMenuOverlay.addChild(unlockedPlayerText); } // --- Skeleton Player Unlock Section --- var skeletonSectionY = 1950; if (skeletonPlayerUnlocked) { var unlockedSkeletonText = new Text2("Skeleton Player (Unlocked!)", { size: 80, fill: 0xFFD700, font: "Impact, Arial Black, Tahoma" }); var unlockedSkeletonIcon = LK.getAsset('Skeletonmodel', { anchorX: 0.5, anchorY: 0.5, x: GAME_W / 2 - 120, y: skeletonSectionY }); unlockedSkeletonText.anchor.set(0, 0.5); unlockedSkeletonText.x = GAME_W / 2 - 60; unlockedSkeletonText.y = skeletonSectionY; mainMenuOverlay.addChild(unlockedSkeletonIcon); mainMenuOverlay.addChild(unlockedSkeletonText); // Make skeleton player section interactive to switch model var skeletonPlayerDownHandler = function skeletonPlayerDownHandler() { // Set skeleton model as selected player model storage.selectedPlayerModel = 'skeleton'; }; unlockedSkeletonText.interactive = true; unlockedSkeletonIcon.interactive = true; unlockedSkeletonText.down = skeletonPlayerDownHandler; unlockedSkeletonIcon.down = skeletonPlayerDownHandler; unlockedSkeletonText.on('down', skeletonPlayerDownHandler); unlockedSkeletonIcon.on('down', skeletonPlayerDownHandler); } else { var killsNeeded = 900 - normalModeKills; if (killsNeeded < 0) killsNeeded = 0; var unlockedSkeletonText = new Text2("??? (Get 900 kills in Normal Mode to unlock)\nKills: " + normalModeKills + " / 900", { size: 60, fill: 0x888888, font: "Impact, Arial Black, Tahoma" }); unlockedSkeletonText.anchor.set(0.5, 0.5); unlockedSkeletonText.x = GAME_W / 2; unlockedSkeletonText.y = skeletonSectionY; mainMenuOverlay.addChild(unlockedSkeletonText); } // Add overlay to game game.addChild(mainMenuOverlay); // Button hit areas normalBtn.interactive = true; hardBtn.interactive = true; // Add direct down event handlers to buttons for pressable effect normalBtn.down = function (x, y, obj) { if (!mainMenuOverlay) { return; } selectMode('normal'); }; hardBtn.down = function (x, y, obj) { if (!mainMenuOverlay) { return; } selectMode('hard'); }; normalBtn.on('down', normalBtn.down); hardBtn.on('down', hardBtn.down); // Touch/click handlers mainMenuOverlay.down = function (x, y, obj) { // Defensive: If overlay is destroyed or null, do nothing if (!mainMenuOverlay) { return; } // Convert to overlay local coordinates var local = mainMenuOverlay.toLocal({ x: x, y: y }); // Check if normalBtn was pressed if (pointInText(normalBtn, local.x, local.y)) { selectMode('normal'); } else if (pointInText(hardBtn, local.x, local.y)) { selectMode('hard'); } }; // Attach to overlay mainMenuOverlay.on('down', mainMenuOverlay.down); // Also attach to game for mobile game.down = function (x, y, obj) { if (menuActive && mainMenuOverlay) { mainMenuOverlay.down(x, y, obj); return; } if (gameOver) { return; } dragNode = minecart; lastTouchX = x; lastTouchY = y; }; } // Helper: check if point is inside Text2 bounds function pointInText(txt, x, y) { var w = txt.width; var h = txt.height; var tx = txt.x - w * txt.anchor.x; var ty = txt.y - h * txt.anchor.y; return x >= tx && x <= tx + w && y >= ty && y <= ty + h; } // Remove menu and start game function selectMode(mode) { if (!mainMenuOverlay) { return; } menuActive = false; mainMenuOverlay.destroy(); mainMenuOverlay = null; // Set difficulty and level mode if (mode === 'normal') { // Set up original game state for normal mode difficulty = 1; game._superHardMode = false; // Remove any super hard mode UI if present if (game._batHealthBarBg) { LK.gui.top.removeChild(game._batHealthBarBg); game._batHealthBarBg = null; } if (game._batHealthBar) { LK.gui.top.removeChild(game._batHealthBar); game._batHealthBar = null; } game._batEnemy = null; game._batMaxHp = null; // Place player at original starting position if (minecart) { minecart.x = GAME_W / 2; minecart.y = PLAYER_Y; // If upgraded knife is unlocked AND player chose to use it, start with knife and max level if (upgradedKnifeUnlocked && useUpgradedKnifeNextGame) { minecart.setWeapon('knife'); minecart.weaponLevel = 3; useUpgradedKnifeNextGame = false; // Reset after use } } } else if (mode === 'hard') { difficulty = 7; game._superHardMode = true; } // Reset game state LK.setScore(0); if (scoreTxt) { scoreTxt.setText('0'); } if (minecart) { minecart.x = GAME_W / 2; minecart.y = PLAYER_Y; minecart.weapon = 'gun'; minecart.weaponLevel = 1; minecart.invincible = false; minecart.invincibleTimer = 0; minecart.attackCooldown = 0; minecart.knifeSwinging = false; minecart.setWeapon('gun'); } bullets = []; enemies = []; obstacles = []; upgrades = []; spawnTimer = 0; obstacleTimer = 60; upgradeTimer = 600; knifeHitEnemies = []; lastKnifeSwingTick = -100; gameOver = false; // If super hard mode, set up new level if (game._superHardMode) { // Remove all enemies, obstacles, upgrades, and spawn a new set for the new level for (var i = 0; i < enemies.length; ++i) { enemies[i].destroy(); } for (var i = 0; i < obstacles.length; ++i) { obstacles[i].destroy(); } for (var i = 0; i < upgrades.length; ++i) { upgrades[i].destroy(); } enemies = []; obstacles = []; upgrades = []; // Place player at the same starting position as normal mode minecart.x = GAME_W / 2; minecart.y = PLAYER_Y; // Optionally, change background or add new obstacles/enemy patterns // Example: spawn a wall of goblins at the top for (var gx = TRACK_LEFT + 120; gx < TRACK_RIGHT - 120; gx += 180) { var g = new Goblin(); g.x = gx; g.y = 0; enemies.push(g); game.addChild(g); } // Example: spawn a bat immediately var bat = new Bat(); bat.x = GAME_W / 2; bat.y = -100; enemies.push(bat); game.addChild(bat); // Set up bat health bar UI for super hard mode var barWidth = 1700; var barHeight = 90; var barBg = LK.getAsset('enemy_goblin', { width: barWidth, height: barHeight, color: 0x222222, anchorX: 0.5, anchorY: 0 }); barBg.x = GAME_W / 2; barBg.y = 10; var bar = LK.getAsset('enemy_goblin', { width: barWidth - 20, height: barHeight - 18, color: 0xff2222, anchorX: 0.5, anchorY: 0 }); bar.x = GAME_W / 2; bar.y = 19; LK.gui.top.addChild(barBg); LK.gui.top.addChild(bar); game._batHealthBarBg = barBg; game._batHealthBar = bar; game._batEnemy = bat; game._batMaxHp = bat.hp; } } // Add maze background image var mazeBg = LK.getAsset('maze_bg', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: GAME_W, height: GAME_H }); game.addChild(mazeBg); // Score display scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create player minecart = new Minecart(); game.addChild(minecart); minecart.x = GAME_W / 2; minecart.y = PLAYER_Y; // Vertical shooter: drag minecart only in X, fixed Y game.down = function (x, y, obj) { if (gameOver) { return; } dragNode = minecart; lastTouchX = x; lastTouchY = y; }; game.up = function (x, y, obj) { dragNode = null; }; game.move = function (x, y, obj) { if (gameOver) { return; } if (dragNode === minecart) { // Only allow movement in X, clamp to track var nx = x; if (nx < TRACK_LEFT) { nx = TRACK_LEFT; } if (nx > TRACK_RIGHT) { nx = TRACK_RIGHT; } minecart.x = nx; minecart.y = PLAYER_Y; } }; // Tap to attack (shoot or knife) game.tap = function (x, y, obj) { if (gameOver) { return; } if (minecart.weapon === 'gun') { if (minecart.attackCooldown <= 0) { fireBullet(); minecart.attackCooldown = 12 - minecart.weaponLevel * 2; // Faster with upgrades if (minecart.attackCooldown < 4) { minecart.attackCooldown = 4; } } } else if (minecart.weapon === 'knife') { if (LK.ticks - lastKnifeSwingTick > 18) { minecart.swingKnife(); lastKnifeSwingTick = LK.ticks; } } }; // Fire bullet(s) function fireBullet() { var spread = minecart.weaponLevel; var angleSpread = 0.18; // radians, about 10 degrees var basePower = 1 + Math.floor((minecart.weaponLevel - 1) / 2); // Level 1-2: 1, Level 3: 2 for (var i = 0; i < spread; ++i) { var b = new Bullet(); // Spread bullets horizontally and with angle var offset = i - (spread - 1) / 2; b.x = minecart.x + offset * 40; b.y = minecart.y - minecart.height / 2 - 10; // Angle for spread: center is 0, sides are negative/positive if (spread > 1) { b.angle = offset * angleSpread; } b.power = basePower; bullets.push(b); game.addChild(b); } } // Main update loop game.update = function () { if (menuActive) { return; } if (gameOver) { return; } // Difficulty scaling if (LK.ticks % 300 === 0 && difficulty < 10) { difficulty += 1; } // Attack cooldown if (minecart && minecart.attackCooldown > 0) { minecart.attackCooldown -= 1; } // Invincibility timer if (minecart && minecart.invincible) { minecart.invincibleTimer -= 1; if (minecart.invincibleTimer <= 0) { minecart.invincible = false; } } // Bullets update for (var i = bullets.length - 1; i >= 0; --i) { var b = bullets[i]; b.update(); if (b.y < -50) { b.destroy(); bullets.splice(i, 1); continue; } // Bullet hits enemy for (var j = enemies.length - 1; j >= 0; --j) { var e = enemies[j]; if (b.intersects(e)) { // Use bullet power for damage e.hp -= b.power || 1; // If this is the Bat, update health bar if (game._batEnemy && e === game._batEnemy && game._batHealthBar) { var percent = Math.max(0, e.hp) / game._batMaxHp; // Clamp width to minimum 0 game._batHealthBar.width = 1680 * percent; // Optionally, you can tint the bar as it gets low (not required) } b.destroy(); bullets.splice(i, 1); if (e.hp <= 0) { addScore(e.scoreValue); e.destroy(); enemies.splice(j, 1); // If Bat is dead, remove health bar UI if (game._batEnemy && e === game._batEnemy) { if (game._batHealthBarBg) { LK.gui.top.removeChild(game._batHealthBarBg); game._batHealthBarBg = null; } if (game._batHealthBar) { LK.gui.top.removeChild(game._batHealthBar); game._batHealthBar = null; } game._batEnemy = null; // If in super hard mode, check for score 1000 to win and unlock upgraded knife if (game._superHardMode && !upgradedKnifeUnlocked) { if (LK.getScore() >= 1000) { upgradedKnifeUnlocked = true; if (typeof storage !== "undefined") { storage.upgradedKnifeUnlocked = true; } // Show a win popup LK.showYouWin(); gameOver = true; return; } // Otherwise, keep playing until score 1000 is reached } } // --- Player unlock logic: count kills in super hard mode --- if (game._superHardMode && !playerUnlocked) { if (typeof playerKills === "undefined") playerKills = 0; playerKills++; if (playerKills >= 250) { playerUnlocked = true; if (typeof storage !== "undefined") { storage.playerUnlocked = true; } } if (typeof storage !== "undefined") { storage.playerKills = playerKills; } } // --- Skeleton player unlock logic: count kills in normal mode --- if (!game._superHardMode && !skeletonPlayerUnlocked) { if (typeof normalModeKills === "undefined") normalModeKills = 0; normalModeKills++; storage.normalModeKills = normalModeKills; if (normalModeKills >= 900) { skeletonPlayerUnlocked = true; storage.skeletonPlayerUnlocked = true; } } } break; } } } // Enemies update (vertical shooter: always visible, move down) for (var i = enemies.length - 1; i >= 0; --i) { var e = enemies[i]; e.update(); // Remove if out of bounds if (e.y > GAME_H + 200) { e.destroy(); enemies.splice(i, 1); continue; } // Enemy hits minecart if (minecart && minecart !== null && !minecart.invincible && e.intersects(minecart)) { // Check if Bat killed the player for jump scare if (game._batEnemy && e === game._batEnemy) { // Show a big jump scare: flash white, show a big FACE in the center, and play a loud sound if available LK.effects.flashScreen(0xffffff, 1200); // Create a big FACE image in the center (using the goblin face as a placeholder for a jumpscare face) var jumpscareFace = LK.getAsset('enemy_goblin', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, x: GAME_W / 2, y: GAME_H / 2 }); jumpscareFace.alpha = 0; game.addChild(jumpscareFace); // Animate the face: scale up and fade in quickly, then fade out tween(jumpscareFace, { alpha: 1, scaleX: 7, scaleY: 7 }, { duration: 120, onFinish: function onFinish() { tween(jumpscareFace, { alpha: 0 }, { duration: 700, delay: 350, onFinish: function onFinish() { jumpscareFace.destroy(); } }); } }); // Optionally, play a loud sound here if you have a jumpscare sound asset } minecart.flash(); LK.effects.flashScreen(0xff0000, 600); // End game LK.showGameOver(); gameOver = true; return; } // Enemy hit by knife if (minecart.weapon === 'knife' && minecart.knife && minecart.knife.visible && !knifeHitEnemies.includes(e)) { // Knife is in swing, check collision var knifeGlobal = minecart.toGlobal(minecart.knife.position); var knifeRect = new Rectangle(knifeGlobal.x - 30, knifeGlobal.y - 12, 60, 24); var enemyRect = new Rectangle(e.x - e.width / 2, e.y - e.height / 2, e.width, e.height); if (rectsIntersect(knifeRect, enemyRect)) { e.hp -= 1; // If this is the Bat, update health bar if (game._batEnemy && e === game._batEnemy && game._batHealthBar) { var percent = Math.max(0, e.hp) / game._batMaxHp; game._batHealthBar.width = 1680 * percent; } knifeHitEnemies.push(e); if (e.hp <= 0) { addScore(e.scoreValue); e.destroy(); enemies.splice(i, 1); // If Bat is dead, remove health bar UI if (game._batEnemy && e === game._batEnemy) { if (game._batHealthBarBg) { LK.gui.top.removeChild(game._batHealthBarBg); game._batHealthBarBg = null; } if (game._batHealthBar) { LK.gui.top.removeChild(game._batHealthBar); game._batHealthBar = null; } game._batEnemy = null; } } } } } // Reset knife hit list if knife not swinging if (!minecart || !minecart.knife || !minecart.knife.visible) { knifeHitEnemies = []; } // Obstacles update for (var i = obstacles.length - 1; i >= 0; --i) { var o = obstacles[i]; o.update(); if (o.y > GAME_H + 100) { o.destroy(); obstacles.splice(i, 1); continue; } // Obstacle hits minecart if (minecart && !minecart.invincible && o.intersects(minecart)) { minecart.flash(); LK.effects.flashScreen(0xff0000, 600); LK.showGameOver(); gameOver = true; return; } } // Upgrades update for (var i = upgrades.length - 1; i >= 0; --i) { var u = upgrades[i]; u.update(); if (u.y > GAME_H + 100) { u.destroy(); upgrades.splice(i, 1); continue; } // Pickup if (u.intersects(minecart)) { if (u.kind === 'gun') { minecart.setWeapon('gun'); minecart.upgradeWeapon(); } else { minecart.setWeapon('knife'); minecart.upgradeWeapon(); } u.destroy(); upgrades.splice(i, 1); } } // Spawning enemies spawnTimer -= 1; if (spawnTimer <= 0) { spawnEnemy(); spawnTimer = Math.max(24, 60 - difficulty * 4 - Math.floor(Math.random() * 10)); } // Spawning obstacles obstacleTimer -= 1; if (obstacleTimer <= 0) { if (Math.random() < 0.5 + difficulty * 0.04) { spawnObstacle(); } obstacleTimer = 90 + Math.floor(Math.random() * 60) - difficulty * 4; if (obstacleTimer < 30) { obstacleTimer = 30; } } // Spawning upgrades upgradeTimer -= 1; if (upgradeTimer <= 0) { if (game._superHardMode) { // Easier: upgrades spawn more often in super hard mode if (Math.random() < 0.38) { spawnUpgrade(); } upgradeTimer = 340 + Math.floor(Math.random() * 120); } else { if (Math.random() < 0.18) { spawnUpgrade(); } upgradeTimer = 600 + Math.floor(Math.random() * 300); } } // Update score display if (LK.getScore() !== lastScore) { scoreTxt.setText(LK.getScore()); lastScore = LK.getScore(); } // Win condition for super hard mode: reach score 1000 if (game._superHardMode && !upgradedKnifeUnlocked && LK.getScore() >= 1000) { upgradedKnifeUnlocked = true; if (typeof storage !== "undefined") { storage.upgradedKnifeUnlocked = true; } LK.showYouWin(); gameOver = true; return; } }; // Spawn enemy at random X at the top (vertical shooter style) function spawnEnemy() { // If in super hard mode, spawn new enemy patterns if (game._superHardMode) { // Example: spawn a slightly slower skeleton and a goblin together (easier) var e1 = new Skeleton(); e1.speed = 10 + Math.random() * 2.5; e1.x = TRACK_LEFT + 120 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 240); e1.y = -80; enemies.push(e1); game.addChild(e1); var e2 = new Goblin(); e2.speed = 8 + Math.random() * 2; e2.x = TRACK_LEFT + 120 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 240); e2.y = -180; enemies.push(e2); game.addChild(e2); // Occasionally spawn a Bat if (Math.random() < 0.12) { var bat = new Bat(); bat.x = TRACK_LEFT + 120 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 240); bat.y = -200; enemies.push(bat); game.addChild(bat); // Set up bat health bar UI var barWidth = 1700; var barHeight = 90; var barBg = LK.getAsset('enemy_goblin', { width: barWidth, height: barHeight, color: 0x222222, anchorX: 0.5, anchorY: 0 }); barBg.x = GAME_W / 2; barBg.y = 10; var bar = LK.getAsset('enemy_goblin', { width: barWidth - 20, height: barHeight - 18, color: 0xff2222, anchorX: 0.5, anchorY: 0 }); bar.x = GAME_W / 2; bar.y = 19; LK.gui.top.addChild(barBg); LK.gui.top.addChild(bar); game._batHealthBarBg = barBg; game._batHealthBar = bar; game._batEnemy = bat; game._batMaxHp = bat.hp; } // Sometimes spawn a ginger if (Math.random() < 0.25) { var g = new Ginger(); g.x = TRACK_LEFT + 120 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 240); g.y = -120; enemies.push(g); game.addChild(g); } return; } // --- Normal mode enemy spawn --- var enemyType = Math.random(); var e = null; // Bat is now extremely rare: only spawn if enemyType < 0.02 (2% chance) if (enemyType < 0.02) { e = new Bat(); // Show warning text and play creepy music when Bat spawns if (!game._batWarningText) { // Create warning text if not already present var batWarning = new Text2("That is not you.", { size: 120, fill: 0xFF2222, font: "Impact, Arial Black, Tahoma" }); batWarning.anchor.set(0.5, 0.5); batWarning.alpha = 0.0; game._batWarningText = batWarning; // Add to LK.gui.center for true center of screen LK.gui.center.addChild(batWarning); } // Fade in text var warningText = game._batWarningText; warningText.alpha = 0.0; tween(warningText, { alpha: 1 }, { duration: 400, onFinish: function onFinish() { // Fade out after 1.2s tween(warningText, { alpha: 0 }, { duration: 800, delay: 1200 }); } }); // Play creepy music (music asset id: 'creepy_bat') LK.playMusic('creepy_bat', { fade: { start: 0, end: 1, duration: 800 } }); // --- Bat Health Bar UI --- // Remove any previous bat health bar if (game._batHealthBarBg) { LK.gui.top.removeChild(game._batHealthBarBg); game._batHealthBarBg = null; } if (game._batHealthBar) { LK.gui.top.removeChild(game._batHealthBar); game._batHealthBar = null; } // Create background bar (much bigger, at the very top) var barWidth = 1700; var barHeight = 90; var barBg = LK.getAsset('enemy_goblin', { width: barWidth, height: barHeight, color: 0x222222, anchorX: 0.5, anchorY: 0 }); barBg.x = GAME_W / 2; barBg.y = 10; // Very top of the screen // Create health bar (red, much bigger) var bar = LK.getAsset('enemy_goblin', { width: barWidth - 20, height: barHeight - 18, color: 0xff2222, anchorX: 0.5, anchorY: 0 }); bar.x = GAME_W / 2; bar.y = 19; // Just below the background bar // Add to GUI LK.gui.top.addChild(barBg); LK.gui.top.addChild(bar); game._batHealthBarBg = barBg; game._batHealthBar = bar; // Store reference to the Bat instance for health bar updates game._batEnemy = e; game._batMaxHp = e.hp; } else if (enemyType < 0.10) { // Ginger is rare, 8% chance (between 2% and 10%) e = new Ginger(); } else if (enemyType < 0.65) { e = new Goblin(); } else { e = new Skeleton(); } // Spawn at random X at the top of the screen e.x = TRACK_LEFT + 80 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 160); e.y = -80; enemies.push(e); game.addChild(e); } // Spawn obstacle function spawnObstacle() { var o = new Obstacle(); o.x = TRACK_LEFT + 80 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 160); o.y = -60; obstacles.push(o); game.addChild(o); } // Spawn upgrade function spawnUpgrade() { var u = new Upgrade(); u.x = TRACK_LEFT + 80 + Math.random() * (TRACK_RIGHT - TRACK_LEFT - 160); u.y = -60; upgrades.push(u); game.addChild(u); } // Add score function addScore(val) { LK.setScore(LK.getScore() + val); } // Rectangle intersection helper function rectsIntersect(r1, r2) { return !(r2.x > r1.x + r1.width || r2.x + r2.width < r1.x || r2.y > r1.y + r1.height || r2.y + r2.height < r1.y); } // Touch to attack (simulate tap on mobile) game.down = function (origDown) { return function (x, y, obj) { if (origDown) { origDown(x, y, obj); } game.tap(x, y, obj); }; }(game.down); // Reset game state on game over LK.on('gameover', function () { gameOver = true; setTimeout(function () { showMainMenu(); }, 600); }); // Track run count for Bat spawn logic if (typeof game._runCount === "undefined") { game._runCount = 0; } LK.on('newgame', function () { game._runCount = (game._runCount || 0) + 1; gameOver = false; LK.setScore(0); if (scoreTxt) { scoreTxt.setText('0'); } // Remove all objects for (var i = 0; i < bullets.length; ++i) { bullets[i].destroy(); } for (var i = 0; i < enemies.length; ++i) { enemies[i].destroy(); } for (var i = 0; i < obstacles.length; ++i) { obstacles[i].destroy(); } for (var i = 0; i < upgrades.length; ++i) { upgrades[i].destroy(); } bullets = []; enemies = []; obstacles = []; upgrades = []; minecart.x = GAME_W / 2; minecart.y = PLAYER_Y; minecart.weapon = 'gun'; minecart.weaponLevel = 1; minecart.invincible = false; minecart.invincibleTimer = 0; minecart.attackCooldown = 0; minecart.knifeSwinging = false; minecart.setWeapon('gun'); difficulty = 1; spawnTimer = 0; obstacleTimer = 0; upgradeTimer = 0; knifeHitEnemies = []; lastKnifeSwingTick = -100; // Remove Bat health bar UI if present if (game._batHealthBarBg) { LK.gui.top.removeChild(game._batHealthBarBg); game._batHealthBarBg = null; } if (game._batHealthBar) { LK.gui.top.removeChild(game._batHealthBar); game._batHealthBar = null; } game._batEnemy = null; game._batMaxHp = null; }); // Initial state spawnTimer = 0; obstacleTimer = 60; upgradeTimer = 600; difficulty = 1; gameOver = false; LK.setScore(0); if (scoreTxt) { scoreTxt.setText('0'); } // Show main menu on load showMainMenu();
===================================================================
--- original.js
+++ change.js
@@ -131,14 +131,19 @@
});
// Player Minecart
var Minecart = Container.expand(function () {
var self = Container.call(this);
- // Use skeleton model if unlocked, otherwise Player if unlocked, otherwise minecart
+ // Use selected player model from storage or default based on unlocks
var assetId = 'minecart';
- if (typeof skeletonPlayerUnlocked !== 'undefined' && skeletonPlayerUnlocked) {
+ var selectedModel = storage.selectedPlayerModel || 'default';
+ if (selectedModel === 'skeleton' && typeof skeletonPlayerUnlocked !== 'undefined' && skeletonPlayerUnlocked) {
assetId = 'Skeletonmodel';
- } else if (typeof playerUnlocked !== 'undefined' && playerUnlocked) {
+ } else if (selectedModel === 'player' && typeof playerUnlocked !== 'undefined' && playerUnlocked) {
assetId = 'Player';
+ } else if (typeof skeletonPlayerUnlocked !== 'undefined' && skeletonPlayerUnlocked && selectedModel === 'default') {
+ assetId = 'Skeletonmodel';
+ } else if (typeof playerUnlocked !== 'undefined' && playerUnlocked && selectedModel === 'default') {
+ assetId = 'Player';
}
var cart = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
@@ -512,8 +517,19 @@
unlockedPlayerText.x = GAME_W / 2 - 60;
unlockedPlayerText.y = playerSectionY;
mainMenuOverlay.addChild(unlockedPlayerIcon);
mainMenuOverlay.addChild(unlockedPlayerText);
+ // Make player section interactive to switch model
+ var playerDownHandler = function playerDownHandler() {
+ // Set player model as selected player model
+ storage.selectedPlayerModel = 'player';
+ };
+ unlockedPlayerText.interactive = true;
+ unlockedPlayerIcon.interactive = true;
+ unlockedPlayerText.down = playerDownHandler;
+ unlockedPlayerIcon.down = playerDownHandler;
+ unlockedPlayerText.on('down', playerDownHandler);
+ unlockedPlayerIcon.on('down', playerDownHandler);
} else {
var killsNeeded = 250 - playerKills;
if (killsNeeded < 0) killsNeeded = 0;
unlockedPlayerText = new Text2("??? (Get 250 kills in Super Hard Mode to unlock)\nKills: " + playerKills + " / 250", {
@@ -544,8 +560,19 @@
unlockedSkeletonText.x = GAME_W / 2 - 60;
unlockedSkeletonText.y = skeletonSectionY;
mainMenuOverlay.addChild(unlockedSkeletonIcon);
mainMenuOverlay.addChild(unlockedSkeletonText);
+ // Make skeleton player section interactive to switch model
+ var skeletonPlayerDownHandler = function skeletonPlayerDownHandler() {
+ // Set skeleton model as selected player model
+ storage.selectedPlayerModel = 'skeleton';
+ };
+ unlockedSkeletonText.interactive = true;
+ unlockedSkeletonIcon.interactive = true;
+ unlockedSkeletonText.down = skeletonPlayerDownHandler;
+ unlockedSkeletonIcon.down = skeletonPlayerDownHandler;
+ unlockedSkeletonText.on('down', skeletonPlayerDownHandler);
+ unlockedSkeletonIcon.on('down', skeletonPlayerDownHandler);
} else {
var killsNeeded = 900 - normalModeKills;
if (killsNeeded < 0) killsNeeded = 0;
var unlockedSkeletonText = new Text2("??? (Get 900 kills in Normal Mode to unlock)\nKills: " + normalModeKills + " / 900", {
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Minecart Mayhem: Armed Run" and with the description "Survive a wild minecart ride by battling multiple enemy types with guns and knives, dodging obstacles, and collecting upgrades for a high-score chase.". No text on banner!
A skeleton with 3 legs and a creepy face and red eyes. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A silver bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a maze . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Man with bag on head and red eyes. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A man with a bag over his head and red eyes. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Knife. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Rock. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Zombie. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A knife with purple and golden around it. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Man with bag on head with cross on it. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Skeleton player model. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat