User prompt
When we click and select the card, we can either spend our blood value and put the card in the card slot, or we can use the card in the card slot to replace the card we sacrificed in that card slot, of course the card with the higher card cost will demand more cards.
User prompt
If the blood value is not sufficient, the card should not be placed in the card slot.
User prompt
delete the card dragging event just click select the card select one of the compartments to put the card click put and solve possible bugs
User prompt
Let me click on the card I want to sacrifice. We need to select a card that requires high level blood points and when we click on a card once, it will be selected and when we click on its destination, it will go.
User prompt
Let me click on the card I want to sacrifice. We need to select a card that requires high level blood points and when we click on a card once, it will be selected and when we click on its destination, it will go.
User prompt
Let me click on the card I want to sacrifice. We need to select a card that requires high level blood points and when we click on a card once, it will be selected and when we click on its destination, it will go.
User prompt
move your opponent's cards up a little
User prompt
move your opponent's cards up a little
User prompt
move your opponent's cards up a little
User prompt
Lower your opponent's card placement area a little and move my cards up a little
User prompt
Your opponent's cards may go up a little
User prompt
The opponent's card placement area may go a little lower, while our placement area and cards may go a little higher.
User prompt
The amount of blood should not increase at the end of each round
User prompt
When you kill an enemy, there should be no bloodshed.
User prompt
Put the blood area on the right corner of the screen, move the life area on the cards a little more to the right than the area where the card is, and likewise move the attack area a little more to the right, do this for all cards.
User prompt
Put the blood area on the left corner of the screen, the life area on the cards should be slightly left from the area where the card is, and the attack part should be the same.
User prompt
end turn key into a red ball keep its function the same
User prompt
Nothing should cover the front of the deck screen. Let the deck screen be at the front.
User prompt
To find out what is left in our deck, let's have a deck next to us, when we hold it down, a screen will appear in front of us, telling us how many of each card are left, and when we take our hand off the deck button, it will go to that screen.
User prompt
Delete the text in the middle of the screen and delete the your cards section next to the stop button.
User prompt
Please move the blue areas where your opponent will place cards a little lower and also move the cards a little lower, as well as your health bar and your turn area, and divide the text in the middle of the screen into two.
User prompt
I don't understand which of the cards are life and which are attack. Fix it by indicating it with symbols and also put the end round button next to the screen.
User prompt
fix all the bugs, list the texts on the left corner of the screen, tell me why I don't have your cards, and add life logic, and include sacrifice logic.
User prompt
Fix the screens, the screen is very confusing and we press a button to give the turn to the other person, the button is on the side.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'containsPoint')' in or related to this line: 'if (!slot.occupied && LK.util.containsPoint(slot, {' Line Number: 485
/**** * 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 var statsTxt = new Text2('', { size: 48, fill: 0xFFEC70 }); statsTxt.anchor.set(0.5, 0.5); statsTxt.x = -70; statsTxt.y = 120; self.addChild(statsTxt); // Cost var costTxt = new Text2('', { size: 40, fill: 0xB8B031 }); costTxt.anchor.set(0.5, 0.5); costTxt.x = 70; 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); }; // Dragging self.isDraggable = false; self.isDragging = false; // Touch events self.down = function (x, y, obj) { if (self.isDraggable && !self.isDragging) { self.isDragging = true; dragCard = self; dragOrigin = { x: self.x, y: self.y }; // Bring to front if (self.parent) { self.parent.removeChild(self); game.addChild(self); } } }; self.up = function (x, y, obj) { if (self.isDragging) { self.isDragging = false; dragCard = null; // Snap back if not played if (!self.justPlayed) { tween(self, { x: dragOrigin.x, y: dragOrigin.y }, { duration: 200, easing: tween.easeOut }); } self.justPlayed = 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.isDraggable = false; card.isDragging = false; card.justPlayed = true; 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 = 2100; var OPPONENT_Y = 700; var HAND_Y = 2500; 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" }]; // --- 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" var dragCard = null; var dragOrigin = null; var validDropSlot = null; var canPlay = true; var playerResources = 0; var turnTxt, healthTxt, oppHealthTxt, resourceTxt, messageTxt; // --- UI Setup --- // Health display healthTxt = new Text2("You: " + playerHealth, { size: 80, fill: "#fff" }); healthTxt.anchor.set(0, 0.5); LK.gui.top.addChild(healthTxt); oppHealthTxt = new Text2("Opponent: " + opponentHealth, { size: 80, fill: "#fff" }); oppHealthTxt.anchor.set(1, 0.5); LK.gui.topRight.addChild(oppHealthTxt); // Turn display turnTxt = new Text2("Your Turn", { size: 70, fill: 0xFFEC70 }); turnTxt.anchor.set(0.5, 0.5); LK.gui.top.addChild(turnTxt); // Resource display resourceTxt = new Text2("Blood: " + playerResources, { size: 60, fill: 0xB8B031 }); resourceTxt.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(resourceTxt); // Message display messageTxt = new Text2("", { size: 60, fill: 0xFFEC70 }); messageTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(messageTxt); // --- 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 for (var i = 0; i < playerHand.length; i++) { var card = playerHand[i]; card.x = 400 + i * HAND_SPACING; card.y = HAND_Y; card.isDraggable = canPlay && turn === "player"; 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) for (var i = 0; i < opponentHand.length; i++) { var card = opponentHand[i]; card.x = 400 + i * HAND_SPACING; card.y = OPPONENT_Y - 250; card.isDraggable = false; 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; messageTxt.setText(""); // 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); resourceTxt.setText("Blood: " + playerResources); turnTxt.setText(turn === "player" ? "Your Turn" : "Opponent Turn"); } // --- Turn Logic --- function startPlayerTurn() { turn = "player"; canPlay = true; playerResources += 1; drawCard(playerDeck, playerHand, true); updateHandDisplay(); updateUI(); messageTxt.setText("Your turn. Drag a card to a slot."); } function startOpponentTurn() { turn = "opponent"; canPlay = false; updateUI(); messageTxt.setText("Opponent's turn..."); 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; if (playerResources >= card.cardData.cost) 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") { playerResources -= card.cardData.cost; } // 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; } // --- Drag & Drop --- game.move = function (x, y, obj) { if (dragCard && dragCard.isDragging) { dragCard.x = x; dragCard.y = y; // Highlight valid slot var found = null; for (var i = 0; i < playerSlots.length; i++) { var slot = playerSlots[i]; var isInside = false; // Defensive: check if LK.util.containsPoint exists and is a function if (typeof LK.util !== "undefined" && typeof LK.util.containsPoint === "function") { isInside = LK.util.containsPoint(slot, { x: x, y: y }); } else if (typeof slot.containsPoint === "function") { // fallback for legacy or engine update isInside = slot.containsPoint({ x: x, y: y }); } if (!slot.occupied && isInside) { found = slot; slot.setHighlight(true); } else { slot.setHighlight(false); } } validDropSlot = found; } }; game.down = function (x, y, obj) { // No-op: handled by Card.down }; game.up = function (x, y, obj) { if (dragCard && dragCard.isDragging) { // Try to play card if (validDropSlot && canPlayCard(dragCard, validDropSlot)) { playCard(dragCard, validDropSlot); dragCard.justPlayed = true; validDropSlot.setHighlight(false); } else { // Snap back dragCard.justPlayed = false; } dragCard.isDragging = false; dragCard = null; validDropSlot = null; for (var i = 0; i < playerSlots.length; i++) playerSlots[i].setHighlight(false); } }; // --- 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) { oppSlot.card.flash(0xd83318); 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) { pSlot.card.flash(0xd83318); 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 }; // --- Start the game --- startGame();
/****
* 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
var statsTxt = new Text2('', {
size: 48,
fill: 0xFFEC70
});
statsTxt.anchor.set(0.5, 0.5);
statsTxt.x = -70;
statsTxt.y = 120;
self.addChild(statsTxt);
// Cost
var costTxt = new Text2('', {
size: 40,
fill: 0xB8B031
});
costTxt.anchor.set(0.5, 0.5);
costTxt.x = 70;
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);
};
// Dragging
self.isDraggable = false;
self.isDragging = false;
// Touch events
self.down = function (x, y, obj) {
if (self.isDraggable && !self.isDragging) {
self.isDragging = true;
dragCard = self;
dragOrigin = {
x: self.x,
y: self.y
};
// Bring to front
if (self.parent) {
self.parent.removeChild(self);
game.addChild(self);
}
}
};
self.up = function (x, y, obj) {
if (self.isDragging) {
self.isDragging = false;
dragCard = null;
// Snap back if not played
if (!self.justPlayed) {
tween(self, {
x: dragOrigin.x,
y: dragOrigin.y
}, {
duration: 200,
easing: tween.easeOut
});
}
self.justPlayed = 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.isDraggable = false;
card.isDragging = false;
card.justPlayed = true;
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 = 2100;
var OPPONENT_Y = 700;
var HAND_Y = 2500;
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"
}];
// --- 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"
var dragCard = null;
var dragOrigin = null;
var validDropSlot = null;
var canPlay = true;
var playerResources = 0;
var turnTxt, healthTxt, oppHealthTxt, resourceTxt, messageTxt;
// --- UI Setup ---
// Health display
healthTxt = new Text2("You: " + playerHealth, {
size: 80,
fill: "#fff"
});
healthTxt.anchor.set(0, 0.5);
LK.gui.top.addChild(healthTxt);
oppHealthTxt = new Text2("Opponent: " + opponentHealth, {
size: 80,
fill: "#fff"
});
oppHealthTxt.anchor.set(1, 0.5);
LK.gui.topRight.addChild(oppHealthTxt);
// Turn display
turnTxt = new Text2("Your Turn", {
size: 70,
fill: 0xFFEC70
});
turnTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(turnTxt);
// Resource display
resourceTxt = new Text2("Blood: " + playerResources, {
size: 60,
fill: 0xB8B031
});
resourceTxt.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(resourceTxt);
// Message display
messageTxt = new Text2("", {
size: 60,
fill: 0xFFEC70
});
messageTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(messageTxt);
// --- 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
for (var i = 0; i < playerHand.length; i++) {
var card = playerHand[i];
card.x = 400 + i * HAND_SPACING;
card.y = HAND_Y;
card.isDraggable = canPlay && turn === "player";
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)
for (var i = 0; i < opponentHand.length; i++) {
var card = opponentHand[i];
card.x = 400 + i * HAND_SPACING;
card.y = OPPONENT_Y - 250;
card.isDraggable = false;
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;
messageTxt.setText("");
// 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);
resourceTxt.setText("Blood: " + playerResources);
turnTxt.setText(turn === "player" ? "Your Turn" : "Opponent Turn");
}
// --- Turn Logic ---
function startPlayerTurn() {
turn = "player";
canPlay = true;
playerResources += 1;
drawCard(playerDeck, playerHand, true);
updateHandDisplay();
updateUI();
messageTxt.setText("Your turn. Drag a card to a slot.");
}
function startOpponentTurn() {
turn = "opponent";
canPlay = false;
updateUI();
messageTxt.setText("Opponent's turn...");
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;
if (playerResources >= card.cardData.cost) 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") {
playerResources -= card.cardData.cost;
}
// 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;
}
// --- Drag & Drop ---
game.move = function (x, y, obj) {
if (dragCard && dragCard.isDragging) {
dragCard.x = x;
dragCard.y = y;
// Highlight valid slot
var found = null;
for (var i = 0; i < playerSlots.length; i++) {
var slot = playerSlots[i];
var isInside = false;
// Defensive: check if LK.util.containsPoint exists and is a function
if (typeof LK.util !== "undefined" && typeof LK.util.containsPoint === "function") {
isInside = LK.util.containsPoint(slot, {
x: x,
y: y
});
} else if (typeof slot.containsPoint === "function") {
// fallback for legacy or engine update
isInside = slot.containsPoint({
x: x,
y: y
});
}
if (!slot.occupied && isInside) {
found = slot;
slot.setHighlight(true);
} else {
slot.setHighlight(false);
}
}
validDropSlot = found;
}
};
game.down = function (x, y, obj) {
// No-op: handled by Card.down
};
game.up = function (x, y, obj) {
if (dragCard && dragCard.isDragging) {
// Try to play card
if (validDropSlot && canPlayCard(dragCard, validDropSlot)) {
playCard(dragCard, validDropSlot);
dragCard.justPlayed = true;
validDropSlot.setHighlight(false);
} else {
// Snap back
dragCard.justPlayed = false;
}
dragCard.isDragging = false;
dragCard = null;
validDropSlot = null;
for (var i = 0; i < playerSlots.length; i++) playerSlots[i].setHighlight(false);
}
};
// --- 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) {
oppSlot.card.flash(0xd83318);
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) {
pSlot.card.flash(0xd83318);
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
};
// --- Start the game ---
startGame();