User prompt
When a sword or defensive gear is added,show it in the player stats and also increase either dmg or defense depending on the geat the player has.
User prompt
No loot dropped is appearign when the battle starts also, something is wrong.
User prompt
No loot dropped is being displayed even after battle ends, can you try fix it.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'filter')' in or related to this line: 'var lootTypes = battleScreen._rewardTypes.filter(function (type) {' Line Number: 857
User prompt
monters can also drop loot. ifmonster drops loot, it should be announced on battle end screen
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.statsTabBtn.textStyle.fill = 0xFFE066;' Line Number: 1095
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.statsTabBtn.style.fill = 0xFFE066;' Line Number: 1095
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.statsTabBtn.textStyle.fill = 0xFFE066;' Line Number: 1095
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.statsTabBtn.style.fill = 0xFFE066;' Line Number: 1095
User prompt
stats should have two tabs. one with the actaulplayer stats and the other with inventory including itemsand coins.
User prompt
When a monster is killed they can drop coins, or loot, like swords, shiedls, armor or helmets. the lower the level of enemy the worst the quality of loot. Initially, lets just create some loot. Wood, bronze an silver for each item, adding +1 +2 +3 to def or attack depending on what they are for.
User prompt
Lets add more rpg elements to othe game. So lets add a button where the player can open up the player stats. Player stats will be DEF, ATK, and HP. Will start with HP=10 and DEF and ATK(DMG) =1. Once the player levels up, they can distribute skill points to either of this categories, and heal their life. this will replace the previous level up options.
User prompt
on chest screen, initially just double click on chest to open it. we will then add more keys, or lockpicks. Chests can have life potions, coins, or gear like shields, swords, helmets and armour.
User prompt
first exp upgrade shoudlbe at 3 exp points
User prompt
Make sure lvl is updated in gui when level changes
User prompt
Add transition and animated screen from one level to another. Something like Level complete! and Entering new dungeon! or however feelsbetter. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Level is complete when all monsters are defeated, even if a cell is not uncoveredor chest not opened
User prompt
first level shoudl be easier
User prompt
add 2 more levels that are more difficult and have also new more difficult enemies.
User prompt
add a a chest image
User prompt
only have 3 monsters in level 1
User prompt
add chests in the grid. Just for development purposes always add a chest on the top left cell, will remove it later. when a chest is found, open a screen similar to battle screen, but instead will say, you found a chest, and then add the player on the bottom like in the battle screen and a chest in the center. we will then add a minigame to try open the game. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
After monster attacks, I do not see the attack option on the player
User prompt
In the battle screen, when enemy is destroyed, do not just close screen,but also add a message saying Victroy! or something and then close.
User prompt
Player shoudl start with 1 dmg
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // BattleScreen: Handles the turn-based combat var BattleScreen = Container.expand(function () { var self = Container.call(this); self.visible = false; // Initially hidden self.alpha = 0; // Set alpha to 0 for fade-in animation // Background overlay self.overlay = self.attachAsset('emptyTileCover', { width: 2048, height: 2732, alpha: 0.8 }); // Monster display self.monsterDisplay = self.attachAsset('monsterTileMonster', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 300, // Position near top-right corner within the battle area y: 2732 * 0.2 + 200, // Position near top-right corner within the battle area scaleX: 2, scaleY: 2 }); // Monster stats text self.monsterStatText = new Text2('', { size: 60, fill: "#fff" }); self.monsterStatText.anchor.set(0.5, 0); // Anchor to top-center self.monsterStatText.x = self.monsterDisplay.x; self.monsterStatText.y = self.monsterDisplay.y + self.monsterDisplay.height / 2 + 60; // Move further below monster image self.addChild(self.monsterStatText); // Player stats text (in battle) self.playerBattleStatText = new Text2('', { size: 60, fill: "#fff" }); self.playerDisplay = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5, x: 300, // Position near bottom-left corner within the battle area y: 2732 * 0.8 - 200, // Position near bottom-left corner within the battle area scaleX: 2, scaleY: 2 }); self.playerBattleStatText.anchor.set(0.5, 0); // Anchor to top-center // Set stat text position to where hero will appear self.playerBattleStatText.x = 300; self.playerBattleStatText.y = 2732 * 0.8 - 200 + 100 + 60; // 100 is half hero height at scale 2 self.addChild(self.playerBattleStatText); // Action button (Attack) self.attackBtn = new Text2('ATTACK', { size: 80, fill: "#fff", font: "Impact" }); self.attackBtn.anchor.set(0.5, 0.5); self.attackBtn.x = 2048 / 2; self.attackBtn.y = 2732 - 300; // Position near bottom self.addChild(self.attackBtn); self.attackBtn.down = function () { if (!self.visible) return; self.playerTurn(); }; self.currentMonster = null; // Reference to the monster tile being fought // Start battle self.startBattle = function (monsterTile) { self.currentMonster = monsterTile; self.visible = true; self.alpha = 0; game.addChild(self); // Add battle screen to game // Hide hero/monster and attack button for intro animation self.monsterDisplay.visible = false; self.playerDisplay.visible = false; self.monsterStatText.visible = false; self.playerBattleStatText.visible = false; self.attackBtn.visible = false; // Fade in battle screen tween(self, { alpha: 1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Show "You encountered a monster!" message var encounterText = new Text2('You encountered a monster!', { size: 90, fill: 0xFFE066 }); encounterText.anchor.set(0.5, 0.5); encounterText.x = 2048 / 2; encounterText.y = 2732 / 2 - 200; self.addChild(encounterText); tween(encounterText, { alpha: 0 }, { duration: 900, delay: 900, easing: tween.easeOut, onFinish: function onFinish() { encounterText.destroy(); // Prepare hero/monster offscreen for slide-in // Save original positions var heroTargetX = 300; var heroTargetY = 2732 * 0.8 - 200; var monsterTargetX = 2048 - 300; var monsterTargetY = 2732 * 0.2 + 200; self.playerDisplay.x = -self.playerDisplay.width; // Offscreen left self.playerDisplay.y = heroTargetY; self.monsterDisplay.x = 2048 + self.monsterDisplay.width; // Offscreen right self.monsterDisplay.y = monsterTargetY; self.playerDisplay.visible = true; self.monsterDisplay.visible = true; self.monsterStatText.visible = false; self.playerBattleStatText.visible = false; // Slide in hero and monster simultaneously var slideInCount = 0; function afterSlideIn() { slideInCount++; if (slideInCount === 2) { // Show stats and decide who attacks first self.monsterStatText.visible = true; self.playerBattleStatText.visible = true; self.updateBattleStats(); // Randomize who attacks first: 0 = player, 1 = monster var firstAttacker = Math.random() < 0.5 ? "player" : "monster"; var firstText = firstAttacker === "monster" ? "Monster strikes first!" : "You start!"; var firstTextColor = firstAttacker === "monster" ? 0xff0000 : 0xFFE066; var whoFirstText = new Text2(firstText, { size: 90, fill: firstTextColor }); whoFirstText.anchor.set(0.5, 0.5); whoFirstText.x = 2048 / 2; whoFirstText.y = 2732 / 2; self.addChild(whoFirstText); tween(whoFirstText, { alpha: 0 }, { duration: 900, delay: 900, easing: tween.easeOut, onFinish: function onFinish() { whoFirstText.destroy(); // Show attack button and start the correct turn after a short delay self.attackBtn.visible = true; if (firstAttacker === "monster") { LK.setTimeout(self.monsterTurn, 500); } // If player starts, do nothing: player must press attackBtn } }); } } tween(self.playerDisplay, { x: heroTargetX }, { duration: 600, easing: tween.cubicOut, onFinish: afterSlideIn }); tween(self.monsterDisplay, { x: monsterTargetX }, { duration: 600, easing: tween.cubicOut, onFinish: afterSlideIn }); } }); } }); }; // End battle self.endBattle = function (win) { self.visible = false; self.alpha = 0; // Reset alpha self.attackBtn.visible = false; if (win) { self.currentMonster.defeat(); monstersLeft--; player.gainExp(self.currentMonster.exp); updateGUI(); if (monstersLeft <= 0) { LK.showYouWin(); gameOver = true; } } else { // Player lost, game over is handled in handleTileDown } self.currentMonster = null; self.parent.removeChild(self); // Remove battle screen from game }; // Update battle stats display self.updateBattleStats = function () { if (self.currentMonster) { self.monsterStatText.setText('HP:' + self.currentMonster.hp + '/' + self.currentMonster.maxHp + ' DMG:' + self.currentMonster.damage); self.playerBattleStatText.setText('HP:' + player.hp + '/' + player.maxHp + ' DMG:' + player.damage); } }; // Player's turn self.playerTurn = function () { if (!self.currentMonster) return; // Animate player attack: slide playerDisplay forward, then back, then apply damage var originalX = self.playerDisplay.x; var attackX = originalX + 220; self.attackBtn.visible = false; // Hide attack button during animation // Show "Player Attacks!" text var playerAttackText = new Text2('Player Attacks!', { size: 80, fill: 0xffe066 }); playerAttackText.anchor.set(0.5, 0.5); playerAttackText.x = 2048 / 2; playerAttackText.y = self.monsterStatText.y - 100; self.addChild(playerAttackText); function doAttack() { // Damage and flash self.currentMonster.hp -= player.damage; LK.effects.flashObject(self.monsterDisplay, 0xffe066, 300); // Show animated -X text above monster in battle if (self.currentMonster && self.monsterDisplay) { var monsterDmgText = new Text2('-' + player.damage, { size: 90, fill: 0xff0000 }); monsterDmgText.anchor.set(0.5, 1); // Position above monster sprite monsterDmgText.x = self.monsterDisplay.x; monsterDmgText.y = self.monsterDisplay.y - self.monsterDisplay.height / 2 - 20; self.addChild(monsterDmgText); // Animate: pop up and fade out tween(monsterDmgText, { y: monsterDmgText.y - 80, alpha: 0 }, { duration: 700, easing: tween.cubicOut, onFinish: function onFinish() { monsterDmgText.destroy(); } }); } self.updateBattleStats(); // Fade out attack text tween(playerAttackText, { alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { playerAttackText.destroy(); } }); // If monster dies, animate monster death if (self.currentMonster.hp <= 0) { // Monster death animation: fade out and scale down tween(self.monsterDisplay, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 600, easing: tween.cubicIn, onFinish: function onFinish() { // Show "Victory!" message before closing battle screen var victoryText = new Text2('Victory!', { size: 120, fill: 0xA3E635 }); victoryText.anchor.set(0.5, 0.5); victoryText.x = 2048 / 2; victoryText.y = 2732 / 2; self.addChild(victoryText); victoryText.alpha = 0; // Fade in, hold, then fade out tween(victoryText, { alpha: 1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(victoryText, { alpha: 0 }, { duration: 500, delay: 700, easing: tween.easeIn, onFinish: function onFinish() { victoryText.destroy(); self.endBattle(true); // Player wins // Reset monsterDisplay for next battle self.monsterDisplay.alpha = 1; self.monsterDisplay.scaleX = 2; self.monsterDisplay.scaleY = 2; } }); } }); } }); } else { // Monster survives, monster's turn after a delay LK.setTimeout(self.monsterTurn, 500); self.attackBtn.visible = true; } } // Animate player forward, then back, then do attack tween(self.playerDisplay, { x: attackX }, { duration: 180, easing: tween.cubicOut, onFinish: function onFinish() { tween(self.playerDisplay, { x: originalX }, { duration: 180, easing: tween.cubicIn, onFinish: doAttack }); } }); }; // Monster's turn self.monsterTurn = function () { if (!self.currentMonster) return; // Animate monster attack: slide monsterDisplay forward, then back, then apply damage var originalX = self.monsterDisplay.x; var attackX = originalX - 220; // Slide left toward player self.attackBtn.visible = false; // Hide attack button during animation // Show "Monster Attacks!" text var monsterAttackText = new Text2('Monster Attacks!', { size: 80, fill: 0xff0000 }); monsterAttackText.anchor.set(0.5, 0.5); monsterAttackText.x = 2048 / 2; monsterAttackText.y = self.playerBattleStatText.y + 100; self.addChild(monsterAttackText); function doMonsterAttack() { player.takeDamage(self.currentMonster.damage); // Flash monster and player LK.effects.flashObject(self.monsterDisplay, 0xff0000, 300); // Flash monster indicating it attacked LK.effects.flashObject(self.playerDisplay, 0xff0000, 300); // Flash player sprite LK.effects.flashObject(self.playerBattleStatText, 0xff0000, 300); // Flash player stats indicating damage // Fade out attack text tween(monsterAttackText, { alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { monsterAttackText.destroy(); // Show attack button again if player is still alive and battle is ongoing if (player.hp > 0 && self.currentMonster && !gameOver) { self.attackBtn.visible = true; } } }); self.updateBattleStats(); if (player.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameOver = true; revealAllMonsters(); self.endBattle(false); // Player loses } } // Animate monster forward, then back, then do attack tween(self.monsterDisplay, { x: attackX }, { duration: 180, easing: tween.cubicOut, onFinish: function onFinish() { tween(self.monsterDisplay, { x: originalX }, { duration: 180, easing: tween.cubicIn, onFinish: doMonsterAttack }); } }); }; return self; }); // ChestScreen: Handles the chest found popup var ChestScreen = Container.expand(function () { var self = Container.call(this); self.visible = false; self.alpha = 0; // Background overlay self.overlay = self.attachAsset('emptyTileCover', { width: 2048, height: 2732, alpha: 0.8 }); // Chest display (center) self.chestDisplay = self.attachAsset('emptyTileBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 100, scaleX: 2, scaleY: 2, color: 0xFFD700 // gold for dev }); // "You found a chest!" text self.chestText = new Text2('You found a chest!', { size: 90, fill: 0xFFD700 }); self.chestText.anchor.set(0.5, 0.5); self.chestText.x = 2048 / 2; self.chestText.y = 2732 / 2 - 350; self.addChild(self.chestText); // Player display (bottom, like battle screen) self.playerDisplay = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 * 0.8, scaleX: 2, scaleY: 2 }); // Start chest screen self.startChest = function (chestTile) { self.currentChest = chestTile; self.visible = true; self.alpha = 0; game.addChild(self); // Fade in tween(self, { alpha: 1 }, { duration: 300, easing: tween.easeOut }); }; // End chest screen self.endChest = function () { self.visible = false; self.alpha = 0; self.currentChest = null; if (self.parent) self.parent.removeChild(self); }; return self; }); // ChestTile: Represents a chest hidden under a tile var ChestTile = Container.expand(function () { var self = Container.call(this); self.revealed = false; self.opened = false; self.cover = self.attachAsset('emptyTileCover', { anchorX: 0.5, anchorY: 0.5 }); // Use a chest image asset (use a box for now, engine will replace with chest art) self.chest = self.attachAsset('emptyTileBg', { anchorX: 0.5, anchorY: 0.5, color: 0xFFD700, // gold color for dev alpha: 0 // Hidden until revealed }); // Reveal the chest self.reveal = function () { if (self.revealed) return; self.revealed = true; self.cover.alpha = 0.2; self.chest.alpha = 1; }; // Mark as opened self.open = function () { self.opened = true; // Optionally animate chest opening here }; return self; }); // EmptyTile: Represents a safe tile (no monster) var EmptyTile = Container.expand(function () { var self = Container.call(this); self.revealed = false; self.adjacentMonsters = 0; self.cover = self.attachAsset('emptyTileCover', { anchorX: 0.5, anchorY: 0.5 }); self.bg = self.attachAsset('emptyTileBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Hidden until revealed }); self.adjText = new Text2('', { size: 48, fill: "#fff" }); self.adjText.anchor.set(0.5, 0.5); self.adjText.alpha = 0; self.addChild(self.adjText); self.reveal = function () { if (self.revealed) return; self.revealed = true; self.cover.alpha = 0.2; self.bg.alpha = 1; if (self.adjacentMonsters > 0) { self.adjText.setText(self.adjacentMonsters + ''); self.adjText.alpha = 1; } }; return self; }); // MonsterTile: Represents a monster hidden under a tile var MonsterTile = Container.expand(function () { var self = Container.call(this); // Monster stats self.hp = 1; self.maxHp = 1; self.damage = 1; self.exp = 1; self.revealed = false; self.defeated = false; // Visuals self.cover = self.attachAsset('monsterTileCover', { anchorX: 0.5, anchorY: 0.5 }); self.monster = self.attachAsset('monsterTileMonster', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Hidden until revealed }); // Show monster stats as text (hidden until revealed) self.statText = new Text2('', { size: 48, fill: "#fff" }); self.statText.anchor.set(0.5, 0.5); self.statText.alpha = 0; self.addChild(self.statText); // Reveal the monster self.reveal = function () { if (self.revealed) return; self.revealed = true; self.cover.alpha = 0.2; self.monster.alpha = 1; self.statText.setText(''); self.statText.alpha = 0; }; // Mark as defeated self.defeat = function () { self.defeated = true; self.monster.alpha = 0.3; self.cover.alpha = 0.1; self.statText.setText(''); self.statText.alpha = 0; }; return self; }); // Player: Holds player stats and methods var Player = Container.expand(function () { var self = Container.call(this); self.maxHp = 10; self.hp = 10; self.damage = 1; self.exp = 0; self.level = 1; self.expToLevel = 5; // Level up: spend exp to increase stats or heal self.levelUp = function (choice) { if (self.exp < self.expToLevel) return false; self.exp -= self.expToLevel; self.level += 1; self.expToLevel = Math.floor(self.expToLevel * 1.5); if (choice === 'hp') { self.maxHp += 3; self.hp = self.maxHp; } else if (choice === 'damage') { self.damage += 1; } else if (choice === 'heal') { self.hp = self.maxHp; } return true; }; // Take damage self.takeDamage = function (amount) { self.hp -= amount; if (self.hp < 0) self.hp = 0; // Show animated -X text above player in battle if (battleScreen && battleScreen.visible && battleScreen.playerDisplay) { var dmgText = new Text2('-' + amount, { size: 90, fill: 0xff0000 }); dmgText.anchor.set(0.5, 1); // Position above player sprite dmgText.x = battleScreen.playerDisplay.x; dmgText.y = battleScreen.playerDisplay.y - battleScreen.playerDisplay.height / 2 - 20; battleScreen.addChild(dmgText); // Animate: pop up and fade out tween(dmgText, { y: dmgText.y - 80, alpha: 0 }, { duration: 700, easing: tween.cubicOut, onFinish: function onFinish() { dmgText.destroy(); } }); } }; // Gain exp self.gainExp = function (amount) { self.exp += amount; }; // Heal self.heal = function (amount) { self.hp += amount; if (self.hp > self.maxHp) self.hp = self.maxHp; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x22223a }); /**** * Game Code ****/ // --- Game Constants --- function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } var GRID_COLS = 8; var GRID_ROWS = 8; var TILE_SIZE = 180; var GRID_OFFSET_X = Math.floor((2048 - GRID_COLS * TILE_SIZE) / 2); var GRID_OFFSET_Y = Math.floor(2732 * 0.2 + (2732 * 0.6 - GRID_ROWS * TILE_SIZE) / 2); // Center the grid vertically within the middle 60% var MONSTER_COUNT = 12; // --- Asset Initialization --- // --- Game State --- var player = new Player(); var grid = []; // 2D array [row][col] var tileObjs = []; // Flat array of all tile objects for easy iteration var monstersLeft = MONSTER_COUNT; var revealedTiles = 0; var totalSafeTiles = GRID_COLS * GRID_ROWS - MONSTER_COUNT; var gameOver = false; var battleScreen = new BattleScreen(); var chestScreen = new ChestScreen(); // --- GUI Elements --- var hpText = new Text2('', { size: 40, fill: 0xFF6666 }); hpText.anchor.set(0.5, 1); // Anchor to bottom-center LK.gui.bottom.addChild(hpText); var dmgText = new Text2('', { size: 40, fill: "#fff" }); dmgText.anchor.set(0.5, 1); // Anchor to bottom-center LK.gui.bottom.addChild(dmgText); var expText = new Text2('', { size: 40, fill: 0xFFE066 }); expText.anchor.set(0.5, 1); // Anchor to bottom-center LK.gui.bottom.addChild(expText); var levelText = new Text2('', { size: 40, fill: 0xA3E635 }); levelText.anchor.set(0, 0.5); // Anchor to left-middle LK.gui.top.addChild(levelText); var monstersLeftText = new Text2('', { size: 40, fill: "#fff" }); monstersLeftText.anchor.set(0, 0.5); // Anchor to left-middle LK.gui.top.addChild(monstersLeftText); var levelUpBtn = new Text2('LEVEL UP', { size: 70, fill: "#fff", font: "Impact" }); levelUpBtn.anchor.set(0.5, 0.5); levelUpBtn.alpha = 0.7; levelUpBtn.visible = false; levelUpBtn.down = function () { if (!this.visible) return; showLevelUpChoices(); }; LK.gui.top.addChild(levelUpBtn); var levelUpChoiceBtns = []; var levelUpChoices = [{ label: "Max HP +3 & Heal", value: "hp" }, { label: "Damage +1", value: "damage" }, { label: "Heal to Max", value: "heal" }]; for (var i = 0; i < levelUpChoices.length; i++) { var btn = new Text2(levelUpChoices[i].label, { size: 60, fill: "#fff", font: "Impact" }); btn.anchor.set(0.5, 0.5); btn.visible = false; btn.alpha = 0.9; // Capture the current choice for this button's event handler var currentChoice = levelUpChoices[i]; btn.down = function () { if (!this.visible) return; player.levelUp(currentChoice.value); hideLevelUpChoices(); updateGUI(); // If player still has enough EXP, show the level up button again if (!gameOver && player.exp >= player.expToLevel) { levelUpBtn.visible = true; levelUpBtn.alpha = 1; } }; LK.gui.bottom.addChild(btn); levelUpChoiceBtns.push(btn); } // --- Helper Functions --- function updateGUI() { if (battleScreen.visible) { hpText.visible = false; dmgText.visible = false; expText.visible = false; levelText.visible = false; monstersLeftText.visible = false; levelUpBtn.visible = false; for (var i = 0; i < levelUpChoiceBtns.length; i++) { levelUpChoiceBtns[i].visible = false; } battleScreen.updateBattleStats(); // Update battle screen stats when visible return; } else { hpText.visible = true; dmgText.visible = true; expText.visible = true; levelText.visible = true; monstersLeftText.visible = true; } hpText.setText('HP: ' + player.hp + '/' + player.maxHp); hpText.x = -200; // Position to the left of center hpText.y = -40; // Position near the bottom edge dmgText.setText('DMG: ' + player.damage); dmgText.x = 0; // Center horizontally dmgText.y = -40; // Position near the bottom edge expText.setText('EXP: ' + player.exp + '/' + player.expToLevel); expText.x = 200; // Position to the right of center expText.y = -40; // Position near the bottom edge // Position levelText and monstersLeftText side-by-side at the top-center, accounting for 100x100 top-left area levelText.setText('LVL: ' + player.level); levelText.x = -100; // Position to the left of center (adjusted for safe area) levelText.y = 60; // Position near the top edge monstersLeftText.setText('Monsters: ' + monstersLeft); monstersLeftText.x = 100; // Position to the right of center monstersLeftText.y = 60; // Position near the top edge // Show level up button if enough exp if (!gameOver && player.exp >= player.expToLevel && !levelUpChoiceBtns.some(function (btn) { return btn.visible; })) { levelUpBtn.visible = true; levelUpBtn.alpha = 1; } else { levelUpBtn.visible = false; } } // Returns true if (row, col) is inside grid function inBounds(row, col) { return row >= 0 && row < GRID_ROWS && col >= 0 && col < GRID_COLS; } // Get all adjacent tile positions function getAdjacent(row, col) { var adj = []; for (var dr = -1; dr <= 1; dr++) { for (var dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; var nr = row + dr, nc = col + dc; if (inBounds(nr, nc)) adj.push([nr, nc]); } } return adj; } // Reveal empty tiles recursively (flood fill) function revealEmptyTiles(row, col) { var tile = grid[row][col]; if (tile.revealed) return; tile.reveal(); revealedTiles++; if (tile.adjacentMonsters === 0) { var adj = getAdjacent(row, col); for (var i = 0; i < adj.length; i++) { var _adj$i = _slicedToArray(adj[i], 2), nr = _adj$i[0], nc = _adj$i[1]; var t = grid[nr][nc]; if (t instanceof EmptyTile && !t.revealed) { revealEmptyTiles(nr, nc); } } } } // Reveal all monsters (on game over) function revealAllMonsters() { for (var i = 0; i < tileObjs.length; i++) { var t = tileObjs[i]; if (t instanceof MonsterTile && !t.revealed) { t.reveal(); } } } // --- Board Generation --- function generateBoard() { // Clear previous for (var i = 0; i < tileObjs.length; i++) { tileObjs[i].destroy(); } grid = []; tileObjs = []; monstersLeft = MONSTER_COUNT; revealedTiles = 0; totalSafeTiles = GRID_COLS * GRID_ROWS - MONSTER_COUNT; gameOver = false; // Place monsters var monsterPositions = []; while (monsterPositions.length < MONSTER_COUNT) { var r = Math.floor(Math.random() * GRID_ROWS); var c = Math.floor(Math.random() * GRID_COLS); var key = r + ',' + c; var found = false; for (var i = 0; i < monsterPositions.length; i++) { if (monsterPositions[i][0] === r && monsterPositions[i][1] === c) { found = true; break; } } if (!found) monsterPositions.push([r, c]); } // Build grid for (var row = 0; row < GRID_ROWS; row++) { grid[row] = []; for (var col = 0; col < GRID_COLS; col++) { var isMonster = false; for (var i = 0; i < monsterPositions.length; i++) { if (monsterPositions[i][0] === row && monsterPositions[i][1] === col) { isMonster = true; break; } } var tile; // Always place a chest at (0,0) for dev if (row === 0 && col === 0) { tile = new ChestTile(); } else if (isMonster) { tile = new MonsterTile(); // Randomize monster stats a bit tile.maxHp = tile.hp = 1 + Math.floor(Math.random() * (1 + player.level)); tile.damage = 1 + Math.floor(Math.random() * (1 + Math.floor(player.level / 2))); tile.exp = 1 + Math.floor(Math.random() * 2); } else { tile = new EmptyTile(); } tile.x = GRID_OFFSET_X + col * TILE_SIZE + TILE_SIZE / 2; tile.y = GRID_OFFSET_Y + row * TILE_SIZE + TILE_SIZE / 2; game.addChild(tile); grid[row][col] = tile; tileObjs.push(tile); } } // Set adjacent monster counts for empty tiles for (var row = 0; row < GRID_ROWS; row++) { for (var col = 0; col < GRID_COLS; col++) { var tile = grid[row][col]; if (tile instanceof EmptyTile) { var adj = getAdjacent(row, col); var count = 0; for (var i = 0; i < adj.length; i++) { var _adj$i2 = _slicedToArray(adj[i], 2), nr = _adj$i2[0], nc = _adj$i2[1]; if (grid[nr][nc] instanceof MonsterTile) count++; } tile.adjacentMonsters = count; } } } } // --- Game Logic --- function handleTileDown(x, y, obj) { if (gameOver) return; if (battleScreen.visible) return; // Don't allow tile interaction if battle screen is up // Find which tile was pressed for (var i = 0; i < tileObjs.length; i++) { var tile = tileObjs[i]; if (tile.revealed) continue; if (tile.cover && tile.cover.alpha > 0.1) { // Check if (x, y) is inside tile var dx = x - tile.x; var dy = y - tile.y; if (Math.abs(dx) < TILE_SIZE / 2 && Math.abs(dy) < TILE_SIZE / 2) { // Reveal tile if (tile instanceof EmptyTile) { revealEmptyTiles(Math.floor((tile.y - GRID_OFFSET_Y) / TILE_SIZE), Math.floor((tile.x - GRID_OFFSET_X) / TILE_SIZE)); updateGUI(); // Win check if (revealedTiles >= totalSafeTiles) { LK.showYouWin(); gameOver = true; revealAllMonsters(); } } else if (tile instanceof ChestTile) { // Reveal chest and show chest screen tile.reveal(); chestScreen.startChest(tile); } else if (tile instanceof MonsterTile) { // Reveal monster and start battle tile.reveal(); // Reveal the monster visually // Start the battle sequence battleScreen.startBattle(tile); } break; } } } } // --- Level Up UI --- function showLevelUpChoices() { levelUpBtn.visible = false; for (var i = 0; i < levelUpChoiceBtns.length; i++) { var btn = levelUpChoiceBtns[i]; btn.visible = true; btn.x = (i - 1) * 400; // x relative to LK.gui.bottom (which is screen center horizontally) btn.y = -2732 * 0.15; // Position choices above the bottom boundary of the battle area btn.alpha = 1; } } function hideLevelUpChoices() { for (var i = 0; i < levelUpChoiceBtns.length; i++) { levelUpChoiceBtns[i].visible = false; } } // --- Event Handlers --- game.down = function (x, y, obj) { // The click handling for levelUpBtn and levelUpChoiceBtns // has been moved to their own 'down' event handlers. // Check for tile interactions handleTileDown(x, y, obj); }; game.update = function () { if (battleScreen.visible) return; // Don't update game elements when battle screen is up // Animate level up button if (levelUpBtn.visible) { levelUpBtn.x = 0; // Centered horizontally relative to LK.gui.top levelUpBtn.y = 120; levelUpBtn.alpha = 0.8 + 0.2 * Math.sin(LK.ticks / 20); } // Animate level up choices for (var i = 0; i < levelUpChoiceBtns.length; i++) { var btn = levelUpChoiceBtns[i]; if (btn.visible) { btn.x = (i - 1) * 400; // x relative to LK.gui.bottom btn.y = -2732 * 0.15; // Position choices above the bottom boundary of the battle area btn.alpha = 0.9 + 0.1 * Math.sin(LK.ticks / 15 + i); } } if (battleScreen.visible || chestScreen && chestScreen.visible) { for (var i = 0; i < tileObjs.length; i++) { tileObjs[i].visible = false; } } else { for (var i = 0; i < tileObjs.length; i++) { tileObjs[i].visible = true; } } }; // --- Start Game --- generateBoard(); updateGUI();
===================================================================
--- original.js
+++ change.js
@@ -394,8 +394,101 @@
});
};
return self;
});
+// ChestScreen: Handles the chest found popup
+var ChestScreen = Container.expand(function () {
+ var self = Container.call(this);
+ self.visible = false;
+ self.alpha = 0;
+ // Background overlay
+ self.overlay = self.attachAsset('emptyTileCover', {
+ width: 2048,
+ height: 2732,
+ alpha: 0.8
+ });
+ // Chest display (center)
+ self.chestDisplay = self.attachAsset('emptyTileBg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2 - 100,
+ scaleX: 2,
+ scaleY: 2,
+ color: 0xFFD700 // gold for dev
+ });
+ // "You found a chest!" text
+ self.chestText = new Text2('You found a chest!', {
+ size: 90,
+ fill: 0xFFD700
+ });
+ self.chestText.anchor.set(0.5, 0.5);
+ self.chestText.x = 2048 / 2;
+ self.chestText.y = 2732 / 2 - 350;
+ self.addChild(self.chestText);
+ // Player display (bottom, like battle screen)
+ self.playerDisplay = self.attachAsset('character', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 * 0.8,
+ scaleX: 2,
+ scaleY: 2
+ });
+ // Start chest screen
+ self.startChest = function (chestTile) {
+ self.currentChest = chestTile;
+ self.visible = true;
+ self.alpha = 0;
+ game.addChild(self);
+ // Fade in
+ tween(self, {
+ alpha: 1
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ };
+ // End chest screen
+ self.endChest = function () {
+ self.visible = false;
+ self.alpha = 0;
+ self.currentChest = null;
+ if (self.parent) self.parent.removeChild(self);
+ };
+ return self;
+});
+// ChestTile: Represents a chest hidden under a tile
+var ChestTile = Container.expand(function () {
+ var self = Container.call(this);
+ self.revealed = false;
+ self.opened = false;
+ self.cover = self.attachAsset('emptyTileCover', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Use a chest image asset (use a box for now, engine will replace with chest art)
+ self.chest = self.attachAsset('emptyTileBg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ color: 0xFFD700,
+ // gold color for dev
+ alpha: 0 // Hidden until revealed
+ });
+ // Reveal the chest
+ self.reveal = function () {
+ if (self.revealed) return;
+ self.revealed = true;
+ self.cover.alpha = 0.2;
+ self.chest.alpha = 1;
+ };
+ // Mark as opened
+ self.open = function () {
+ self.opened = true;
+ // Optionally animate chest opening here
+ };
+ return self;
+});
// EmptyTile: Represents a safe tile (no monster)
var EmptyTile = Container.expand(function () {
var self = Container.call(this);
self.revealed = false;
@@ -614,8 +707,9 @@
var revealedTiles = 0;
var totalSafeTiles = GRID_COLS * GRID_ROWS - MONSTER_COUNT;
var gameOver = false;
var battleScreen = new BattleScreen();
+var chestScreen = new ChestScreen();
// --- GUI Elements ---
var hpText = new Text2('', {
size: 40,
fill: 0xFF6666
@@ -825,9 +919,12 @@
break;
}
}
var tile;
- if (isMonster) {
+ // Always place a chest at (0,0) for dev
+ if (row === 0 && col === 0) {
+ tile = new ChestTile();
+ } else if (isMonster) {
tile = new MonsterTile();
// Randomize monster stats a bit
tile.maxHp = tile.hp = 1 + Math.floor(Math.random() * (1 + player.level));
tile.damage = 1 + Math.floor(Math.random() * (1 + Math.floor(player.level / 2)));
@@ -882,8 +979,12 @@
LK.showYouWin();
gameOver = true;
revealAllMonsters();
}
+ } else if (tile instanceof ChestTile) {
+ // Reveal chest and show chest screen
+ tile.reveal();
+ chestScreen.startChest(tile);
} else if (tile instanceof MonsterTile) {
// Reveal monster and start battle
tile.reveal(); // Reveal the monster visually
// Start the battle sequence
@@ -933,9 +1034,9 @@
btn.y = -2732 * 0.15; // Position choices above the bottom boundary of the battle area
btn.alpha = 0.9 + 0.1 * Math.sin(LK.ticks / 15 + i);
}
}
- if (battleScreen.visible) {
+ if (battleScreen.visible || chestScreen && chestScreen.visible) {
for (var i = 0; i < tileObjs.length; i++) {
tileObjs[i].visible = false;
}
} else {