User prompt
Please fix the bug: 'Uncaught TypeError: slot.containsPoint is not a function' in or related to this line: 'if (!slot.occupied && slot.containsPoint({' Line Number: 485
Code edit (1 edits merged)
Please save this source code
User prompt
Cardbound: The Inscription Trials
Initial prompt
I want a game like inscription from you
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Card class: represents a single card (creature or resource) var Card = Container.expand(function () { var self = Container.call(this); // Card properties (to be set on creation) self.cardData = null; // {name, attack, health, cost, type, id} self.isPlayerCard = true; // true if belongs to player, false if opponent // Card visual var cardBox = self.attachAsset('cardBox', { width: 260, height: 360, color: 0x222222, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Card name var nameTxt = new Text2('', { size: 48, fill: "#fff" }); nameTxt.anchor.set(0.5, 0); nameTxt.x = 0; nameTxt.y = -150; self.addChild(nameTxt); // Attack/Health with symbols var statsTxt = new Text2('', { size: 48, fill: 0xFFEC70 }); statsTxt.anchor.set(0.5, 0.5); // Move stats area further to the right statsTxt.x = 0; // was -50, now centered more right statsTxt.y = 120; self.addChild(statsTxt); // Cost var costTxt = new Text2('', { size: 40, fill: 0xB8B031 }); costTxt.anchor.set(0.5, 0.5); // Move cost area further to the right costTxt.x = 120; // was 90, now more right costTxt.y = 120; self.addChild(costTxt); // Set card data and visuals self.setCard = function (cardData, isPlayerCard) { self.cardData = cardData; self.isPlayerCard = isPlayerCard; nameTxt.setText(cardData.name); statsTxt.setText("⚔" + cardData.attack + " ♥" + cardData.health); costTxt.setText(cardData.cost); // Tint for opponent cards cardBox.tint = isPlayerCard ? 0x222222 : 0x2a1a2a; }; // Update stats display self.updateStats = function () { if (self.cardData) { statsTxt.setText("⚔" + self.cardData.attack + " ♥" + self.cardData.health); } }; // Flash effect for damage self.flash = function (color) { LK.effects.flashObject(self, color, 300); }; // Selection properties self.isSelected = false; return self; }); // Slot class: represents a board slot (for creatures) var Slot = Container.expand(function () { var self = Container.call(this); self.isPlayerSlot = true; self.slotIndex = 0; self.occupied = false; self.card = null; var slotBox = self.attachAsset('slotBox', { width: 270, height: 380, color: 0x444444, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Highlight for valid drop self.setHighlight = function (on) { slotBox.tint = on ? 0x83de44 : 0x444444; }; // Place card in slot self.placeCard = function (card) { self.card = card; self.occupied = true; card.x = self.x; card.y = self.y; card.isSelected = false; card.alpha = 1.0; game.addChild(card); }; // Remove card from slot self.removeCard = function () { self.card = null; self.occupied = false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x18181a }); /**** * Game Code ****/ // --- Game Constants --- var BOARD_COLS = 4; var PLAYER_Y = 1950; var OPPONENT_Y = 1150; var HAND_Y = 2450; var SLOT_SPACING = 340; var HAND_SPACING = 320; var MAX_HAND = 5; var MAX_HEALTH = 10; // --- Card Pool --- var CARD_POOL = [{ id: 1, name: "Stoat", attack: 1, health: 2, cost: 1, type: "creature" }, { id: 2, name: "Wolf", attack: 3, health: 2, cost: 2, type: "creature" }, { id: 3, name: "Bullfrog", attack: 1, health: 3, cost: 1, type: "creature" }, { id: 4, name: "Adder", attack: 1, health: 1, cost: 2, type: "creature" }, { id: 5, name: "Squirrel", attack: 0, health: 1, cost: 0, type: "resource" }, // New card types { id: 6, name: "Grizzly", attack: 4, health: 6, cost: 3, type: "creature" }, { id: 7, name: "Raven", attack: 2, health: 3, cost: 2, type: "creature" }, { id: 8, name: "Elk", attack: 2, health: 4, cost: 2, type: "creature" }, { id: 9, name: "Rabbit", attack: 0, health: 1, cost: 0, type: "resource" }]; // --- Game State --- var playerDeck = []; var opponentDeck = []; var playerHand = []; var opponentHand = []; var playerSlots = []; var opponentSlots = []; var playerHealth = MAX_HEALTH; var opponentHealth = MAX_HEALTH; var turn = "player"; // "player" or "opponent" // Card selection variables var selectedCard = null; var canPlay = true; var playerResources = 0; var turnTxt, healthTxt, oppHealthTxt, resourceTxt, messageTxt; // --- UI Setup --- // Card list removed // Life display in top center var lifeTxt = new Text2("♥ " + playerHealth + " | ♥ " + opponentHealth, { size: 80, fill: 0xFF6B6B }); lifeTxt.anchor.set(0.5, 0); lifeTxt.y = 20; LK.gui.top.addChild(lifeTxt); // Health display (keeping original for backward compatibility) healthTxt = new Text2("You: " + playerHealth, { size: 80, fill: "#fff" }); healthTxt.anchor.set(0, 0.5); healthTxt.visible = false; // Hide original health display LK.gui.top.addChild(healthTxt); oppHealthTxt = new Text2("Opponent: " + opponentHealth, { size: 80, fill: "#fff" }); oppHealthTxt.anchor.set(1, 0.5); oppHealthTxt.visible = false; // Hide original health display LK.gui.topRight.addChild(oppHealthTxt); // Turn display turnTxt = new Text2("Your Turn", { size: 70, fill: 0xFFEC70 }); turnTxt.anchor.set(0.5, 0.5); turnTxt.y = 200; // Move lower LK.gui.top.addChild(turnTxt); // Resource display resourceTxt = new Text2("🩸 " + playerResources, { size: 60, fill: 0xB8B031 }); resourceTxt.anchor.set(1, 0.5); resourceTxt.x = -20; resourceTxt.y = 150; LK.gui.topRight.addChild(resourceTxt); // Upper message display removed // Lower message display removed // --- End Turn Button --- // Remove any previous button if present if (typeof endTurnBtn !== "undefined" && endTurnBtn.parent) { endTurnBtn.parent.removeChild(endTurnBtn); } endTurnBtn = LK.getAsset('centerCircle', { width: 150, height: 150, color: 0xff0000, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5, x: 1900, y: 1366 }); game.addChild(endTurnBtn); // End turn button logic endTurnBtn.interactive = true; endTurnBtn.buttonMode = true; endTurnBtn.visible = turn === "player"; endTurnBtn.down = function (x, y, obj) { if (turn === "player" && canPlay) { canPlay = false; endTurnBtn.visible = false; // Message displays removed LK.setTimeout(startOpponentTurn, 400); } }; // --- Board Setup --- // Player slots for (var i = 0; i < BOARD_COLS; i++) { var slot = new Slot(); slot.isPlayerSlot = true; slot.slotIndex = i; slot.x = 400 + i * SLOT_SPACING; slot.y = PLAYER_Y; playerSlots.push(slot); game.addChild(slot); } // Opponent slots for (var i = 0; i < BOARD_COLS; i++) { var slot = new Slot(); slot.isPlayerSlot = false; slot.slotIndex = i; slot.x = 400 + i * SLOT_SPACING; slot.y = OPPONENT_Y; opponentSlots.push(slot); game.addChild(slot); } // --- Deck/Hand Setup --- function shuffleDeck(deck) { for (var i = deck.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } } function createDeck() { // Player: 2 Stoat, 2 Wolf, 2 Bullfrog, 1 Adder, 3 Squirrel var deck = []; for (var i = 0; i < 2; i++) deck.push(CARD_POOL[0]); for (var i = 0; i < 2; i++) deck.push(CARD_POOL[1]); for (var i = 0; i < 2; i++) deck.push(CARD_POOL[2]); deck.push(CARD_POOL[3]); for (var i = 0; i < 3; i++) deck.push(CARD_POOL[4]); shuffleDeck(deck); return deck.slice(); } function createOpponentDeck() { // Opponent: 2 Wolf, 2 Bullfrog, 2 Adder, 2 Squirrel var deck = []; for (var i = 0; i < 2; i++) deck.push(CARD_POOL[1]); for (var i = 0; i < 2; i++) deck.push(CARD_POOL[2]); for (var i = 0; i < 2; i++) deck.push(CARD_POOL[3]); for (var i = 0; i < 2; i++) deck.push(CARD_POOL[4]); shuffleDeck(deck); return deck.slice(); } // --- Hand Display --- function updateHandDisplay() { // Remove all player hand cards from game for (var i = 0; i < playerHand.length; i++) { if (playerHand[i].parent) playerHand[i].parent.removeChild(playerHand[i]); } // Layout hand - align with board slots for (var i = 0; i < playerHand.length; i++) { var card = playerHand[i]; card.x = 400 + i * SLOT_SPACING; card.y = HAND_Y; card.isPlayerCard = true; game.addChild(card); } } function updateOpponentHandDisplay() { // Remove all opponent hand cards from game for (var i = 0; i < opponentHand.length; i++) { if (opponentHand[i].parent) opponentHand[i].parent.removeChild(opponentHand[i]); } // Layout hand (hidden) - align with board slots for (var i = 0; i < opponentHand.length; i++) { var card = opponentHand[i]; card.x = 400 + i * SLOT_SPACING; card.y = OPPONENT_Y - 400; card.isPlayerCard = false; game.addChild(card); } } // --- Draw Card --- function drawCard(deck, hand, isPlayer) { if (deck.length === 0 || hand.length >= MAX_HAND) return; var cardData = deck.shift(); var card = new Card(); card.setCard(cardData, isPlayer); hand.push(card); } // --- Start Game --- function startGame() { playerDeck = createDeck(); opponentDeck = createOpponentDeck(); playerHand = []; opponentHand = []; playerHealth = MAX_HEALTH; opponentHealth = MAX_HEALTH; playerResources = 0; turn = "player"; canPlay = true; // Message displays removed // Remove all cards from slots for (var i = 0; i < BOARD_COLS; i++) { if (playerSlots[i].card) { playerSlots[i].card.destroy(); playerSlots[i].removeCard(); } if (opponentSlots[i].card) { opponentSlots[i].card.destroy(); opponentSlots[i].removeCard(); } } // Draw initial hands for (var i = 0; i < 4; i++) drawCard(playerDeck, playerHand, true); for (var i = 0; i < 4; i++) drawCard(opponentDeck, opponentHand, false); updateHandDisplay(); updateOpponentHandDisplay(); updateUI(); } function updateUI() { healthTxt.setText("You: " + playerHealth); oppHealthTxt.setText("Opponent: " + opponentHealth); if (typeof lifeTxt !== "undefined") { lifeTxt.setText("♥ " + playerHealth + " | ♥ " + opponentHealth); } resourceTxt.setText("🩸 " + playerResources); turnTxt.setText(turn === "player" ? "Your Turn" : "Opponent Turn"); } // --- Turn Logic --- function startPlayerTurn() { turn = "player"; canPlay = true; drawCard(playerDeck, playerHand, true); updateHandDisplay(); updateUI(); // Message displays removed if (typeof endTurnBtn !== "undefined") { endTurnBtn.visible = true; } } function startOpponentTurn() { turn = "opponent"; canPlay = false; updateUI(); // Message displays removed if (typeof endTurnBtn !== "undefined") { endTurnBtn.visible = false; } LK.setTimeout(opponentPlay, 900); } // --- Play Card --- function canPlayCard(card, slot) { if (!card || !slot) return false; if (!slot.isPlayerSlot) return false; if (slot.occupied) return false; if (card.cardData.type === "resource") return true; // For creatures, check if we have enough blood or creatures to sacrifice if (card.cardData.type === "creature") { // If we have enough blood, we can play if (playerResources >= card.cardData.cost) return true; // Count available creatures for sacrifice (excluding the target slot and squirrels) var creaturesOnBoard = 0; for (var i = 0; i < playerSlots.length; i++) { if (playerSlots[i].card && playerSlots[i].card.cardData.type === "creature" && playerSlots[i] !== slot && playerSlots[i].card.cardData.id !== 5) { creaturesOnBoard++; } } // Check if we have enough creatures to sacrifice to cover the remaining cost var bloodNeeded = card.cardData.cost - playerResources; if (creaturesOnBoard >= bloodNeeded) return true; } return false; } function playCard(card, slot) { if (!canPlayCard(card, slot)) return false; // Remove from hand var idx = playerHand.indexOf(card); if (idx !== -1) playerHand.splice(idx, 1); // Place in slot slot.placeCard(card); // Pay cost if (card.cardData.type === "creature") { if (playerResources >= card.cardData.cost) { playerResources -= card.cardData.cost; } else { // Sacrifice creatures for blood (excluding squirrels) var costRemaining = card.cardData.cost; for (var i = 0; i < playerSlots.length && costRemaining > 0; i++) { if (playerSlots[i].card && playerSlots[i].card.cardData.type === "creature" && playerSlots[i] !== slot && playerSlots[i].card.cardData.id !== 5) { var sacrificeCard = playerSlots[i].card; sacrificeCard.flash(0xd83318); LK.setTimeout(function (slotToRemove, cardToDestroy) { return function () { slotToRemove.removeCard(); cardToDestroy.destroy(); }; }(playerSlots[i], sacrificeCard), 300); costRemaining--; } } } } // Squirrel: resource, gives +1 blood, then disappears if (card.cardData.type === "resource") { playerResources += 1; card.flash(0xb8b031); LK.setTimeout(function () { slot.removeCard(); card.destroy(); }, 400); } updateHandDisplay(); updateUI(); return true; } // --- Card Sacrifice Selection --- var selectedCardForSacrifice = null; var sacrificeHighlight = null; // Helper to clear sacrifice selection function clearSacrificeSelection() { if (selectedCardForSacrifice) { // Remove highlight if any if (sacrificeHighlight && sacrificeHighlight.parent) { sacrificeHighlight.parent.removeChild(sacrificeHighlight); } sacrificeHighlight = null; selectedCardForSacrifice = null; // Clear all slot highlights for (var i = 0; i < playerSlots.length; i++) { playerSlots[i].setHighlight(false); } } } // Helper to highlight a card for sacrifice function highlightCardForSacrifice(card) { if (sacrificeHighlight && sacrificeHighlight.parent) { sacrificeHighlight.parent.removeChild(sacrificeHighlight); } sacrificeHighlight = LK.getAsset('centerCircle', { width: 280, height: 380, color: 0x00ff00, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: card.x, y: card.y }); sacrificeHighlight.alpha = 0.3; // Place highlight below the card if (card.parent) { card.parent.addChildAt(sacrificeHighlight, 0); } // Highlight all slots to show where the card can be moved (both empty and occupied for replacement) for (var i = 0; i < playerSlots.length; i++) { playerSlots[i].setHighlight(true); } } // Helper function to clear card selection function clearCardSelection() { if (selectedCard) { selectedCard.isSelected = false; // Remove any visual selection indicator selectedCard.alpha = 1.0; selectedCard = null; // Clear slot highlights for (var i = 0; i < playerSlots.length; i++) { playerSlots[i].setHighlight(false); } } } // Helper function to select a card function selectCard(card) { clearCardSelection(); selectedCard = card; card.isSelected = true; // Visual feedback for selected card card.alpha = 0.7; // Highlight available slots for (var i = 0; i < playerSlots.length; i++) { if (!playerSlots[i].occupied) { playerSlots[i].setHighlight(true); } } } // Click-based card selection and placement game.down = function (x, y, obj) { // If we have a card already selected, check if clicking on a slot to place it if (selectedCard) { // Check if clicked on a slot for (var i = 0; i < playerSlots.length; i++) { var slot = playerSlots[i]; var slotWidth = 270; var slotHeight = 380; var isInside = x >= slot.x - slotWidth / 2 && x <= slot.x + slotWidth / 2 && y >= slot.y - slotHeight / 2 && y <= slot.y + slotHeight / 2; if (!slot.occupied && isInside) { // Check if we can play this card (including blood cost check) if (canPlayCard(selectedCard, slot)) { // Play the selected card playCard(selectedCard, slot); clearCardSelection(); return; } else { // Flash red to indicate insufficient resources LK.effects.flashObject(selectedCard, 0xff0000, 500); clearCardSelection(); return; } } } // If clicked elsewhere, clear selection clearCardSelection(); return; } // Check for sacrifice selection first (high-cost cards that need sacrifice) if (selectedCardForSacrifice) { // Check if clicked on a slot for (var i = 0; i < playerSlots.length; i++) { var slot = playerSlots[i]; var slotWidth = 270; var slotHeight = 380; var isInside = x >= slot.x - slotWidth / 2 && x <= slot.x + slotWidth / 2 && y >= slot.y - slotHeight / 2 && y <= slot.y + slotHeight / 2; if (isInside) { // Check if we can sacrifice creatures for this card var card = selectedCardForSacrifice; var totalCostRequired = card.cardData.cost; // If slot is occupied, calculate replacement cost if (slot.occupied && slot.card.cardData.type === "creature") { var existingCard = slot.card; // Higher cost cards require more sacrifice, lower cost cards reduce requirement var costDifference = totalCostRequired - existingCard.cardData.cost; totalCostRequired = Math.max(0, costDifference); } var bloodRequired = totalCostRequired - playerResources; // Count available creatures for sacrifice (excluding source slot, target slot, and squirrels) var availableCreatures = []; for (var j = 0; j < playerSlots.length; j++) { if (playerSlots[j].card && playerSlots[j].card.cardData.type === "creature" && playerSlots[j].card !== card && playerSlots[j] !== slot && playerSlots[j].card.cardData.id !== 5) { availableCreatures.push(playerSlots[j]); } } // Check if we have enough creatures to sacrifice if (bloodRequired <= 0 || availableCreatures.length >= bloodRequired) { // Remove from hand if in hand var idx = playerHand.indexOf(card); if (idx !== -1) playerHand.splice(idx, 1); // Remove existing card from target slot if occupied (this counts as part of the sacrifice) if (slot.occupied && slot.card.cardData.type === "creature") { var replacedCard = slot.card; replacedCard.flash(0xd83318); LK.setTimeout(function (cardToDestroy) { return function () { cardToDestroy.destroy(); }; }(replacedCard), 300); slot.removeCard(); } // Remove from old slot if it was on board var wasOnBoard = false; for (var j = 0; j < playerSlots.length; j++) { if (playerSlots[j].card === card) { playerSlots[j].removeCard(); wasOnBoard = true; break; } } // Sacrifice creatures if needed (using blood first) var remainingCost = totalCostRequired; remainingCost -= playerResources; playerResources = Math.max(0, playerResources - totalCostRequired); if (remainingCost > 0) { // Sacrifice creatures for (var k = 0; k < availableCreatures.length && remainingCost > 0; k++) { var sacrificeSlot = availableCreatures[k]; var sacrificeCard = sacrificeSlot.card; sacrificeCard.flash(0xd83318); LK.setTimeout(function (slotToRemove, cardToDestroy) { return function () { slotToRemove.removeCard(); cardToDestroy.destroy(); }; }(sacrificeSlot, sacrificeCard), 300); remainingCost--; } } slot.placeCard(card); clearSacrificeSelection(); updateHandDisplay(); updateUI(); return; } else { // Not enough resources - flash red LK.effects.flashObject(card, 0xff0000, 500); clearSacrificeSelection(); return; } } } // If not clicked on a slot, clear selection clearSacrificeSelection(); return; } // Check if a card in hand is clicked for selection for (var i = 0; i < playerHand.length; i++) { var card = playerHand[i]; var cardWidth = 260; var cardHeight = 360; var isInside = x >= card.x - cardWidth / 2 && x <= card.x + cardWidth / 2 && y >= card.y - cardHeight / 2 && y <= card.y + cardHeight / 2; if (isInside && turn === "player" && canPlay) { // Check if this card requires sacrifice if (card.cardData.type === "creature" && card.cardData.cost > playerResources) { // This card requires sacrifice - use sacrifice system selectedCardForSacrifice = card; highlightCardForSacrifice(card); return; } else { // Regular card selection selectCard(card); return; } } } // Check if a card on the board is clicked for selection (only if turn is player and can play) if (turn === "player" && canPlay) { for (var i = 0; i < playerSlots.length; i++) { if (playerSlots[i].card && playerSlots[i].card.cardData.type === "creature") { var card = playerSlots[i].card; var cardWidth = 260; var cardHeight = 360; var isInside = x >= card.x - cardWidth / 2 && x <= card.x + cardWidth / 2 && y >= card.y - cardHeight / 2 && y <= card.y + cardHeight / 2; if (isInside) { // Only select for sacrifice if it's a high-cost creature that can be moved // or if we need to sacrifice it for another card selectedCardForSacrifice = card; highlightCardForSacrifice(card); return; } } } } }; // No up handler needed for click-based system // --- Combat Phase --- function combatPhase() { // Player creatures attack for (var i = 0; i < BOARD_COLS; i++) { var pSlot = playerSlots[i]; if (pSlot.card && pSlot.card.cardData.type === "creature") { var oppSlot = opponentSlots[i]; if (oppSlot.card && oppSlot.card.cardData.type === "creature") { // Attack opposing creature oppSlot.card.cardData.health -= pSlot.card.cardData.attack; pSlot.card.flash(0xffec70); oppSlot.card.flash(0xd83318); oppSlot.card.updateStats(); if (oppSlot.card.cardData.health <= 0) { LK.setTimeout(function (slot, card) { return function () { slot.removeCard(); card.destroy(); }; }(oppSlot, oppSlot.card), 300); } } else { // Attack opponent directly opponentHealth -= pSlot.card.cardData.attack; if (opponentHealth < 0) opponentHealth = 0; } } } // Opponent creatures attack for (var i = 0; i < BOARD_COLS; i++) { var oSlot = opponentSlots[i]; if (oSlot.card && oSlot.card.cardData.type === "creature") { var pSlot = playerSlots[i]; if (pSlot.card && pSlot.card.cardData.type === "creature") { // Attack opposing creature pSlot.card.cardData.health -= oSlot.card.cardData.attack; oSlot.card.flash(0xffec70); pSlot.card.flash(0xd83318); pSlot.card.updateStats(); if (pSlot.card.cardData.health <= 0) { LK.setTimeout(function (slot, card) { return function () { slot.removeCard(); card.destroy(); }; }(pSlot, pSlot.card), 300); } } else { // Attack player directly playerHealth -= oSlot.card.cardData.attack; if (playerHealth < 0) playerHealth = 0; } } } updateUI(); // Check win/lose if (playerHealth <= 0) { LK.effects.flashScreen(0xd83318, 1000); LK.showGameOver(); return; } if (opponentHealth <= 0) { LK.effects.flashScreen(0x83de44, 1000); LK.showYouWin(); return; } // Next turn if (turn === "player") { LK.setTimeout(startOpponentTurn, 900); } else { LK.setTimeout(startPlayerTurn, 900); } } // --- Opponent AI --- function opponentPlay() { // Play first playable creature to empty slot var played = false; for (var i = 0; i < opponentHand.length; i++) { var card = opponentHand[i]; if (card.cardData.type === "creature") { for (var j = 0; j < BOARD_COLS; j++) { var slot = opponentSlots[j]; if (!slot.occupied) { // Play card opponentHand.splice(i, 1); slot.placeCard(card); played = true; break; } } if (played) break; } } // Draw a card drawCard(opponentDeck, opponentHand, false); updateOpponentHandDisplay(); LK.setTimeout(combatPhase, 900); } // --- Game Update --- game.update = function () { // No per-frame logic needed for MVP }; // --- Deck Button --- var deckBtn = LK.getAsset('cardBox', { width: 120, height: 160, color: 0x4a4a4a, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 150, y: HAND_Y - 200 }); game.addChild(deckBtn); // Deck button label var deckBtnTxt = new Text2("DECK", { size: 36, fill: "#fff" }); deckBtnTxt.anchor.set(0.5, 0.5); deckBtnTxt.x = 150; deckBtnTxt.y = HAND_Y - 200; game.addChild(deckBtnTxt); // --- Deck View Screen --- var deckViewScreen = new Container(); var deckViewBg = LK.getAsset('cardBox', { width: 1400, height: 1800, color: 0x2a2a2a, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); deckViewScreen.addChild(deckViewBg); var deckViewTitle = new Text2("DECK CONTENTS", { size: 80, fill: "#fff", fontWeight: "bold" }); deckViewTitle.anchor.set(0.5, 0.5); deckViewTitle.x = 1024; deckViewTitle.y = 600; deckViewScreen.addChild(deckViewTitle); // Card count displays var deckCountTexts = []; for (var i = 0; i < CARD_POOL.length; i++) { var countTxt = new Text2("", { size: 60, fill: "#fff" }); countTxt.anchor.set(0.5, 0.5); countTxt.x = 1024; countTxt.y = 800 + i * 120; deckViewScreen.addChild(countTxt); deckCountTexts.push(countTxt); } deckViewScreen.visible = false; // Function to update deck view function updateDeckView() { // Count cards in deck by ID var cardCounts = {}; for (var i = 0; i < CARD_POOL.length; i++) { cardCounts[CARD_POOL[i].id] = 0; } for (var i = 0; i < playerDeck.length; i++) { var cardId = playerDeck[i].id; if (cardCounts[cardId] !== undefined) { cardCounts[cardId]++; } } // Update text displays for (var i = 0; i < CARD_POOL.length; i++) { var card = CARD_POOL[i]; var count = cardCounts[card.id] || 0; deckCountTexts[i].setText(card.name + ": " + count + " remaining"); } } // Deck button touch handlers deckBtn.interactive = true; deckBtn.buttonMode = true; deckBtn.down = function (x, y, obj) { updateDeckView(); deckViewScreen.visible = true; // Bring deck view to front game.removeChild(deckViewScreen); game.addChild(deckViewScreen); }; deckBtn.up = function (x, y, obj) { deckViewScreen.visible = false; }; // Also add touch handlers to the text for better usability deckBtnTxt.interactive = true; deckBtnTxt.buttonMode = true; deckBtnTxt.down = function (x, y, obj) { updateDeckView(); deckViewScreen.visible = true; // Bring deck view to front game.removeChild(deckViewScreen); game.addChild(deckViewScreen); }; deckBtnTxt.up = function (x, y, obj) { deckViewScreen.visible = false; }; // --- Start the game --- startGame(); // Add deck view screen last to ensure it renders on top game.addChild(deckViewScreen); ;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Card class: represents a single card (creature or resource)
var Card = Container.expand(function () {
var self = Container.call(this);
// Card properties (to be set on creation)
self.cardData = null; // {name, attack, health, cost, type, id}
self.isPlayerCard = true; // true if belongs to player, false if opponent
// Card visual
var cardBox = self.attachAsset('cardBox', {
width: 260,
height: 360,
color: 0x222222,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Card name
var nameTxt = new Text2('', {
size: 48,
fill: "#fff"
});
nameTxt.anchor.set(0.5, 0);
nameTxt.x = 0;
nameTxt.y = -150;
self.addChild(nameTxt);
// Attack/Health with symbols
var statsTxt = new Text2('', {
size: 48,
fill: 0xFFEC70
});
statsTxt.anchor.set(0.5, 0.5);
// Move stats area further to the right
statsTxt.x = 0; // was -50, now centered more right
statsTxt.y = 120;
self.addChild(statsTxt);
// Cost
var costTxt = new Text2('', {
size: 40,
fill: 0xB8B031
});
costTxt.anchor.set(0.5, 0.5);
// Move cost area further to the right
costTxt.x = 120; // was 90, now more right
costTxt.y = 120;
self.addChild(costTxt);
// Set card data and visuals
self.setCard = function (cardData, isPlayerCard) {
self.cardData = cardData;
self.isPlayerCard = isPlayerCard;
nameTxt.setText(cardData.name);
statsTxt.setText("⚔" + cardData.attack + " ♥" + cardData.health);
costTxt.setText(cardData.cost);
// Tint for opponent cards
cardBox.tint = isPlayerCard ? 0x222222 : 0x2a1a2a;
};
// Update stats display
self.updateStats = function () {
if (self.cardData) {
statsTxt.setText("⚔" + self.cardData.attack + " ♥" + self.cardData.health);
}
};
// Flash effect for damage
self.flash = function (color) {
LK.effects.flashObject(self, color, 300);
};
// Selection properties
self.isSelected = false;
return self;
});
// Slot class: represents a board slot (for creatures)
var Slot = Container.expand(function () {
var self = Container.call(this);
self.isPlayerSlot = true;
self.slotIndex = 0;
self.occupied = false;
self.card = null;
var slotBox = self.attachAsset('slotBox', {
width: 270,
height: 380,
color: 0x444444,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Highlight for valid drop
self.setHighlight = function (on) {
slotBox.tint = on ? 0x83de44 : 0x444444;
};
// Place card in slot
self.placeCard = function (card) {
self.card = card;
self.occupied = true;
card.x = self.x;
card.y = self.y;
card.isSelected = false;
card.alpha = 1.0;
game.addChild(card);
};
// Remove card from slot
self.removeCard = function () {
self.card = null;
self.occupied = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x18181a
});
/****
* Game Code
****/
// --- Game Constants ---
var BOARD_COLS = 4;
var PLAYER_Y = 1950;
var OPPONENT_Y = 1150;
var HAND_Y = 2450;
var SLOT_SPACING = 340;
var HAND_SPACING = 320;
var MAX_HAND = 5;
var MAX_HEALTH = 10;
// --- Card Pool ---
var CARD_POOL = [{
id: 1,
name: "Stoat",
attack: 1,
health: 2,
cost: 1,
type: "creature"
}, {
id: 2,
name: "Wolf",
attack: 3,
health: 2,
cost: 2,
type: "creature"
}, {
id: 3,
name: "Bullfrog",
attack: 1,
health: 3,
cost: 1,
type: "creature"
}, {
id: 4,
name: "Adder",
attack: 1,
health: 1,
cost: 2,
type: "creature"
}, {
id: 5,
name: "Squirrel",
attack: 0,
health: 1,
cost: 0,
type: "resource"
},
// New card types
{
id: 6,
name: "Grizzly",
attack: 4,
health: 6,
cost: 3,
type: "creature"
}, {
id: 7,
name: "Raven",
attack: 2,
health: 3,
cost: 2,
type: "creature"
}, {
id: 8,
name: "Elk",
attack: 2,
health: 4,
cost: 2,
type: "creature"
}, {
id: 9,
name: "Rabbit",
attack: 0,
health: 1,
cost: 0,
type: "resource"
}];
// --- Game State ---
var playerDeck = [];
var opponentDeck = [];
var playerHand = [];
var opponentHand = [];
var playerSlots = [];
var opponentSlots = [];
var playerHealth = MAX_HEALTH;
var opponentHealth = MAX_HEALTH;
var turn = "player"; // "player" or "opponent"
// Card selection variables
var selectedCard = null;
var canPlay = true;
var playerResources = 0;
var turnTxt, healthTxt, oppHealthTxt, resourceTxt, messageTxt;
// --- UI Setup ---
// Card list removed
// Life display in top center
var lifeTxt = new Text2("♥ " + playerHealth + " | ♥ " + opponentHealth, {
size: 80,
fill: 0xFF6B6B
});
lifeTxt.anchor.set(0.5, 0);
lifeTxt.y = 20;
LK.gui.top.addChild(lifeTxt);
// Health display (keeping original for backward compatibility)
healthTxt = new Text2("You: " + playerHealth, {
size: 80,
fill: "#fff"
});
healthTxt.anchor.set(0, 0.5);
healthTxt.visible = false; // Hide original health display
LK.gui.top.addChild(healthTxt);
oppHealthTxt = new Text2("Opponent: " + opponentHealth, {
size: 80,
fill: "#fff"
});
oppHealthTxt.anchor.set(1, 0.5);
oppHealthTxt.visible = false; // Hide original health display
LK.gui.topRight.addChild(oppHealthTxt);
// Turn display
turnTxt = new Text2("Your Turn", {
size: 70,
fill: 0xFFEC70
});
turnTxt.anchor.set(0.5, 0.5);
turnTxt.y = 200; // Move lower
LK.gui.top.addChild(turnTxt);
// Resource display
resourceTxt = new Text2("🩸 " + playerResources, {
size: 60,
fill: 0xB8B031
});
resourceTxt.anchor.set(1, 0.5);
resourceTxt.x = -20;
resourceTxt.y = 150;
LK.gui.topRight.addChild(resourceTxt);
// Upper message display removed
// Lower message display removed
// --- End Turn Button ---
// Remove any previous button if present
if (typeof endTurnBtn !== "undefined" && endTurnBtn.parent) {
endTurnBtn.parent.removeChild(endTurnBtn);
}
endTurnBtn = LK.getAsset('centerCircle', {
width: 150,
height: 150,
color: 0xff0000,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5,
x: 1900,
y: 1366
});
game.addChild(endTurnBtn);
// End turn button logic
endTurnBtn.interactive = true;
endTurnBtn.buttonMode = true;
endTurnBtn.visible = turn === "player";
endTurnBtn.down = function (x, y, obj) {
if (turn === "player" && canPlay) {
canPlay = false;
endTurnBtn.visible = false;
// Message displays removed
LK.setTimeout(startOpponentTurn, 400);
}
};
// --- Board Setup ---
// Player slots
for (var i = 0; i < BOARD_COLS; i++) {
var slot = new Slot();
slot.isPlayerSlot = true;
slot.slotIndex = i;
slot.x = 400 + i * SLOT_SPACING;
slot.y = PLAYER_Y;
playerSlots.push(slot);
game.addChild(slot);
}
// Opponent slots
for (var i = 0; i < BOARD_COLS; i++) {
var slot = new Slot();
slot.isPlayerSlot = false;
slot.slotIndex = i;
slot.x = 400 + i * SLOT_SPACING;
slot.y = OPPONENT_Y;
opponentSlots.push(slot);
game.addChild(slot);
}
// --- Deck/Hand Setup ---
function shuffleDeck(deck) {
for (var i = deck.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
function createDeck() {
// Player: 2 Stoat, 2 Wolf, 2 Bullfrog, 1 Adder, 3 Squirrel
var deck = [];
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[0]);
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[1]);
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[2]);
deck.push(CARD_POOL[3]);
for (var i = 0; i < 3; i++) deck.push(CARD_POOL[4]);
shuffleDeck(deck);
return deck.slice();
}
function createOpponentDeck() {
// Opponent: 2 Wolf, 2 Bullfrog, 2 Adder, 2 Squirrel
var deck = [];
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[1]);
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[2]);
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[3]);
for (var i = 0; i < 2; i++) deck.push(CARD_POOL[4]);
shuffleDeck(deck);
return deck.slice();
}
// --- Hand Display ---
function updateHandDisplay() {
// Remove all player hand cards from game
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i].parent) playerHand[i].parent.removeChild(playerHand[i]);
}
// Layout hand - align with board slots
for (var i = 0; i < playerHand.length; i++) {
var card = playerHand[i];
card.x = 400 + i * SLOT_SPACING;
card.y = HAND_Y;
card.isPlayerCard = true;
game.addChild(card);
}
}
function updateOpponentHandDisplay() {
// Remove all opponent hand cards from game
for (var i = 0; i < opponentHand.length; i++) {
if (opponentHand[i].parent) opponentHand[i].parent.removeChild(opponentHand[i]);
}
// Layout hand (hidden) - align with board slots
for (var i = 0; i < opponentHand.length; i++) {
var card = opponentHand[i];
card.x = 400 + i * SLOT_SPACING;
card.y = OPPONENT_Y - 400;
card.isPlayerCard = false;
game.addChild(card);
}
}
// --- Draw Card ---
function drawCard(deck, hand, isPlayer) {
if (deck.length === 0 || hand.length >= MAX_HAND) return;
var cardData = deck.shift();
var card = new Card();
card.setCard(cardData, isPlayer);
hand.push(card);
}
// --- Start Game ---
function startGame() {
playerDeck = createDeck();
opponentDeck = createOpponentDeck();
playerHand = [];
opponentHand = [];
playerHealth = MAX_HEALTH;
opponentHealth = MAX_HEALTH;
playerResources = 0;
turn = "player";
canPlay = true;
// Message displays removed
// Remove all cards from slots
for (var i = 0; i < BOARD_COLS; i++) {
if (playerSlots[i].card) {
playerSlots[i].card.destroy();
playerSlots[i].removeCard();
}
if (opponentSlots[i].card) {
opponentSlots[i].card.destroy();
opponentSlots[i].removeCard();
}
}
// Draw initial hands
for (var i = 0; i < 4; i++) drawCard(playerDeck, playerHand, true);
for (var i = 0; i < 4; i++) drawCard(opponentDeck, opponentHand, false);
updateHandDisplay();
updateOpponentHandDisplay();
updateUI();
}
function updateUI() {
healthTxt.setText("You: " + playerHealth);
oppHealthTxt.setText("Opponent: " + opponentHealth);
if (typeof lifeTxt !== "undefined") {
lifeTxt.setText("♥ " + playerHealth + " | ♥ " + opponentHealth);
}
resourceTxt.setText("🩸 " + playerResources);
turnTxt.setText(turn === "player" ? "Your Turn" : "Opponent Turn");
}
// --- Turn Logic ---
function startPlayerTurn() {
turn = "player";
canPlay = true;
drawCard(playerDeck, playerHand, true);
updateHandDisplay();
updateUI();
// Message displays removed
if (typeof endTurnBtn !== "undefined") {
endTurnBtn.visible = true;
}
}
function startOpponentTurn() {
turn = "opponent";
canPlay = false;
updateUI();
// Message displays removed
if (typeof endTurnBtn !== "undefined") {
endTurnBtn.visible = false;
}
LK.setTimeout(opponentPlay, 900);
}
// --- Play Card ---
function canPlayCard(card, slot) {
if (!card || !slot) return false;
if (!slot.isPlayerSlot) return false;
if (slot.occupied) return false;
if (card.cardData.type === "resource") return true;
// For creatures, check if we have enough blood or creatures to sacrifice
if (card.cardData.type === "creature") {
// If we have enough blood, we can play
if (playerResources >= card.cardData.cost) return true;
// Count available creatures for sacrifice (excluding the target slot and squirrels)
var creaturesOnBoard = 0;
for (var i = 0; i < playerSlots.length; i++) {
if (playerSlots[i].card && playerSlots[i].card.cardData.type === "creature" && playerSlots[i] !== slot && playerSlots[i].card.cardData.id !== 5) {
creaturesOnBoard++;
}
}
// Check if we have enough creatures to sacrifice to cover the remaining cost
var bloodNeeded = card.cardData.cost - playerResources;
if (creaturesOnBoard >= bloodNeeded) return true;
}
return false;
}
function playCard(card, slot) {
if (!canPlayCard(card, slot)) return false;
// Remove from hand
var idx = playerHand.indexOf(card);
if (idx !== -1) playerHand.splice(idx, 1);
// Place in slot
slot.placeCard(card);
// Pay cost
if (card.cardData.type === "creature") {
if (playerResources >= card.cardData.cost) {
playerResources -= card.cardData.cost;
} else {
// Sacrifice creatures for blood (excluding squirrels)
var costRemaining = card.cardData.cost;
for (var i = 0; i < playerSlots.length && costRemaining > 0; i++) {
if (playerSlots[i].card && playerSlots[i].card.cardData.type === "creature" && playerSlots[i] !== slot && playerSlots[i].card.cardData.id !== 5) {
var sacrificeCard = playerSlots[i].card;
sacrificeCard.flash(0xd83318);
LK.setTimeout(function (slotToRemove, cardToDestroy) {
return function () {
slotToRemove.removeCard();
cardToDestroy.destroy();
};
}(playerSlots[i], sacrificeCard), 300);
costRemaining--;
}
}
}
}
// Squirrel: resource, gives +1 blood, then disappears
if (card.cardData.type === "resource") {
playerResources += 1;
card.flash(0xb8b031);
LK.setTimeout(function () {
slot.removeCard();
card.destroy();
}, 400);
}
updateHandDisplay();
updateUI();
return true;
}
// --- Card Sacrifice Selection ---
var selectedCardForSacrifice = null;
var sacrificeHighlight = null;
// Helper to clear sacrifice selection
function clearSacrificeSelection() {
if (selectedCardForSacrifice) {
// Remove highlight if any
if (sacrificeHighlight && sacrificeHighlight.parent) {
sacrificeHighlight.parent.removeChild(sacrificeHighlight);
}
sacrificeHighlight = null;
selectedCardForSacrifice = null;
// Clear all slot highlights
for (var i = 0; i < playerSlots.length; i++) {
playerSlots[i].setHighlight(false);
}
}
}
// Helper to highlight a card for sacrifice
function highlightCardForSacrifice(card) {
if (sacrificeHighlight && sacrificeHighlight.parent) {
sacrificeHighlight.parent.removeChild(sacrificeHighlight);
}
sacrificeHighlight = LK.getAsset('centerCircle', {
width: 280,
height: 380,
color: 0x00ff00,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: card.x,
y: card.y
});
sacrificeHighlight.alpha = 0.3;
// Place highlight below the card
if (card.parent) {
card.parent.addChildAt(sacrificeHighlight, 0);
}
// Highlight all slots to show where the card can be moved (both empty and occupied for replacement)
for (var i = 0; i < playerSlots.length; i++) {
playerSlots[i].setHighlight(true);
}
}
// Helper function to clear card selection
function clearCardSelection() {
if (selectedCard) {
selectedCard.isSelected = false;
// Remove any visual selection indicator
selectedCard.alpha = 1.0;
selectedCard = null;
// Clear slot highlights
for (var i = 0; i < playerSlots.length; i++) {
playerSlots[i].setHighlight(false);
}
}
}
// Helper function to select a card
function selectCard(card) {
clearCardSelection();
selectedCard = card;
card.isSelected = true;
// Visual feedback for selected card
card.alpha = 0.7;
// Highlight available slots
for (var i = 0; i < playerSlots.length; i++) {
if (!playerSlots[i].occupied) {
playerSlots[i].setHighlight(true);
}
}
}
// Click-based card selection and placement
game.down = function (x, y, obj) {
// If we have a card already selected, check if clicking on a slot to place it
if (selectedCard) {
// Check if clicked on a slot
for (var i = 0; i < playerSlots.length; i++) {
var slot = playerSlots[i];
var slotWidth = 270;
var slotHeight = 380;
var isInside = x >= slot.x - slotWidth / 2 && x <= slot.x + slotWidth / 2 && y >= slot.y - slotHeight / 2 && y <= slot.y + slotHeight / 2;
if (!slot.occupied && isInside) {
// Check if we can play this card (including blood cost check)
if (canPlayCard(selectedCard, slot)) {
// Play the selected card
playCard(selectedCard, slot);
clearCardSelection();
return;
} else {
// Flash red to indicate insufficient resources
LK.effects.flashObject(selectedCard, 0xff0000, 500);
clearCardSelection();
return;
}
}
}
// If clicked elsewhere, clear selection
clearCardSelection();
return;
}
// Check for sacrifice selection first (high-cost cards that need sacrifice)
if (selectedCardForSacrifice) {
// Check if clicked on a slot
for (var i = 0; i < playerSlots.length; i++) {
var slot = playerSlots[i];
var slotWidth = 270;
var slotHeight = 380;
var isInside = x >= slot.x - slotWidth / 2 && x <= slot.x + slotWidth / 2 && y >= slot.y - slotHeight / 2 && y <= slot.y + slotHeight / 2;
if (isInside) {
// Check if we can sacrifice creatures for this card
var card = selectedCardForSacrifice;
var totalCostRequired = card.cardData.cost;
// If slot is occupied, calculate replacement cost
if (slot.occupied && slot.card.cardData.type === "creature") {
var existingCard = slot.card;
// Higher cost cards require more sacrifice, lower cost cards reduce requirement
var costDifference = totalCostRequired - existingCard.cardData.cost;
totalCostRequired = Math.max(0, costDifference);
}
var bloodRequired = totalCostRequired - playerResources;
// Count available creatures for sacrifice (excluding source slot, target slot, and squirrels)
var availableCreatures = [];
for (var j = 0; j < playerSlots.length; j++) {
if (playerSlots[j].card && playerSlots[j].card.cardData.type === "creature" && playerSlots[j].card !== card && playerSlots[j] !== slot && playerSlots[j].card.cardData.id !== 5) {
availableCreatures.push(playerSlots[j]);
}
}
// Check if we have enough creatures to sacrifice
if (bloodRequired <= 0 || availableCreatures.length >= bloodRequired) {
// Remove from hand if in hand
var idx = playerHand.indexOf(card);
if (idx !== -1) playerHand.splice(idx, 1);
// Remove existing card from target slot if occupied (this counts as part of the sacrifice)
if (slot.occupied && slot.card.cardData.type === "creature") {
var replacedCard = slot.card;
replacedCard.flash(0xd83318);
LK.setTimeout(function (cardToDestroy) {
return function () {
cardToDestroy.destroy();
};
}(replacedCard), 300);
slot.removeCard();
}
// Remove from old slot if it was on board
var wasOnBoard = false;
for (var j = 0; j < playerSlots.length; j++) {
if (playerSlots[j].card === card) {
playerSlots[j].removeCard();
wasOnBoard = true;
break;
}
}
// Sacrifice creatures if needed (using blood first)
var remainingCost = totalCostRequired;
remainingCost -= playerResources;
playerResources = Math.max(0, playerResources - totalCostRequired);
if (remainingCost > 0) {
// Sacrifice creatures
for (var k = 0; k < availableCreatures.length && remainingCost > 0; k++) {
var sacrificeSlot = availableCreatures[k];
var sacrificeCard = sacrificeSlot.card;
sacrificeCard.flash(0xd83318);
LK.setTimeout(function (slotToRemove, cardToDestroy) {
return function () {
slotToRemove.removeCard();
cardToDestroy.destroy();
};
}(sacrificeSlot, sacrificeCard), 300);
remainingCost--;
}
}
slot.placeCard(card);
clearSacrificeSelection();
updateHandDisplay();
updateUI();
return;
} else {
// Not enough resources - flash red
LK.effects.flashObject(card, 0xff0000, 500);
clearSacrificeSelection();
return;
}
}
}
// If not clicked on a slot, clear selection
clearSacrificeSelection();
return;
}
// Check if a card in hand is clicked for selection
for (var i = 0; i < playerHand.length; i++) {
var card = playerHand[i];
var cardWidth = 260;
var cardHeight = 360;
var isInside = x >= card.x - cardWidth / 2 && x <= card.x + cardWidth / 2 && y >= card.y - cardHeight / 2 && y <= card.y + cardHeight / 2;
if (isInside && turn === "player" && canPlay) {
// Check if this card requires sacrifice
if (card.cardData.type === "creature" && card.cardData.cost > playerResources) {
// This card requires sacrifice - use sacrifice system
selectedCardForSacrifice = card;
highlightCardForSacrifice(card);
return;
} else {
// Regular card selection
selectCard(card);
return;
}
}
}
// Check if a card on the board is clicked for selection (only if turn is player and can play)
if (turn === "player" && canPlay) {
for (var i = 0; i < playerSlots.length; i++) {
if (playerSlots[i].card && playerSlots[i].card.cardData.type === "creature") {
var card = playerSlots[i].card;
var cardWidth = 260;
var cardHeight = 360;
var isInside = x >= card.x - cardWidth / 2 && x <= card.x + cardWidth / 2 && y >= card.y - cardHeight / 2 && y <= card.y + cardHeight / 2;
if (isInside) {
// Only select for sacrifice if it's a high-cost creature that can be moved
// or if we need to sacrifice it for another card
selectedCardForSacrifice = card;
highlightCardForSacrifice(card);
return;
}
}
}
}
};
// No up handler needed for click-based system
// --- Combat Phase ---
function combatPhase() {
// Player creatures attack
for (var i = 0; i < BOARD_COLS; i++) {
var pSlot = playerSlots[i];
if (pSlot.card && pSlot.card.cardData.type === "creature") {
var oppSlot = opponentSlots[i];
if (oppSlot.card && oppSlot.card.cardData.type === "creature") {
// Attack opposing creature
oppSlot.card.cardData.health -= pSlot.card.cardData.attack;
pSlot.card.flash(0xffec70);
oppSlot.card.flash(0xd83318);
oppSlot.card.updateStats();
if (oppSlot.card.cardData.health <= 0) {
LK.setTimeout(function (slot, card) {
return function () {
slot.removeCard();
card.destroy();
};
}(oppSlot, oppSlot.card), 300);
}
} else {
// Attack opponent directly
opponentHealth -= pSlot.card.cardData.attack;
if (opponentHealth < 0) opponentHealth = 0;
}
}
}
// Opponent creatures attack
for (var i = 0; i < BOARD_COLS; i++) {
var oSlot = opponentSlots[i];
if (oSlot.card && oSlot.card.cardData.type === "creature") {
var pSlot = playerSlots[i];
if (pSlot.card && pSlot.card.cardData.type === "creature") {
// Attack opposing creature
pSlot.card.cardData.health -= oSlot.card.cardData.attack;
oSlot.card.flash(0xffec70);
pSlot.card.flash(0xd83318);
pSlot.card.updateStats();
if (pSlot.card.cardData.health <= 0) {
LK.setTimeout(function (slot, card) {
return function () {
slot.removeCard();
card.destroy();
};
}(pSlot, pSlot.card), 300);
}
} else {
// Attack player directly
playerHealth -= oSlot.card.cardData.attack;
if (playerHealth < 0) playerHealth = 0;
}
}
}
updateUI();
// Check win/lose
if (playerHealth <= 0) {
LK.effects.flashScreen(0xd83318, 1000);
LK.showGameOver();
return;
}
if (opponentHealth <= 0) {
LK.effects.flashScreen(0x83de44, 1000);
LK.showYouWin();
return;
}
// Next turn
if (turn === "player") {
LK.setTimeout(startOpponentTurn, 900);
} else {
LK.setTimeout(startPlayerTurn, 900);
}
}
// --- Opponent AI ---
function opponentPlay() {
// Play first playable creature to empty slot
var played = false;
for (var i = 0; i < opponentHand.length; i++) {
var card = opponentHand[i];
if (card.cardData.type === "creature") {
for (var j = 0; j < BOARD_COLS; j++) {
var slot = opponentSlots[j];
if (!slot.occupied) {
// Play card
opponentHand.splice(i, 1);
slot.placeCard(card);
played = true;
break;
}
}
if (played) break;
}
}
// Draw a card
drawCard(opponentDeck, opponentHand, false);
updateOpponentHandDisplay();
LK.setTimeout(combatPhase, 900);
}
// --- Game Update ---
game.update = function () {
// No per-frame logic needed for MVP
};
// --- Deck Button ---
var deckBtn = LK.getAsset('cardBox', {
width: 120,
height: 160,
color: 0x4a4a4a,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: HAND_Y - 200
});
game.addChild(deckBtn);
// Deck button label
var deckBtnTxt = new Text2("DECK", {
size: 36,
fill: "#fff"
});
deckBtnTxt.anchor.set(0.5, 0.5);
deckBtnTxt.x = 150;
deckBtnTxt.y = HAND_Y - 200;
game.addChild(deckBtnTxt);
// --- Deck View Screen ---
var deckViewScreen = new Container();
var deckViewBg = LK.getAsset('cardBox', {
width: 1400,
height: 1800,
color: 0x2a2a2a,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
deckViewScreen.addChild(deckViewBg);
var deckViewTitle = new Text2("DECK CONTENTS", {
size: 80,
fill: "#fff",
fontWeight: "bold"
});
deckViewTitle.anchor.set(0.5, 0.5);
deckViewTitle.x = 1024;
deckViewTitle.y = 600;
deckViewScreen.addChild(deckViewTitle);
// Card count displays
var deckCountTexts = [];
for (var i = 0; i < CARD_POOL.length; i++) {
var countTxt = new Text2("", {
size: 60,
fill: "#fff"
});
countTxt.anchor.set(0.5, 0.5);
countTxt.x = 1024;
countTxt.y = 800 + i * 120;
deckViewScreen.addChild(countTxt);
deckCountTexts.push(countTxt);
}
deckViewScreen.visible = false;
// Function to update deck view
function updateDeckView() {
// Count cards in deck by ID
var cardCounts = {};
for (var i = 0; i < CARD_POOL.length; i++) {
cardCounts[CARD_POOL[i].id] = 0;
}
for (var i = 0; i < playerDeck.length; i++) {
var cardId = playerDeck[i].id;
if (cardCounts[cardId] !== undefined) {
cardCounts[cardId]++;
}
}
// Update text displays
for (var i = 0; i < CARD_POOL.length; i++) {
var card = CARD_POOL[i];
var count = cardCounts[card.id] || 0;
deckCountTexts[i].setText(card.name + ": " + count + " remaining");
}
}
// Deck button touch handlers
deckBtn.interactive = true;
deckBtn.buttonMode = true;
deckBtn.down = function (x, y, obj) {
updateDeckView();
deckViewScreen.visible = true;
// Bring deck view to front
game.removeChild(deckViewScreen);
game.addChild(deckViewScreen);
};
deckBtn.up = function (x, y, obj) {
deckViewScreen.visible = false;
};
// Also add touch handlers to the text for better usability
deckBtnTxt.interactive = true;
deckBtnTxt.buttonMode = true;
deckBtnTxt.down = function (x, y, obj) {
updateDeckView();
deckViewScreen.visible = true;
// Bring deck view to front
game.removeChild(deckViewScreen);
game.addChild(deckViewScreen);
};
deckBtnTxt.up = function (x, y, obj) {
deckViewScreen.visible = false;
};
// --- Start the game ---
startGame();
// Add deck view screen last to ensure it renders on top
game.addChild(deckViewScreen);
;