User prompt
when every card play by player play the sound effect
User prompt
assign boss asset to the last enemy (boss)
User prompt
there is no boss asset in assets make one
User prompt
make boss a different enemy
User prompt
sometimes when i end turn cards disappear make fresh card deck when end turn now there is no card left
User prompt
make end turn text black
User prompt
make end turn button background as asset
User prompt
make end turn button visual to end turn text
User prompt
defend cards should be dragged to the player not the enemy.
User prompt
make card titles white
User prompt
allign card texts under the card
User prompt
make player bigger
User prompt
make enemies as the same height as player horizontally same level
User prompt
No. It shouldn't be the defend asset. Add background asset so i can change it
User prompt
add background asset. It is the same with defend asset now.
User prompt
Player health should be under the character
User prompt
Add background to the maps and also to the map. Boss should be seperate background. And also can you explain cards (card texts) under cards. and make it white text
User prompt
still. There is no information about players' stamina. Add text for player stamina above player or above cards. And also enemy says it would attack with 6 but it only attacks 1. Also there is no Block text under player
User prompt
Please fix the bug: 'Uncaught TypeError: guiStaminaTxt.setText is not a function' in or related to this line: 'guiStaminaTxt.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina);' Line Number: 664
User prompt
still there is no information about players' stamina. And also end turn button should be little more above. Now it blends with cards.
User prompt
add stamina gui to see stamina. when stamina finishes player shouldn't be able to play any cards and add a button above the cards to end turn. When player clicks to end turn now its enemies turn
User prompt
Please fix the bug: 'Uncaught ReferenceError: enemyData is not defined' in or related to this line: 'enemyNode.setIntent(enemyData.intent);' Line Number: 551
User prompt
enemy attacks are not taking the players health down. And we can add more visiual to the game player can be on the left as a sprite. And background will be a cave. And the enemy can be on the right. (sometimes there are multiple enemies and player has to drag card to choose enemy to attack). Also there should be a stamina and every card has a stamina cost so the player sometimes can't play all cards in hand. Every cave the player can choose stamina upgrade or a new card
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(enemyTurn, 500);' Line Number: 681
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Card class var Card = Container.expand(function () { var self = Container.call(this); // Card data: {type, name, desc, damage, block, special} self.cardData = null; // Card background var cardBg = null; // Card text var nameTxt = null; var descTxt = null; // Set card data and visuals self.setCard = function (cardData) { self.cardData = cardData; if (cardBg) cardBg.destroy(); if (nameTxt) nameTxt.destroy(); if (descTxt) descTxt.destroy(); if (self.staminaTxt) { self.staminaTxt.destroy(); self.staminaTxt = null; } var assetId = 'card'; if (cardData.type === 'attack') assetId = 'cardAttack';else if (cardData.type === 'defend') assetId = 'cardDefend';else if (cardData.type === 'special') assetId = 'cardSpecial'; cardBg = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); nameTxt = new Text2(cardData.name, { size: 48, fill: '#222222' }); nameTxt.anchor.set(0.5, 0); nameTxt.x = 0; nameTxt.y = -180; self.addChild(nameTxt); // Card description text (explains what the card does, e.g. "Deal 6 damage", "Gain 5 block") // This text is shown under the card image, centered, and uses white color for clarity descTxt = new Text2(cardData.desc, { size: 32, fill: '#ffffff' }); descTxt.anchor.set(0.5, 0); descTxt.x = 0; descTxt.y = -100; self.addChild(descTxt); // Show stamina cost var cost = cardData.stamina || 1; self.staminaTxt = new Text2(cost + '', { size: 48, fill: '#ffaa00' }); self.staminaTxt.anchor.set(0.5, 0.5); self.staminaTxt.x = 0; self.staminaTxt.y = 160; self.addChild(self.staminaTxt); }; // Highlight for selection self.setSelected = function (selected) { if (cardBg) { cardBg.alpha = selected ? 1 : 0.85; cardBg.scaleX = cardBg.scaleY = selected ? 1.08 : 1; } }; // For drag/press self.down = function (x, y, obj) { if (self.onCardDown) self.onCardDown(self, x, y, obj); }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); self.maxHp = 1; self.hp = 1; self.intent = null; // {type, value} self.enemyData = null; var enemyShape = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); var hpTxt = new Text2('', { size: 48, fill: '#ffffff' }); hpTxt.anchor.set(0.5, 0.5); hpTxt.x = 0; hpTxt.y = 0; self.addChild(hpTxt); var intentTxt = new Text2('', { size: 36, fill: '#ffcc00' }); intentTxt.anchor.set(0.5, 0); intentTxt.x = 0; intentTxt.y = 120; self.addChild(intentTxt); self.setEnemy = function (enemyData) { self.enemyData = enemyData; self.maxHp = enemyData.hp; self.hp = enemyData.hp; self.updateHp(); self.setIntent(enemyData.intent); }; self.setIntent = function (intent) { self.intent = intent; if (intent && intent.type === 'attack') { intentTxt.setText('Attack\n' + intent.value); } else if (intent && intent.type === 'block') { intentTxt.setText('Block\n' + intent.value); } else { intentTxt.setText(''); } }; self.updateHp = function () { hpTxt.setText(self.hp + ' / ' + self.maxHp); }; return self; }); // MapNode class var MapNode = Container.expand(function () { var self = Container.call(this); self.nodeType = 'normal'; // 'normal', 'boss' self.nodeIndex = 0; self.isCurrent = false; self.isVisited = false; var nodeShape = null; var nodeTxt = null; self.setNode = function (type, isCurrent, isBoss) { self.nodeType = type; self.isCurrent = isCurrent; if (nodeShape) nodeShape.destroy(); if (nodeTxt) nodeTxt.destroy(); var assetId = isBoss ? 'mapNodeBoss' : isCurrent ? 'mapNodeCurrent' : 'mapNode'; nodeShape = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); nodeTxt = new Text2(isBoss ? 'B' : '', { size: 64, fill: '#222222' }); nodeTxt.anchor.set(0.5, 0.5); nodeTxt.x = 0; nodeTxt.y = 0; self.addChild(nodeTxt); }; // For tap self.down = function (x, y, obj) { if (self.onNodeDown) self.onNodeDown(self, x, y, obj); }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); self.maxHp = 30; self.hp = 30; self.block = 0; var playerShape = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); var hpTxt = new Text2('', { size: 48, fill: '#222222' }); hpTxt.anchor.set(0.5, 0.5); hpTxt.x = 0; hpTxt.y = 0; self.addChild(hpTxt); var blockTxt = new Text2('', { size: 36, fill: '#55aaff' }); blockTxt.anchor.set(0.5, 0); blockTxt.x = 0; blockTxt.y = 120; self.addChild(blockTxt); self.updateStats = function () { hpTxt.setText(self.hp + ' / ' + self.maxHp); blockTxt.setText('Block: ' + self.block); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // --- Card Data --- // Card shapes (rectangles for cards) var CARD_LIBRARY = [{ type: 'attack', name: 'Strike', desc: 'Deal 6 damage.', damage: 6, stamina: 1 }, { type: 'defend', name: 'Defend', desc: 'Gain 5 block.', block: 5, stamina: 1 }, { type: 'attack', name: 'Slash', desc: 'Deal 8 damage.', damage: 8, stamina: 2 }, { type: 'defend', name: 'Guard', desc: 'Gain 7 block.', block: 7, stamina: 2 }, { type: 'special', name: 'Heal', desc: 'Heal 4 HP.', special: 'heal', value: 4, stamina: 2 }, { type: 'special', name: 'Double Strike', desc: 'Deal 4 damage twice.', special: 'double', value: 4, stamina: 2 }, { type: 'special', name: 'Bash', desc: 'Deal 10 damage. Next attack +3.', special: 'bash', value: 10, stamina: 2 }]; // --- Enemy Data --- var ENEMY_LIBRARY = [{ name: 'Goblin', hp: 18, intent: { type: 'attack', value: 5 } }, { name: 'Slime', hp: 22, intent: { type: 'block', value: 6 } }, { name: 'Orc', hp: 28, intent: { type: 'attack', value: 8 } }, { name: 'Boss', hp: 40, intent: { type: 'attack', value: 12 } }]; // --- Game State --- var player = null; var enemy = null; var hand = []; var deck = []; var discard = []; var drawPile = []; var selectedCard = null; var cardNodes = []; var enemyNode = null; var playerNode = null; var mapNodes = []; var mapPaths = []; var currentMapIndex = 0; var mapData = []; var inBattle = false; var battleResult = null; // null, 'win', 'lose' var rewardCards = []; var rewardCardNodes = []; var rewardTxt = null; var dragCard = null; var dragStart = null; var dragValid = false; var guiHpTxt = null; var guiEnemyHpTxt = null; var guiFloorTxt = null; var guiBlockTxt = null; var guiEnemyIntentTxt = null; var guiMapGroup = null; var guiHandGroup = null; var guiBattleGroup = null; var guiRewardGroup = null; var guiStaminaTxt = null; var floorNum = 1; var maxFloors = 8; // Stamina system var playerStamina = 3; var playerMaxStamina = 3; // --- Utility Functions --- function shuffleArray(arr) { for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = arr[i]; arr[i] = arr[j]; arr[j] = t; } } function cloneCard(card) { var c = {}; for (var k in card) c[k] = card[k]; return c; } function getRandomCard() { var idx = Math.floor(Math.random() * CARD_LIBRARY.length); return cloneCard(CARD_LIBRARY[idx]); } function getRandomEnemy(isBoss) { if (isBoss) return ENEMY_LIBRARY[3]; var idx = Math.floor(Math.random() * 3); return ENEMY_LIBRARY[idx]; } // --- Map Generation --- function generateMap() { // Simple linear with 2-branch at each node, boss at end mapData = []; for (var i = 0; i < maxFloors - 1; ++i) { var node = { type: 'normal', isBoss: false, index: i }; mapData.push(node); } mapData.push({ type: 'boss', isBoss: true, index: maxFloors - 1 }); } // --- Map Rendering --- function renderMap() { // Add map background if not present if (!game.mapBg) { game.mapBg = LK.getAsset('cardSpecial', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 8, x: 2048 / 2, y: 2732 / 2 }); game.addChildAt(game.mapBg, 0); } game.mapBg.visible = true; // Add boss background if not present if (!game.bossBg) { game.bossBg = LK.getAsset('cardAttack', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 8, x: 2048 / 2, y: 2732 / 2 }); game.addChildAt(game.bossBg, 0); } // Show boss background only if on boss node, otherwise hide if (mapData && mapData[currentMapIndex] && mapData[currentMapIndex].isBoss) { game.bossBg.visible = true; game.mapBg.visible = false; } else { game.bossBg.visible = false; game.mapBg.visible = true; } if (!guiMapGroup) { guiMapGroup = new Container(); game.addChild(guiMapGroup); } // Clear old for (var i = 0; i < mapNodes.length; ++i) mapNodes[i].destroy(); mapNodes = []; for (var i = 0; i < mapPaths.length; ++i) mapPaths[i].destroy(); mapPaths = []; var startY = 350; var gapY = 220; var centerX = 2048 / 2; for (var i = 0; i < mapData.length; ++i) { var node = new MapNode(); var isCurrent = i === currentMapIndex; node.setNode(mapData[i].type, isCurrent, mapData[i].isBoss); node.x = centerX; node.y = startY + i * gapY; node.nodeIndex = i; node.onNodeDown = onMapNodeDown; guiMapGroup.addChild(node); mapNodes.push(node); // Path to next if (i < mapData.length - 1) { var path = LK.getAsset('mapPath', { anchorX: 0.5, anchorY: 0, x: centerX, y: node.y + 60, scaleY: 1.2 }); guiMapGroup.addChild(path); mapPaths.push(path); } } } // --- Map Node Click --- function onMapNodeDown(node, x, y, obj) { if (inBattle) return; if (node.nodeIndex === currentMapIndex) { // Enter battle startBattle(node.nodeIndex); } } // --- Start Battle --- function startBattle(mapIdx) { inBattle = true; // Remove map if (guiMapGroup) guiMapGroup.visible = false; // Hide map and boss backgrounds, show cave background if (game.mapBg) game.mapBg.visible = false; if (game.bossBg) game.bossBg.visible = false; // Setup cave background if (!game.caveBg) { game.caveBg = LK.getAsset('cardDefend', { // Use cardDefend as a placeholder cave bg anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 8, x: 2048 / 2, y: 2732 / 2 }); game.addChildAt(game.caveBg, 0); } else { game.caveBg.visible = true; } // Setup player sprite on left if (!playerNode) { playerNode = new Player(); playerNode.x = 400; playerNode.y = 1700; game.addChild(playerNode); } else { playerNode.x = 400; playerNode.y = 1700; playerNode.visible = true; } playerNode.updateStats(); // Add stamina text above player sprite if (!playerNode.staminaTxt) { playerNode.staminaTxt = new Text2('', { size: 44, fill: '#ffaa00' }); playerNode.staminaTxt.anchor.set(0.5, 0.5); playerNode.staminaTxt.x = 0; playerNode.staminaTxt.y = -160; playerNode.addChild(playerNode.staminaTxt); } playerNode.staminaTxt.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); playerNode.staminaTxt.visible = true; // Setup enemy/enemies on right if (enemyNode) enemyNode.destroy(); enemyNode = new Enemy(); enemyNode.setEnemy(getRandomEnemy(mapData[mapIdx].isBoss)); enemyNode.x = 1648; enemyNode.y = 700; game.addChild(enemyNode); // For future: support multiple enemies // (for now, just one enemyNode, but can be extended to an array of Enemy nodes) // Setup deck/hand if (deck.length === 0) { // Starting deck: 5x Strike, 5x Defend deck = []; for (var i = 0; i < 5; ++i) deck.push(cloneCard(CARD_LIBRARY[0])); for (var i = 0; i < 5; ++i) deck.push(cloneCard(CARD_LIBRARY[1])); } drawPile = []; for (var i = 0; i < deck.length; ++i) drawPile.push(cloneCard(deck[i])); shuffleArray(drawPile); discard = []; hand = []; drawHand(); // Show battle group if (!guiBattleGroup) { guiBattleGroup = new Container(); game.addChild(guiBattleGroup); } guiBattleGroup.visible = true; // Hide reward group if present if (guiRewardGroup) guiRewardGroup.visible = false; // Floor text if (!guiFloorTxt) { guiFloorTxt = new Text2('', { size: 64, fill: '#ffffff' }); guiFloorTxt.anchor.set(0.5, 0); LK.gui.top.addChild(guiFloorTxt); } guiFloorTxt.setText('Floor ' + (mapIdx + 1)); // Reset player stats playerNode.block = 0; playerNode.updateStats(); // Reset stamina playerMaxStamina = 3 + Math.floor(currentMapIndex / 2); // Optionally scale with progress playerStamina = playerMaxStamina; // Show stamina UI as a bar and text above cards, visually distinct if (!guiStaminaTxt) { // Stamina bar background guiStaminaTxt = new Container(); guiStaminaTxt.bg = LK.getAsset('card', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 0.25, x: 0, y: 0 }); guiStaminaTxt.bg.alpha = 0.18; guiStaminaTxt.addChild(guiStaminaTxt.bg); // Stamina bar fill guiStaminaTxt.bar = LK.getAsset('cardAttack', { anchorX: 0, anchorY: 0.5, scaleX: 2.1, scaleY: 0.18, x: -160, y: 0 }); guiStaminaTxt.bar.alpha = 0.45; guiStaminaTxt.addChild(guiStaminaTxt.bar); // Stamina text guiStaminaTxt.text = new Text2('', { size: 54, fill: '#ffaa00' }); guiStaminaTxt.text.anchor.set(0.5, 0.5); guiStaminaTxt.text.x = 0; guiStaminaTxt.text.y = 0; guiStaminaTxt.addChild(guiStaminaTxt.text); guiStaminaTxt.x = 2048 / 2; guiStaminaTxt.y = 1550; LK.gui.top.addChild(guiStaminaTxt); } // Update stamina bar and text var staminaRatio = playerMaxStamina > 0 ? playerStamina / playerMaxStamina : 0; if (guiStaminaTxt.bar) { guiStaminaTxt.bar.scaleX = 2.1 * staminaRatio; } if (guiStaminaTxt.text) { guiStaminaTxt.text.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); } // Enemy intent enemyNode.setIntent(enemyNode.enemyData.intent); // Render hand renderHand(); } // --- Draw Hand --- function drawHand() { hand = []; for (var i = 0; i < 5; ++i) { if (drawPile.length === 0) { // Reshuffle discard if (discard.length === 0) break; for (var j = 0; j < discard.length; ++j) drawPile.push(cloneCard(discard[j])); shuffleArray(drawPile); discard = []; } if (drawPile.length > 0) { hand.push(drawPile.pop()); } } } // --- Render Hand --- function renderHand() { if (!guiHandGroup) { guiHandGroup = new Container(); game.addChild(guiHandGroup); } // Remove old for (var i = 0; i < cardNodes.length; ++i) cardNodes[i].destroy(); cardNodes = []; // Remove old end turn button if present if (guiHandGroup.endTurnBtn) { guiHandGroup.endTurnBtn.destroy(); guiHandGroup.endTurnBtn = null; } var handY = 2400; var handX0 = 2048 / 2 - 2 * 360; for (var i = 0; i < hand.length; ++i) { var cardNode = new Card(); cardNode.setCard(hand[i]); cardNode.x = handX0 + i * 360; cardNode.y = handY; cardNode.onCardDown = onCardDown; guiHandGroup.addChild(cardNode); cardNodes.push(cardNode); // Disable card interaction if stamina is 0 if (playerStamina <= 0) { cardNode.interactive = false; cardNode.alpha = 0.5; } else { cardNode.interactive = true; cardNode.alpha = 1; } } // Add End Turn button above cards if (!guiHandGroup.endTurnBtn) { var btn = new Text2('End Turn', { size: 64, fill: playerStamina > 0 ? '#cccccc' : '#888888' }); btn.anchor.set(0.5, 0.5); btn.x = 2048 / 2; btn.y = handY - 320; // Move button higher above the cards for better separation btn.interactive = true; btn.buttonMode = true; btn.alpha = playerStamina > 0 ? 1 : 0.7; btn.down = function (x, y, obj) { if (!inBattle || battleResult) return; // Only allow end turn if player has stamina left or hand is not empty if (playerStamina > 0 || hand.length > 0) { playerStamina = 0; if (guiStaminaTxt && guiStaminaTxt.text) guiStaminaTxt.text.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); // Disable cards for (var i = 0; i < cardNodes.length; ++i) { cardNodes[i].interactive = false; cardNodes[i].alpha = 0.5; } // End turn, let enemy act after short delay LK.setTimeout(enemyTurn, 400); } }; guiHandGroup.endTurnBtn = btn; guiHandGroup.addChild(btn); } // Update button color/alpha if stamina is 0 if (guiHandGroup.endTurnBtn) { guiHandGroup.endTurnBtn.fill = playerStamina > 0 ? '#cccccc' : '#888888'; guiHandGroup.endTurnBtn.alpha = playerStamina > 0 ? 1 : 0.7; } // Update stamina bar and text after hand render if (guiStaminaTxt && guiStaminaTxt.bar && guiStaminaTxt.text) { var staminaRatio = playerMaxStamina > 0 ? playerStamina / playerMaxStamina : 0; guiStaminaTxt.bar.scaleX = 2.1 * staminaRatio; guiStaminaTxt.text.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); } } // --- Card Down (Select/Drag) --- function onCardDown(cardNode, x, y, obj) { if (!inBattle) return; if (battleResult) return; if (playerStamina <= 0) return; // Prevent card play if no stamina dragCard = cardNode; dragStart = { x: cardNode.x, y: cardNode.y }; dragValid = false; // Highlight for (var i = 0; i < cardNodes.length; ++i) cardNodes[i].setSelected(cardNodes[i] === cardNode); } // --- Game Move (Drag Card) --- game.move = function (x, y, obj) { if (dragCard && inBattle && !battleResult) { // Move card with finger dragCard.x = x; dragCard.y = y; // If dragged over enemy, highlight var enemyRect = { x: enemyNode.x - 110, y: enemyNode.y - 110, w: 220, h: 220 }; if (x > enemyRect.x && x < enemyRect.x + enemyRect.w && y > enemyRect.y && y < enemyRect.y + enemyRect.h) { dragValid = true; enemyNode.alpha = 0.7; } else { dragValid = false; enemyNode.alpha = 1; } } }; // --- Game Up (Release Card) --- game.up = function (x, y, obj) { if (dragCard && inBattle && !battleResult) { // If valid, play card if (dragValid) { playCard(dragCard); } else { // Return to hand tween(dragCard, { x: dragStart.x, y: dragStart.y }, { duration: 180, easing: tween.easeOut }); for (var i = 0; i < cardNodes.length; ++i) cardNodes[i].setSelected(false); } dragCard = null; dragStart = null; dragValid = false; enemyNode.alpha = 1; } }; // --- Play Card --- function playCard(cardNode) { var idx = cardNodes.indexOf(cardNode); if (idx === -1) return; var card = hand[idx]; var cost = card.stamina || 1; if (playerStamina < cost) { // Not enough stamina, shake card and return tween(cardNode, { x: cardNode.x - 30 }, { duration: 80, yoyo: true, repeat: 1, onFinish: function onFinish() { tween(cardNode, { x: dragStart ? dragStart.x : cardNode.x }, { duration: 80 }); } }); for (var i = 0; i < cardNodes.length; ++i) cardNodes[i].setSelected(false); return; } playerStamina -= cost; // Update stamina GUI bar and text after card play if (guiStaminaTxt && guiStaminaTxt.bar && guiStaminaTxt.text) { var staminaRatio = playerMaxStamina > 0 ? playerStamina / playerMaxStamina : 0; guiStaminaTxt.bar.scaleX = 2.1 * staminaRatio; guiStaminaTxt.text.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); } // Update player stamina text above player if (playerNode && playerNode.staminaTxt) { playerNode.staminaTxt.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); } // Animate card to enemy tween(cardNode, { x: enemyNode.x, y: enemyNode.y }, { duration: 180, easing: tween.easeIn, onFinish: function onFinish() { // Apply effect if (card.type === 'attack') { var dmg = card.damage; // Bash effect: next attack +3 if (playerNode.nextAttackBonus) { dmg += playerNode.nextAttackBonus; playerNode.nextAttackBonus = 0; } enemyNode.hp -= dmg; if (enemyNode.hp < 0) enemyNode.hp = 0; enemyNode.updateHp(); LK.effects.flashObject(enemyNode, 0xff0000, 300); } else if (card.type === 'defend') { playerNode.block += card.block; LK.effects.flashObject(playerNode, 0x55aaff, 300); } else if (card.type === 'special') { if (card.special === 'heal') { playerNode.hp += card.value; if (playerNode.hp > playerNode.maxHp) playerNode.hp = playerNode.maxHp; LK.effects.flashObject(playerNode, 0x55ff99, 300); } else if (card.special === 'double') { var dmg = card.value; if (playerNode.nextAttackBonus) { dmg += playerNode.nextAttackBonus; playerNode.nextAttackBonus = 0; } enemyNode.hp -= dmg; enemyNode.hp -= dmg; if (enemyNode.hp < 0) enemyNode.hp = 0; enemyNode.updateHp(); LK.effects.flashObject(enemyNode, 0xff0000, 300); } else if (card.special === 'bash') { enemyNode.hp -= card.value; if (enemyNode.hp < 0) enemyNode.hp = 0; enemyNode.updateHp(); playerNode.nextAttackBonus = 3; LK.effects.flashObject(enemyNode, 0xff0000, 300); } } playerNode.updateStats(); // Discard card discard.push(card); hand.splice(idx, 1); cardNode.destroy(); cardNodes.splice(idx, 1); // Check win if (enemyNode.hp <= 0) { battleResult = 'win'; LK.setTimeout(showBattleWin, 600); return; } // Enemy turn if no cards left or after play if (hand.length === 0) { LK.setTimeout(enemyTurn, 500); } else { // If stamina is 0, disable cards and prompt end turn if (playerStamina <= 0) { renderHand(); } else { renderHand(); } } } }); } // --- Enemy Turn --- function enemyTurn() { // Enemy intent var intent = enemyNode.intent; if (intent && intent.type === 'attack') { var dmg = intent.value; var block = playerNode.block; var taken = dmg; if (block > 0) { if (block >= dmg) { playerNode.block -= dmg; taken = 0; } else { taken = dmg - block; playerNode.block = 0; } } playerNode.hp -= taken; if (playerNode.hp < 0) playerNode.hp = 0; LK.effects.flashObject(playerNode, 0xff0000, 400); // Show floating damage text above player if (taken > 0) { var dmgTxt = new Text2('-' + taken, { size: 48, fill: '#ff3333' }); dmgTxt.anchor.set(0.5, 0.5); dmgTxt.x = playerNode.x; dmgTxt.y = playerNode.y - 120; game.addChild(dmgTxt); tween(dmgTxt, { y: dmgTxt.y - 80, alpha: 0 }, { duration: 700, onFinish: function onFinish() { dmgTxt.destroy(); } }); } } else if (intent && intent.type === 'block') { enemyNode.hp += intent.value; if (enemyNode.hp > enemyNode.maxHp) enemyNode.hp = enemyNode.maxHp; LK.effects.flashObject(enemyNode, 0x55aaff, 400); } playerNode.updateStats(); enemyNode.updateHp(); // Check lose if (playerNode.hp <= 0) { battleResult = 'lose'; LK.setTimeout(showBattleLose, 600); return; } // Next turn: draw new hand, reset block playerNode.block = 0; playerNode.updateStats(); playerStamina = playerMaxStamina; // Update stamina GUI bar and text after enemy turn if (guiStaminaTxt && guiStaminaTxt.bar && guiStaminaTxt.text) { var staminaRatio = playerMaxStamina > 0 ? playerStamina / playerMaxStamina : 0; guiStaminaTxt.bar.scaleX = 2.1 * staminaRatio; guiStaminaTxt.text.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); } drawHand(); renderHand(); // Update player stamina text above player if (playerNode && playerNode.staminaTxt) { playerNode.staminaTxt.setText('Stamina: ' + playerStamina + ' / ' + playerMaxStamina); } // New enemy intent var enemyData = enemyNode.enemyData; // Randomize intent if (Math.random() < 0.5) { enemyNode.setIntent({ type: 'attack', value: enemyData.intent.value }); } else { enemyNode.setIntent({ type: 'block', value: Math.floor(enemyData.intent.value * 0.8) }); } } // --- Show Battle Win --- function showBattleWin() { // Remove enemy if (enemyNode) enemyNode.destroy(); enemyNode = null; // Hide end turn button and disable cards if (guiHandGroup && guiHandGroup.endTurnBtn) { guiHandGroup.endTurnBtn.visible = false; } for (var i = 0; i < cardNodes.length; ++i) { cardNodes[i].interactive = false; cardNodes[i].alpha = 0.5; } // Show reward showReward(); } // --- Show Battle Lose --- function showBattleLose() { LK.effects.flashScreen(0xff0000, 1000); // Hide end turn button and disable cards if (guiHandGroup && guiHandGroup.endTurnBtn) { guiHandGroup.endTurnBtn.visible = false; } for (var i = 0; i < cardNodes.length; ++i) { cardNodes[i].interactive = false; cardNodes[i].alpha = 0.5; } LK.showGameOver(); } // --- Show Reward (Choose 1 of 3 cards) --- function showReward() { if (!guiRewardGroup) { guiRewardGroup = new Container(); game.addChild(guiRewardGroup); } guiRewardGroup.visible = true; // Hide player stamina text when not in battle if (playerNode && playerNode.staminaTxt) { playerNode.staminaTxt.visible = false; } // Remove old for (var i = 0; i < rewardCardNodes.length; ++i) rewardCardNodes[i].destroy(); rewardCardNodes = []; if (rewardTxt) rewardTxt.destroy(); rewardTxt = new Text2('Choose a card to add to your deck\nor +1 Max Stamina', { size: 64, fill: '#fff' }); rewardTxt.anchor.set(0.5, 0); rewardTxt.x = 2048 / 2; rewardTxt.y = 600; guiRewardGroup.addChild(rewardTxt); rewardCards = []; for (var i = 0; i < 3; ++i) rewardCards.push(getRandomCard()); var rx0 = 2048 / 2 - 360; for (var i = 0; i < 3; ++i) { var cardNode = new Card(); cardNode.setCard(rewardCards[i]); cardNode.x = rx0 + i * 360; cardNode.y = 1100; cardNode.onCardDown = onRewardCardDown; guiRewardGroup.addChild(cardNode); rewardCardNodes.push(cardNode); } // Add stamina upgrade button if (!guiRewardGroup.staminaBtn) { guiRewardGroup.staminaBtn = new Text2('+1 Max Stamina', { size: 56, fill: '#ffaa00' }); guiRewardGroup.staminaBtn.anchor.set(0.5, 0.5); guiRewardGroup.staminaBtn.x = 2048 / 2; guiRewardGroup.staminaBtn.y = 1500; guiRewardGroup.staminaBtn.interactive = true; guiRewardGroup.staminaBtn.buttonMode = true; guiRewardGroup.staminaBtn.down = function (x, y, obj) { playerMaxStamina += 1; guiRewardGroup.visible = false; battleResult = null; inBattle = false; currentMapIndex += 1; if (currentMapIndex >= mapData.length) { LK.showYouWin(); return; } guiMapGroup.visible = true; renderMap(); }; guiRewardGroup.addChild(guiRewardGroup.staminaBtn); } else { guiRewardGroup.staminaBtn.visible = true; } } // --- Reward Card Down (Pick Card) --- function onRewardCardDown(cardNode, x, y, obj) { var idx = rewardCardNodes.indexOf(cardNode); if (idx === -1) return; // Add to deck deck.push(cloneCard(rewardCards[idx])); // Next map node guiRewardGroup.visible = false; if (game.caveBg) game.caveBg.visible = false; if (playerNode) playerNode.visible = false; if (playerNode && playerNode.staminaTxt) playerNode.staminaTxt.visible = false; if (enemyNode) enemyNode.visible = false; battleResult = null; inBattle = false; currentMapIndex += 1; if (currentMapIndex >= mapData.length) { // Win game LK.showYouWin(); return; } // Show map again if (game.mapBg) game.mapBg.visible = true; if (game.bossBg) game.bossBg.visible = false; guiMapGroup.visible = true; renderMap(); } // --- Game Update --- game.update = function () { // No per-frame logic needed for now }; // --- Game Start --- function startGame() { // Reset state player = null; enemy = null; hand = []; deck = []; discard = []; drawPile = []; selectedCard = null; cardNodes = []; enemyNode = null; playerNode = null; mapNodes = []; mapPaths = []; currentMapIndex = 0; inBattle = false; battleResult = null; rewardCards = []; rewardCardNodes = []; floorNum = 1; // Generate map generateMap(); renderMap(); } startGame();
===================================================================
--- original.js
+++ change.js
@@ -39,11 +39,13 @@
nameTxt.anchor.set(0.5, 0);
nameTxt.x = 0;
nameTxt.y = -180;
self.addChild(nameTxt);
+ // Card description text (explains what the card does, e.g. "Deal 6 damage", "Gain 5 block")
+ // This text is shown under the card image, centered, and uses white color for clarity
descTxt = new Text2(cardData.desc, {
size: 32,
- fill: '#333333'
+ fill: '#ffffff'
});
descTxt.anchor.set(0.5, 0);
descTxt.x = 0;
descTxt.y = -100;
@@ -356,8 +358,41 @@
});
}
// --- Map Rendering ---
function renderMap() {
+ // Add map background if not present
+ if (!game.mapBg) {
+ game.mapBg = LK.getAsset('cardSpecial', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 8,
+ scaleY: 8,
+ x: 2048 / 2,
+ y: 2732 / 2
+ });
+ game.addChildAt(game.mapBg, 0);
+ }
+ game.mapBg.visible = true;
+ // Add boss background if not present
+ if (!game.bossBg) {
+ game.bossBg = LK.getAsset('cardAttack', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 8,
+ scaleY: 8,
+ x: 2048 / 2,
+ y: 2732 / 2
+ });
+ game.addChildAt(game.bossBg, 0);
+ }
+ // Show boss background only if on boss node, otherwise hide
+ if (mapData && mapData[currentMapIndex] && mapData[currentMapIndex].isBoss) {
+ game.bossBg.visible = true;
+ game.mapBg.visible = false;
+ } else {
+ game.bossBg.visible = false;
+ game.mapBg.visible = true;
+ }
if (!guiMapGroup) {
guiMapGroup = new Container();
game.addChild(guiMapGroup);
}
@@ -405,8 +440,11 @@
function startBattle(mapIdx) {
inBattle = true;
// Remove map
if (guiMapGroup) guiMapGroup.visible = false;
+ // Hide map and boss backgrounds, show cave background
+ if (game.mapBg) game.mapBg.visible = false;
+ if (game.bossBg) game.bossBg.visible = false;
// Setup cave background
if (!game.caveBg) {
game.caveBg = LK.getAsset('cardDefend', {
// Use cardDefend as a placeholder cave bg
@@ -999,8 +1037,10 @@
LK.showYouWin();
return;
}
// Show map again
+ if (game.mapBg) game.mapBg.visible = true;
+ if (game.bossBg) game.bossBg.visible = false;
guiMapGroup.visible = true;
renderMap();
}
// --- Game Update ---
2d stylized dungeon enemy. In-Game asset. 2d. High contrast. No shadows
boss logo skull head. In-Game asset. 2d. High contrast. No shadows
dungeon card game, Strike card. In-Game asset. 2d. High contrast. No shadows
dungeon card game defend card . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
dungeon card game special card with fire logo . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
2d card game player hero asset. In-Game asset. 2d. High contrast. No shadows
dungeon simple 2d side view dungeon crawler game background. In-Game asset. 2d. High contrast. No shadows. background
golden button horizontal. In-Game asset. 2d. High contrast. No shadows
2d dungeon crawler boss. In-Game asset. 2d. High contrast. No shadows