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) { // If not last level, advance to next level if (currentLevel < LEVELS.length - 1) { // Animated level transition screen var transitionContainer = new Container(); transitionContainer.alpha = 0; // Overlay var overlay = LK.getAsset('emptyTileCover', { width: 2048, height: 2732, alpha: 0.92, anchorX: 0, anchorY: 0 }); transitionContainer.addChild(overlay); // "Level Complete!" text var completeText = new Text2('Level Complete!', { size: 120, fill: 0xA3E635 }); completeText.anchor.set(0.5, 0.5); completeText.x = 2048 / 2; completeText.y = 2732 / 2 - 200; transitionContainer.addChild(completeText); // "Entering new dungeon!" text var enteringText = new Text2('Entering new dungeon...', { size: 90, fill: 0xFFE066 }); enteringText.anchor.set(0.5, 0.5); enteringText.x = 2048 / 2; enteringText.y = 2732 / 2 + 100; enteringText.alpha = 0; transitionContainer.addChild(enteringText); // "Level X" text var nextLevelText = new Text2('Level ' + (currentLevel + 2) + '!', { size: 100, fill: 0xA3E635 }); nextLevelText.anchor.set(0.5, 0.5); nextLevelText.x = 2048 / 2; nextLevelText.y = 2732 / 2 + 300; nextLevelText.alpha = 0; transitionContainer.addChild(nextLevelText); game.addChild(transitionContainer); // Fade in overlay and "Level Complete!" tween(transitionContainer, { alpha: 1 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Fade in "Entering new dungeon..." tween(enteringText, { alpha: 1 }, { duration: 400, delay: 200, easing: tween.easeIn, onFinish: function onFinish() { // Fade in "Level X" tween(nextLevelText, { alpha: 1 }, { duration: 400, delay: 200, easing: tween.easeIn, onFinish: function onFinish() { // Hold, then fade out all tween(transitionContainer, { alpha: 0 }, { duration: 600, delay: 900, easing: tween.easeIn, onFinish: function onFinish() { transitionContainer.destroy(); // Advance to next level currentLevel++; MONSTER_COUNT = LEVELS[currentLevel].monsters; generateBoard(); updateGUI(); } }); } }); } }); } }); gameOver = false; } else { 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) - use chest image asset self.chestDisplay = self.attachAsset('chest', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 100, scaleX: 2, scaleY: 2 }); // "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 self.chest = self.attachAsset('chest', { anchorX: 0.5, anchorY: 0.5, 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% // --- Level System --- var LEVELS = [{ monsters: 3, monsterStats: { minHp: 1, maxHp: 2, minDmg: 1, maxDmg: 1, minExp: 1, maxExp: 1 } }, { monsters: 5, monsterStats: { minHp: 3, maxHp: 5, minDmg: 2, maxDmg: 3, minExp: 2, maxExp: 3 } }, { monsters: 7, monsterStats: { minHp: 5, maxHp: 8, minDmg: 3, maxDmg: 5, minExp: 3, maxExp: 4 } }]; var currentLevel = 0; var MONSTER_COUNT = LEVELS[currentLevel].monsters; // --- 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 = LEVELS[currentLevel].monsters; revealedTiles = 0; totalSafeTiles = GRID_COLS * GRID_ROWS - LEVELS[currentLevel].monsters; gameOver = false; // Place monsters var monsterPositions = []; while (monsterPositions.length < LEVELS[currentLevel].monsters) { 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 var stats = LEVELS[currentLevel].monsterStats; 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(); // Level-based monster stats tile.maxHp = tile.hp = stats.minHp + Math.floor(Math.random() * (stats.maxHp - stats.minHp + 1)); tile.damage = stats.minDmg + Math.floor(Math.random() * (stats.maxDmg - stats.minDmg + 1)); tile.exp = stats.minExp + Math.floor(Math.random() * (stats.maxExp - stats.minExp + 1)); } 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 // (Removed: revealing all safe tiles no longer triggers win. Level is won only when all monsters are defeated.) } 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
@@ -192,36 +192,91 @@
updateGUI();
if (monstersLeft <= 0) {
// If not last level, advance to next level
if (currentLevel < LEVELS.length - 1) {
- var nextLevelText = new Text2('Level ' + (currentLevel + 2) + '!', {
+ // Animated level transition screen
+ var transitionContainer = new Container();
+ transitionContainer.alpha = 0;
+ // Overlay
+ var overlay = LK.getAsset('emptyTileCover', {
+ width: 2048,
+ height: 2732,
+ alpha: 0.92,
+ anchorX: 0,
+ anchorY: 0
+ });
+ transitionContainer.addChild(overlay);
+ // "Level Complete!" text
+ var completeText = new Text2('Level Complete!', {
size: 120,
fill: 0xA3E635
});
+ completeText.anchor.set(0.5, 0.5);
+ completeText.x = 2048 / 2;
+ completeText.y = 2732 / 2 - 200;
+ transitionContainer.addChild(completeText);
+ // "Entering new dungeon!" text
+ var enteringText = new Text2('Entering new dungeon...', {
+ size: 90,
+ fill: 0xFFE066
+ });
+ enteringText.anchor.set(0.5, 0.5);
+ enteringText.x = 2048 / 2;
+ enteringText.y = 2732 / 2 + 100;
+ enteringText.alpha = 0;
+ transitionContainer.addChild(enteringText);
+ // "Level X" text
+ var nextLevelText = new Text2('Level ' + (currentLevel + 2) + '!', {
+ size: 100,
+ fill: 0xA3E635
+ });
nextLevelText.anchor.set(0.5, 0.5);
nextLevelText.x = 2048 / 2;
- nextLevelText.y = 2732 / 2;
- self.addChild(nextLevelText);
+ nextLevelText.y = 2732 / 2 + 300;
nextLevelText.alpha = 0;
- tween(nextLevelText, {
+ transitionContainer.addChild(nextLevelText);
+ game.addChild(transitionContainer);
+ // Fade in overlay and "Level Complete!"
+ tween(transitionContainer, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
- tween(nextLevelText, {
- alpha: 0
+ // Fade in "Entering new dungeon..."
+ tween(enteringText, {
+ alpha: 1
}, {
- duration: 500,
- delay: 900,
+ duration: 400,
+ delay: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
- nextLevelText.destroy();
- // Advance to next level
- currentLevel++;
- MONSTER_COUNT = LEVELS[currentLevel].monsters;
- generateBoard();
- updateGUI();
+ // Fade in "Level X"
+ tween(nextLevelText, {
+ alpha: 1
+ }, {
+ duration: 400,
+ delay: 200,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ // Hold, then fade out all
+ tween(transitionContainer, {
+ alpha: 0
+ }, {
+ duration: 600,
+ delay: 900,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ transitionContainer.destroy();
+ // Advance to next level
+ currentLevel++;
+ MONSTER_COUNT = LEVELS[currentLevel].monsters;
+ generateBoard();
+ updateGUI();
+ }
+ });
+ }
+ });
}
});
}
});