User prompt
the damage animations must be bigger and slower ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the enemy always block two damage
User prompt
more
User prompt
Health and Resource Bars**: Make these more thematic, possibly with a design that reflects the game's fantasy elements. Ensure they are large enough to be easily visible and positioned intuitively
User prompt
Move it a little up
User prompt
Make it bigger
User prompt
Now I cant see my own health bar. Move it to the buttom
User prompt
I need the cards to have a "image area" which takes up most of the top part of the card. The buttom part should be white and reserved for text, making it easier to read. MTG or Flesh and blood
User prompt
i need to be able to add individual images for earch card front. Divide all different cards into unique assets
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'resources')' in or related to this line: 'resourceIndicator = new Text2("Resources: " + playerHero.resources, {' Line Number: 338
User prompt
make a "resource indicator" on the right side that show the available resources after a player pitch
User prompt
Change the word discard to pitch
User prompt
Make it so that once a player has comited cards to an attack, the opponent can choose to block with their cards
User prompt
make the hand size 4 cards only when starting a game
User prompt
at the start of a turn, a player should draw to have minimum and maximum 4 cards
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'effectMsg.style.fill = "#ff3333";' Line Number: 972
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'effectMsg.style.fill = "#ff3333";' Line Number: 969
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'effectMsg.style.fill = "#ff3333";' Line Number: 971
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'effectMsg.style.fill = "#ff3333";' Line Number: 969
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'effectMsg.style.fill = "#ff3333";' Line Number: 971
Initial prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'effectMsg.style.fill = "#ff3333";' Line Number: 965
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, gamesPlayed: 0 }); /**** * Classes ****/ // Button class for game controls var Button = Container.expand(function (text, width, height) { var self = Container.call(this); self.isEnabled = true; // Button background self.background = self.attachAsset('buttonBg', { anchorX: 0.5, anchorY: 0.5, width: width || 200, height: height || 80 }); // Button text self.text = new Text2(text || "Button", { size: 28, fill: 0xFFFFFF }); self.text.anchor.set(0.5, 0.5); self.addChild(self.text); // Interaction handlers self.down = function (x, y, obj) { if (self.isEnabled) { self.background.alpha = 0.7; } }; self.up = function (x, y, obj) { if (self.isEnabled) { self.background.alpha = 1; if (typeof self.onClick === 'function') { self.onClick(); } } }; // Enable/disable the button self.setEnabled = function (enabled) { self.isEnabled = enabled; self.alpha = enabled ? 1 : 0.5; }; return self; }); // Card class to represent game cards var Card = Container.expand(function (type, value, name, description) { var self = Container.call(this); // Card properties self.type = type || 'attack'; // attack, defense, utility self.value = value || 1; // primary value (attack/defense/resource) self.name = name || 'Basic Card'; self.description = description || 'A basic card'; self.isPlayable = true; self.isSelected = false; // Visual elements self.background = self.attachAsset('cardFront', { anchorX: 0.5, anchorY: 0.5 }); // Card title self.titleText = new Text2(self.name, { size: 24, fill: 0x000000 }); self.titleText.anchor.set(0.5, 0); self.titleText.y = -150; self.addChild(self.titleText); // Card value and type var typeColors = { attack: '#ff3333', defense: '#3399ff', utility: '#33cc33' }; self.valueText = new Text2(self.value.toString(), { size: 40, fill: typeColors[self.type] || "#000000" }); self.valueText.anchor.set(0.5, 0.5); self.valueText.y = -70; self.addChild(self.valueText); // Card type icon var iconType = self.type === 'attack' ? 'attackIcon' : self.type === 'defense' ? 'defenseIcon' : 'resourceIcon'; self.typeIcon = self.attachAsset(iconType, { anchorX: 0.5, anchorY: 0.5, x: 0, y: -20 }); // Description text self.descText = new Text2(self.description, { size: 18, fill: 0x333333 }); self.descText.anchor.set(0.5, 0); self.descText.y = 20; self.descText.x = 0; // Limit text width if (self.descText.width > 230) { self.descText.scale.set(230 / self.descText.width); } self.addChild(self.descText); // Resource value (all cards can be discarded for resources) self.resourceValue = Math.max(1, Math.floor(self.value / 2)); self.resourceText = new Text2("R: " + self.resourceValue, { size: 24, fill: 0xFFCC00 }); self.resourceText.anchor.set(0.5, 1); self.resourceText.y = 140; self.addChild(self.resourceText); // Highlight for selection self.highlight = self.attachAsset('cardHighlight', { anchorX: 0.5, anchorY: 0.5 }); self.highlight.alpha = 0; // Card interaction events self.down = function (x, y, obj) { if (self.isPlayable) { self.isSelected = true; self.highlight.alpha = 0.5; } }; self.up = function (x, y, obj) { if (!self.isPlayable) { return; } // Call the game's card played handler - implemented in game.cardPlayed var gameCoords = game.toLocal(self.parent.toGlobal(self.position)); game.cardSelected(self, gameCoords.x, gameCoords.y); }; // Toggle selection state self.setSelected = function (selected) { self.isSelected = selected; self.highlight.alpha = selected ? 0.5 : 0; }; // Set card playability self.setPlayable = function (playable) { self.isPlayable = playable; self.alpha = playable ? 1 : 0.6; }; return self; }); // Hero class representing player or enemy champion var Hero = Container.expand(function (isPlayer) { var self = Container.call(this); // Hero properties self.isPlayer = isPlayer; self.health = 20; self.maxHealth = 20; self.resources = 0; self.maxResources = 10; self.attack = 0; self.defense = 0; self.name = isPlayer ? "Player Hero" : "Enemy Hero"; // Visual representation self.avatar = self.attachAsset(isPlayer ? 'heroAvatar' : 'enemyAvatar', { anchorX: 0.5, anchorY: 0.5 }); // Name display self.nameText = new Text2(self.name, { size: 28, fill: 0xFFFFFF }); self.nameText.anchor.set(0.5, 0); self.nameText.y = -130; self.addChild(self.nameText); // Health bar self.healthBarBg = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, y: 120, tint: 0x666666 }); self.healthBar = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0.5, x: -100, y: 120 }); // Health text self.healthText = new Text2(self.health + "/" + self.maxHealth, { size: 22, fill: 0xFFFFFF }); self.healthText.anchor.set(0.5, 0.5); self.healthText.y = 120; self.addChild(self.healthText); // Resource bar (only for player) if (isPlayer) { self.resourceBarBg = self.attachAsset('resourceBar', { anchorX: 0.5, anchorY: 0.5, y: 150, tint: 0x666666 }); self.resourceBar = self.attachAsset('resourceBar', { anchorX: 0, anchorY: 0.5, x: -100, y: 150 }); // Resource text self.resourceText = new Text2(self.resources + "/" + self.maxResources, { size: 22, fill: 0xFFFFFF }); self.resourceText.anchor.set(0.5, 0.5); self.resourceText.y = 150; self.addChild(self.resourceText); } // Update health display self.updateHealth = function (newHealth) { self.health = Math.max(0, Math.min(self.maxHealth, newHealth)); self.healthText.setText(self.health + "/" + self.maxHealth); // Update health bar var healthRatio = self.health / self.maxHealth; self.healthBar.width = 200 * healthRatio; self.healthBar.x = -100; // Flash red if damage taken if (newHealth < self.health) { LK.effects.flashObject(self.avatar, 0xff0000, 500); } return self.health; }; // Update resource display (player only) self.updateResources = function (newResources) { if (!self.isPlayer) { return; } self.resources = Math.max(0, Math.min(self.maxResources, newResources)); self.resourceText.setText(self.resources + "/" + self.maxResources); // Update resource bar var resourceRatio = self.resources / self.maxResources; self.resourceBar.width = 200 * resourceRatio; }; // Take damage accounting for defense self.takeDamage = function (amount) { var actualDamage = Math.max(0, amount - self.defense); self.defense = Math.max(0, self.defense - amount); if (actualDamage > 0) { self.updateHealth(self.health - actualDamage); LK.getSound('damage').play(); // Flash effect for damage LK.effects.flashObject(self, 0xff0000, 300); } return actualDamage; }; // Add attack power self.addAttack = function (amount) { self.attack += amount; return self.attack; }; // Add defense self.addDefense = function (amount) { self.defense += amount; return self.defense; }; // Reset turn stats self.resetTurnStats = function () { self.attack = 0; self.defense = 0; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game state var playerHand = []; var playerDeck = []; var enemyDeck = []; var enemyHand = []; var discardPile = []; var isPlayerTurn = true; var gameStarted = false; var selectedCard = null; var draggedCard = null; var turnCounter = 0; var playZone = null; var maxHandSize = 5; var roundActions = []; // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var CARD_WIDTH = 250; var CARD_HEIGHT = 350; var HAND_Y = 2300; var PLAY_ZONE_Y = 1500; // Game entities var playerHero; var enemyHero; var endTurnButton; var playCardButton; var discardCardButton; var actionText; var turnIndicator; // Initialize game elements function initializeGame() { // Create heroes playerHero = new Hero(true); playerHero.x = GAME_WIDTH / 2; playerHero.y = GAME_HEIGHT - 500; game.addChild(playerHero); enemyHero = new Hero(false); enemyHero.x = GAME_WIDTH / 2; enemyHero.y = 500; game.addChild(enemyHero); // Create card templates createCardTemplates(); // Create play zone playZone = new Container(); playZone.x = GAME_WIDTH / 2; playZone.y = PLAY_ZONE_Y; game.addChild(playZone); // Create UI elements createUIElements(); // Shuffle and deal initial hands initializeDecks(); shuffleDeck(playerDeck); shuffleDeck(enemyDeck); dealInitialHands(); // Setup turn indicator turnIndicator = LK.getAsset('turnIndicator', { anchorX: 0.5, anchorY: 0.5 }); turnIndicator.x = GAME_WIDTH / 2; turnIndicator.y = GAME_HEIGHT / 2 - 300; turnIndicator.alpha = 0.7; game.addChild(turnIndicator); // Add action text actionText = new Text2("Your Turn", { size: 40, fill: 0xFFFFFF }); actionText.anchor.set(0.5, 0.5); actionText.x = GAME_WIDTH / 2; actionText.y = GAME_HEIGHT / 2 - 300; game.addChild(actionText); // Start with player turn startPlayerTurn(); // Play background music LK.playMusic('battleMusic'); gameStarted = true; } // Create UI buttons function createUIElements() { // End turn button endTurnButton = new Button("End Turn", 250, 80); endTurnButton.x = GAME_WIDTH - 200; endTurnButton.y = GAME_HEIGHT - 200; endTurnButton.onClick = function () { if (isPlayerTurn) { endPlayerTurn(); } }; game.addChild(endTurnButton); // Play card button (appears when a card is selected) playCardButton = new Button("Play Card", 200, 80); playCardButton.x = GAME_WIDTH / 2 - 120; playCardButton.y = GAME_HEIGHT - 200; playCardButton.alpha = 0; playCardButton.onClick = function () { if (selectedCard) { playCard(selectedCard); } }; game.addChild(playCardButton); // Discard for resources button discardCardButton = new Button("Discard", 200, 80); discardCardButton.x = GAME_WIDTH / 2 + 120; discardCardButton.y = GAME_HEIGHT - 200; discardCardButton.alpha = 0; discardCardButton.onClick = function () { if (selectedCard) { discardForResources(selectedCard); } }; game.addChild(discardCardButton); } // Create card templates function createCardTemplates() { cardTemplates = [ // Attack cards { type: 'attack', value: 3, name: 'Fierce Strike', description: 'Deal 3 damage to opponent' }, { type: 'attack', value: 2, name: 'Quick Slash', description: 'Deal 2 damage to opponent' }, { type: 'attack', value: 4, name: 'Heavy Blow', description: 'Deal 4 damage to opponent' }, { type: 'attack', value: 5, name: 'Crushing Attack', description: 'Deal 5 damage to opponent' }, { type: 'attack', value: 1, name: 'Jab', description: 'Deal 1 damage to opponent' }, // Defense cards { type: 'defense', value: 2, name: 'Block', description: 'Reduce damage by 2' }, { type: 'defense', value: 3, name: 'Shield Up', description: 'Reduce damage by 3' }, { type: 'defense', value: 4, name: 'Deflect', description: 'Reduce damage by 4' }, { type: 'defense', value: 1, name: 'Parry', description: 'Reduce damage by 1' }, // Utility cards { type: 'utility', value: 2, name: 'Focus', description: 'Draw 1 card' }, { type: 'utility', value: 3, name: 'Strategize', description: 'Gain 2 resources' }, { type: 'utility', value: 4, name: 'Second Wind', description: 'Restore 2 health' }]; } // Initialize player and enemy decks function initializeDecks() { playerDeck = []; enemyDeck = []; // Add 30 cards to each deck for (var i = 0; i < 30; i++) { var templateIndex = i % cardTemplates.length; var cardTemplate = cardTemplates[templateIndex]; // Create player card var playerCard = new Card(cardTemplate.type, cardTemplate.value, cardTemplate.name, cardTemplate.description); playerDeck.push(playerCard); // Create enemy card var enemyCard = new Card(cardTemplate.type, cardTemplate.value, cardTemplate.name, cardTemplate.description); enemyDeck.push(enemyCard); } } // Shuffle a deck 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; } } // Deal initial hands function dealInitialHands() { // Draw cards for player for (var i = 0; i < maxHandSize; i++) { drawCard(true); } // Draw cards for enemy for (var i = 0; i < maxHandSize; i++) { drawCard(false); } // Display player hand updateHandDisplay(); } // Draw a card for player or enemy function drawCard(isPlayer) { var deck = isPlayer ? playerDeck : enemyDeck; var hand = isPlayer ? playerHand : enemyHand; if (deck.length > 0 && hand.length < maxHandSize) { var card = deck.pop(); hand.push(card); if (isPlayer) { updateHandDisplay(); } return card; } return null; } // Update the display of cards in player's hand function updateHandDisplay() { // Remove all existing cards from display for (var i = 0; i < playerHand.length; i++) { if (playerHand[i].parent) { playerHand[i].parent.removeChild(playerHand[i]); } } // Calculate card positioning var totalWidth = playerHand.length * CARD_WIDTH * 0.7; var startX = (GAME_WIDTH - totalWidth) / 2; // Add cards to display for (var i = 0; i < playerHand.length; i++) { var card = playerHand[i]; card.x = startX + i * (CARD_WIDTH * 0.7); card.y = HAND_Y; card.setPlayable(isPlayerTurn); game.addChild(card); } } // Start player turn function startPlayerTurn() { isPlayerTurn = true; turnCounter++; // Reset state playerHero.resetTurnStats(); selectedCard = null; hideCardButtons(); // Draw a card if possible if (playerHand.length < maxHandSize) { drawCard(true); } // Update player resources playerHero.updateResources(Math.min(playerHero.maxResources, playerHero.resources + 2)); // Update UI endTurnButton.setEnabled(true); actionText.setText("Your Turn"); // Update player hand cards to be playable for (var i = 0; i < playerHand.length; i++) { playerHand[i].setPlayable(true); } // Position the turn indicator near player tween(turnIndicator, { x: playerHero.x, y: playerHero.y - 250 }, { duration: 500, easing: tween.easeOut }); // Log turn start console.log("Player turn " + turnCounter + " started"); } // End player turn and start enemy turn function endPlayerTurn() { isPlayerTurn = false; // Update UI endTurnButton.setEnabled(false); actionText.setText("Enemy Turn"); hideCardButtons(); // Update player hand cards to not be playable for (var i = 0; i < playerHand.length; i++) { playerHand[i].setPlayable(false); playerHand[i].setSelected(false); } // Position turn indicator near enemy tween(turnIndicator, { x: enemyHero.x, y: enemyHero.y + 250 }, { duration: 500, easing: tween.easeOut }); // Execute enemy turn with a delay LK.setTimeout(function () { executeEnemyTurn(); }, 1000); } // Execute enemy AI turn function executeEnemyTurn() { // Reset enemy stats enemyHero.resetTurnStats(); // Draw a card if (enemyHand.length < maxHandSize) { drawCard(false); } // Update enemy resources (AI starts with some resources) enemyHero.resources = Math.min(enemyHero.maxResources, enemyHero.resources + 2); // AI decision making var actions = planEnemyActions(); executeEnemyActions(actions); } // Plan enemy actions function planEnemyActions() { var actions = []; var availableResources = enemyHero.resources; // Sort cards by value enemyHand.sort(function (a, b) { // Prioritize attack cards if (a.type === 'attack' && b.type !== 'attack') { return -1; } if (a.type !== 'attack' && b.type === 'attack') { return 1; } // Then by value return b.value - a.value; }); // First, check if we need to defend if (playerHero.attack > 0) { // Find defense cards var defenseCards = enemyHand.filter(function (card) { return card.type === 'defense'; }); // Use defense if available if (defenseCards.length > 0) { actions.push({ type: 'play', card: defenseCards[0] }); availableResources -= defenseCards[0].value; // Remove this card from consideration var index = enemyHand.indexOf(defenseCards[0]); if (index !== -1) { enemyHand.splice(index, 1); } } } // Then, try to play attack cards var attackCards = enemyHand.filter(function (card) { return card.type === 'attack' && card.value <= availableResources; }); for (var i = 0; i < attackCards.length; i++) { if (availableResources >= attackCards[i].value) { actions.push({ type: 'play', card: attackCards[i] }); availableResources -= attackCards[i].value; // Remove this card from consideration var index = enemyHand.indexOf(attackCards[i]); if (index !== -1) { enemyHand.splice(index, 1); } } } // If we haven't used any cards but have some, discard one for resources if (actions.length === 0 && enemyHand.length > 0) { // Sort by resource value enemyHand.sort(function (a, b) { return b.resourceValue - a.resourceValue; }); actions.push({ type: 'discard', card: enemyHand[0] }); // Remove this card from consideration var index = enemyHand.indexOf(enemyHand[0]); if (index !== -1) { enemyHand.splice(index, 1); } } return actions; } // Execute a list of enemy actions with delays function executeEnemyActions(actions) { if (actions.length === 0) { // End enemy turn if no more actions LK.setTimeout(startPlayerTurn, 1000); return; } var action = actions.shift(); var card = action.card; LK.setTimeout(function () { if (action.type === 'play') { // Create a visual representation of the card var enemyCard = new Card(card.type, card.value, card.name, card.description); enemyCard.x = enemyHero.x; enemyCard.y = enemyHero.y + 100; game.addChild(enemyCard); // Animate it to play area tween(enemyCard, { x: GAME_WIDTH / 2, y: PLAY_ZONE_Y - 200 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Apply card effect applyCardEffect(card, false); // Fade out card tween(enemyCard, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { game.removeChild(enemyCard); // Continue with next action executeEnemyActions(actions); } }); } }); } else if (action.type === 'discard') { // Create a visual representation of the card var enemyCard = new Card(card.type, card.value, card.name, card.description); enemyCard.x = enemyHero.x; enemyCard.y = enemyHero.y + 100; game.addChild(enemyCard); // Animate discard tween(enemyCard, { x: GAME_WIDTH / 2 + 400, y: PLAY_ZONE_Y, rotation: Math.PI / 4 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Add resources enemyHero.resources += card.resourceValue; // Show resource gain var resourceMsg = new Text2("+" + card.resourceValue + " R", { size: 40, fill: 0xFFCC00 }); resourceMsg.anchor.set(0.5, 0.5); resourceMsg.x = enemyHero.x; resourceMsg.y = enemyHero.y - 50; game.addChild(resourceMsg); // Fade out card tween(enemyCard, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { game.removeChild(enemyCard); // Fade out resource message tween(resourceMsg, { alpha: 0, y: resourceMsg.y - 50 }, { duration: 500, onFinish: function onFinish() { game.removeChild(resourceMsg); // Continue with next action executeEnemyActions(actions); } }); } }); } }); } }, 1000); } // Handle card selected by player game.cardSelected = function (card, x, y) { // Deselect previous card if (selectedCard && selectedCard !== card) { selectedCard.setSelected(false); } // Toggle selection if (selectedCard === card) { selectedCard.setSelected(false); selectedCard = null; hideCardButtons(); } else { selectedCard = card; showCardButtons(); } }; // Show action buttons when a card is selected function showCardButtons() { if (!selectedCard) { return; } // Check if the card can be played (enough resources) var canPlay = playerHero.resources >= selectedCard.value; playCardButton.setEnabled(canPlay); // Show buttons tween(playCardButton, { alpha: 1 }, { duration: 200 }); tween(discardCardButton, { alpha: 1 }, { duration: 200 }); } // Hide action buttons function hideCardButtons() { tween(playCardButton, { alpha: 0 }, { duration: 200 }); tween(discardCardButton, { alpha: 0 }, { duration: 200 }); } // Play selected card function playCard(card) { if (!isPlayerTurn || playerHero.resources < card.value) { return; } // Subtract resources playerHero.updateResources(playerHero.resources - card.value); // Remove from hand var index = playerHand.indexOf(card); if (index !== -1) { playerHand.splice(index, 1); } // Play sound LK.getSound('cardPlay').play(); // Move card to play area var originalX = card.x; var originalY = card.y; tween(card, { x: GAME_WIDTH / 2, y: PLAY_ZONE_Y }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Apply card effect applyCardEffect(card, true); // Fade out card tween(card, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { // Remove card game.removeChild(card); // Reset selection selectedCard = null; hideCardButtons(); // Update hand display updateHandDisplay(); } }); } }); } // Discard card for resources function discardForResources(card) { if (!isPlayerTurn) { return; } // Add resources playerHero.updateResources(playerHero.resources + card.resourceValue); // Remove from hand var index = playerHand.indexOf(card); if (index !== -1) { playerHand.splice(index, 1); } // Play sound LK.getSound('cardPlay').play(); // Move card to discard area tween(card, { x: GAME_WIDTH / 2 + 400, y: PLAY_ZONE_Y, rotation: Math.PI / 4 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Show resource gain var resourceMsg = new Text2("+" + card.resourceValue + " Resources", { size: 40, fill: 0xFFCC00 }); resourceMsg.anchor.set(0.5, 0.5); resourceMsg.x = playerHero.x; resourceMsg.y = playerHero.y - 50; game.addChild(resourceMsg); // Fade out card tween(card, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { game.removeChild(card); // Fade out resource message tween(resourceMsg, { alpha: 0, y: resourceMsg.y - 50 }, { duration: 500, onFinish: function onFinish() { game.removeChild(resourceMsg); } }); // Reset selection selectedCard = null; hideCardButtons(); // Update hand display updateHandDisplay(); } }); } }); } // Apply card effect based on type function applyCardEffect(card, isPlayer) { var hero = isPlayer ? playerHero : enemyHero; var opponent = isPlayer ? enemyHero : playerHero; // Create effect text var effectMsg = new Text2("", { size: 40, style: { fill: 0xFFFFFF } }); effectMsg.anchor.set(0.5, 0.5); effectMsg.x = isPlayer ? playerHero.x : enemyHero.x; effectMsg.y = isPlayer ? playerHero.y - 50 : enemyHero.y - 50; switch (card.type) { case 'attack': // Add attack power hero.addAttack(card.value); // Deal damage immediately var damageDone = opponent.takeDamage(card.value); // Play sound LK.getSound('attack').play(); // Show damage text effectMsg.setText("-" + damageDone); effectMsg.style.fill = "#ff3333"; break; case 'defense': // Add defense hero.addDefense(card.value); // Play sound LK.getSound('defend').play(); // Show defense text effectMsg.setText("+" + card.value + " DEF"); effectMsg.style.fill = "#3399ff"; break; case 'utility': // Handle utility effects if (card.name.includes("Draw")) { // Draw card drawCard(isPlayer); effectMsg.setText("Draw Card"); effectMsg.style.fill = "#33cc33"; } else if (card.name.includes("Gain")) { // Add resources var resourceGain = Math.floor(card.value / 2); hero.updateResources(hero.resources + resourceGain); effectMsg.setText("+" + resourceGain + " Resources"); effectMsg.style.fill = "#ffcc00"; } else if (card.name.includes("Restore")) { // Heal var healAmount = Math.floor(card.value / 2); hero.updateHealth(hero.health + healAmount); effectMsg.setText("+" + healAmount + " HP"); effectMsg.style.fill = "#33cc33"; } break; } // Add effect message to game game.addChild(effectMsg); // Animate and remove effect message tween(effectMsg, { alpha: 0, y: effectMsg.y - 50 }, { duration: 1000, onFinish: function onFinish() { game.removeChild(effectMsg); } }); // Check for game over if (opponent.health <= 0) { LK.setTimeout(function () { if (isPlayer) { // Player won storage.gamesPlayed = (storage.gamesPlayed || 0) + 1; storage.highScore = Math.max(storage.highScore || 0, playerHero.health); LK.setScore(playerHero.health); LK.showYouWin(); } else { // Enemy won storage.gamesPlayed = (storage.gamesPlayed || 0) + 1; LK.setScore(0); LK.showGameOver(); } }, 1000); } } // Game update loop game.update = function () { if (!gameStarted) { initializeGame(); } }; // Handle touch/mouse movement game.move = function (x, y, obj) { // We could implement card dragging here if needed }; // Start the game LK.playMusic('battleMusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
gamesPlayed: 0
});
/****
* Classes
****/
// Button class for game controls
var Button = Container.expand(function (text, width, height) {
var self = Container.call(this);
self.isEnabled = true;
// Button background
self.background = self.attachAsset('buttonBg', {
anchorX: 0.5,
anchorY: 0.5,
width: width || 200,
height: height || 80
});
// Button text
self.text = new Text2(text || "Button", {
size: 28,
fill: 0xFFFFFF
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
// Interaction handlers
self.down = function (x, y, obj) {
if (self.isEnabled) {
self.background.alpha = 0.7;
}
};
self.up = function (x, y, obj) {
if (self.isEnabled) {
self.background.alpha = 1;
if (typeof self.onClick === 'function') {
self.onClick();
}
}
};
// Enable/disable the button
self.setEnabled = function (enabled) {
self.isEnabled = enabled;
self.alpha = enabled ? 1 : 0.5;
};
return self;
});
// Card class to represent game cards
var Card = Container.expand(function (type, value, name, description) {
var self = Container.call(this);
// Card properties
self.type = type || 'attack'; // attack, defense, utility
self.value = value || 1; // primary value (attack/defense/resource)
self.name = name || 'Basic Card';
self.description = description || 'A basic card';
self.isPlayable = true;
self.isSelected = false;
// Visual elements
self.background = self.attachAsset('cardFront', {
anchorX: 0.5,
anchorY: 0.5
});
// Card title
self.titleText = new Text2(self.name, {
size: 24,
fill: 0x000000
});
self.titleText.anchor.set(0.5, 0);
self.titleText.y = -150;
self.addChild(self.titleText);
// Card value and type
var typeColors = {
attack: '#ff3333',
defense: '#3399ff',
utility: '#33cc33'
};
self.valueText = new Text2(self.value.toString(), {
size: 40,
fill: typeColors[self.type] || "#000000"
});
self.valueText.anchor.set(0.5, 0.5);
self.valueText.y = -70;
self.addChild(self.valueText);
// Card type icon
var iconType = self.type === 'attack' ? 'attackIcon' : self.type === 'defense' ? 'defenseIcon' : 'resourceIcon';
self.typeIcon = self.attachAsset(iconType, {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -20
});
// Description text
self.descText = new Text2(self.description, {
size: 18,
fill: 0x333333
});
self.descText.anchor.set(0.5, 0);
self.descText.y = 20;
self.descText.x = 0;
// Limit text width
if (self.descText.width > 230) {
self.descText.scale.set(230 / self.descText.width);
}
self.addChild(self.descText);
// Resource value (all cards can be discarded for resources)
self.resourceValue = Math.max(1, Math.floor(self.value / 2));
self.resourceText = new Text2("R: " + self.resourceValue, {
size: 24,
fill: 0xFFCC00
});
self.resourceText.anchor.set(0.5, 1);
self.resourceText.y = 140;
self.addChild(self.resourceText);
// Highlight for selection
self.highlight = self.attachAsset('cardHighlight', {
anchorX: 0.5,
anchorY: 0.5
});
self.highlight.alpha = 0;
// Card interaction events
self.down = function (x, y, obj) {
if (self.isPlayable) {
self.isSelected = true;
self.highlight.alpha = 0.5;
}
};
self.up = function (x, y, obj) {
if (!self.isPlayable) {
return;
}
// Call the game's card played handler - implemented in game.cardPlayed
var gameCoords = game.toLocal(self.parent.toGlobal(self.position));
game.cardSelected(self, gameCoords.x, gameCoords.y);
};
// Toggle selection state
self.setSelected = function (selected) {
self.isSelected = selected;
self.highlight.alpha = selected ? 0.5 : 0;
};
// Set card playability
self.setPlayable = function (playable) {
self.isPlayable = playable;
self.alpha = playable ? 1 : 0.6;
};
return self;
});
// Hero class representing player or enemy champion
var Hero = Container.expand(function (isPlayer) {
var self = Container.call(this);
// Hero properties
self.isPlayer = isPlayer;
self.health = 20;
self.maxHealth = 20;
self.resources = 0;
self.maxResources = 10;
self.attack = 0;
self.defense = 0;
self.name = isPlayer ? "Player Hero" : "Enemy Hero";
// Visual representation
self.avatar = self.attachAsset(isPlayer ? 'heroAvatar' : 'enemyAvatar', {
anchorX: 0.5,
anchorY: 0.5
});
// Name display
self.nameText = new Text2(self.name, {
size: 28,
fill: 0xFFFFFF
});
self.nameText.anchor.set(0.5, 0);
self.nameText.y = -130;
self.addChild(self.nameText);
// Health bar
self.healthBarBg = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: 120,
tint: 0x666666
});
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
x: -100,
y: 120
});
// Health text
self.healthText = new Text2(self.health + "/" + self.maxHealth, {
size: 22,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.healthText.y = 120;
self.addChild(self.healthText);
// Resource bar (only for player)
if (isPlayer) {
self.resourceBarBg = self.attachAsset('resourceBar', {
anchorX: 0.5,
anchorY: 0.5,
y: 150,
tint: 0x666666
});
self.resourceBar = self.attachAsset('resourceBar', {
anchorX: 0,
anchorY: 0.5,
x: -100,
y: 150
});
// Resource text
self.resourceText = new Text2(self.resources + "/" + self.maxResources, {
size: 22,
fill: 0xFFFFFF
});
self.resourceText.anchor.set(0.5, 0.5);
self.resourceText.y = 150;
self.addChild(self.resourceText);
}
// Update health display
self.updateHealth = function (newHealth) {
self.health = Math.max(0, Math.min(self.maxHealth, newHealth));
self.healthText.setText(self.health + "/" + self.maxHealth);
// Update health bar
var healthRatio = self.health / self.maxHealth;
self.healthBar.width = 200 * healthRatio;
self.healthBar.x = -100;
// Flash red if damage taken
if (newHealth < self.health) {
LK.effects.flashObject(self.avatar, 0xff0000, 500);
}
return self.health;
};
// Update resource display (player only)
self.updateResources = function (newResources) {
if (!self.isPlayer) {
return;
}
self.resources = Math.max(0, Math.min(self.maxResources, newResources));
self.resourceText.setText(self.resources + "/" + self.maxResources);
// Update resource bar
var resourceRatio = self.resources / self.maxResources;
self.resourceBar.width = 200 * resourceRatio;
};
// Take damage accounting for defense
self.takeDamage = function (amount) {
var actualDamage = Math.max(0, amount - self.defense);
self.defense = Math.max(0, self.defense - amount);
if (actualDamage > 0) {
self.updateHealth(self.health - actualDamage);
LK.getSound('damage').play();
// Flash effect for damage
LK.effects.flashObject(self, 0xff0000, 300);
}
return actualDamage;
};
// Add attack power
self.addAttack = function (amount) {
self.attack += amount;
return self.attack;
};
// Add defense
self.addDefense = function (amount) {
self.defense += amount;
return self.defense;
};
// Reset turn stats
self.resetTurnStats = function () {
self.attack = 0;
self.defense = 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game state
var playerHand = [];
var playerDeck = [];
var enemyDeck = [];
var enemyHand = [];
var discardPile = [];
var isPlayerTurn = true;
var gameStarted = false;
var selectedCard = null;
var draggedCard = null;
var turnCounter = 0;
var playZone = null;
var maxHandSize = 5;
var roundActions = [];
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CARD_WIDTH = 250;
var CARD_HEIGHT = 350;
var HAND_Y = 2300;
var PLAY_ZONE_Y = 1500;
// Game entities
var playerHero;
var enemyHero;
var endTurnButton;
var playCardButton;
var discardCardButton;
var actionText;
var turnIndicator;
// Initialize game elements
function initializeGame() {
// Create heroes
playerHero = new Hero(true);
playerHero.x = GAME_WIDTH / 2;
playerHero.y = GAME_HEIGHT - 500;
game.addChild(playerHero);
enemyHero = new Hero(false);
enemyHero.x = GAME_WIDTH / 2;
enemyHero.y = 500;
game.addChild(enemyHero);
// Create card templates
createCardTemplates();
// Create play zone
playZone = new Container();
playZone.x = GAME_WIDTH / 2;
playZone.y = PLAY_ZONE_Y;
game.addChild(playZone);
// Create UI elements
createUIElements();
// Shuffle and deal initial hands
initializeDecks();
shuffleDeck(playerDeck);
shuffleDeck(enemyDeck);
dealInitialHands();
// Setup turn indicator
turnIndicator = LK.getAsset('turnIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
turnIndicator.x = GAME_WIDTH / 2;
turnIndicator.y = GAME_HEIGHT / 2 - 300;
turnIndicator.alpha = 0.7;
game.addChild(turnIndicator);
// Add action text
actionText = new Text2("Your Turn", {
size: 40,
fill: 0xFFFFFF
});
actionText.anchor.set(0.5, 0.5);
actionText.x = GAME_WIDTH / 2;
actionText.y = GAME_HEIGHT / 2 - 300;
game.addChild(actionText);
// Start with player turn
startPlayerTurn();
// Play background music
LK.playMusic('battleMusic');
gameStarted = true;
}
// Create UI buttons
function createUIElements() {
// End turn button
endTurnButton = new Button("End Turn", 250, 80);
endTurnButton.x = GAME_WIDTH - 200;
endTurnButton.y = GAME_HEIGHT - 200;
endTurnButton.onClick = function () {
if (isPlayerTurn) {
endPlayerTurn();
}
};
game.addChild(endTurnButton);
// Play card button (appears when a card is selected)
playCardButton = new Button("Play Card", 200, 80);
playCardButton.x = GAME_WIDTH / 2 - 120;
playCardButton.y = GAME_HEIGHT - 200;
playCardButton.alpha = 0;
playCardButton.onClick = function () {
if (selectedCard) {
playCard(selectedCard);
}
};
game.addChild(playCardButton);
// Discard for resources button
discardCardButton = new Button("Discard", 200, 80);
discardCardButton.x = GAME_WIDTH / 2 + 120;
discardCardButton.y = GAME_HEIGHT - 200;
discardCardButton.alpha = 0;
discardCardButton.onClick = function () {
if (selectedCard) {
discardForResources(selectedCard);
}
};
game.addChild(discardCardButton);
}
// Create card templates
function createCardTemplates() {
cardTemplates = [
// Attack cards
{
type: 'attack',
value: 3,
name: 'Fierce Strike',
description: 'Deal 3 damage to opponent'
}, {
type: 'attack',
value: 2,
name: 'Quick Slash',
description: 'Deal 2 damage to opponent'
}, {
type: 'attack',
value: 4,
name: 'Heavy Blow',
description: 'Deal 4 damage to opponent'
}, {
type: 'attack',
value: 5,
name: 'Crushing Attack',
description: 'Deal 5 damage to opponent'
}, {
type: 'attack',
value: 1,
name: 'Jab',
description: 'Deal 1 damage to opponent'
},
// Defense cards
{
type: 'defense',
value: 2,
name: 'Block',
description: 'Reduce damage by 2'
}, {
type: 'defense',
value: 3,
name: 'Shield Up',
description: 'Reduce damage by 3'
}, {
type: 'defense',
value: 4,
name: 'Deflect',
description: 'Reduce damage by 4'
}, {
type: 'defense',
value: 1,
name: 'Parry',
description: 'Reduce damage by 1'
},
// Utility cards
{
type: 'utility',
value: 2,
name: 'Focus',
description: 'Draw 1 card'
}, {
type: 'utility',
value: 3,
name: 'Strategize',
description: 'Gain 2 resources'
}, {
type: 'utility',
value: 4,
name: 'Second Wind',
description: 'Restore 2 health'
}];
}
// Initialize player and enemy decks
function initializeDecks() {
playerDeck = [];
enemyDeck = [];
// Add 30 cards to each deck
for (var i = 0; i < 30; i++) {
var templateIndex = i % cardTemplates.length;
var cardTemplate = cardTemplates[templateIndex];
// Create player card
var playerCard = new Card(cardTemplate.type, cardTemplate.value, cardTemplate.name, cardTemplate.description);
playerDeck.push(playerCard);
// Create enemy card
var enemyCard = new Card(cardTemplate.type, cardTemplate.value, cardTemplate.name, cardTemplate.description);
enemyDeck.push(enemyCard);
}
}
// Shuffle a deck
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;
}
}
// Deal initial hands
function dealInitialHands() {
// Draw cards for player
for (var i = 0; i < maxHandSize; i++) {
drawCard(true);
}
// Draw cards for enemy
for (var i = 0; i < maxHandSize; i++) {
drawCard(false);
}
// Display player hand
updateHandDisplay();
}
// Draw a card for player or enemy
function drawCard(isPlayer) {
var deck = isPlayer ? playerDeck : enemyDeck;
var hand = isPlayer ? playerHand : enemyHand;
if (deck.length > 0 && hand.length < maxHandSize) {
var card = deck.pop();
hand.push(card);
if (isPlayer) {
updateHandDisplay();
}
return card;
}
return null;
}
// Update the display of cards in player's hand
function updateHandDisplay() {
// Remove all existing cards from display
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i].parent) {
playerHand[i].parent.removeChild(playerHand[i]);
}
}
// Calculate card positioning
var totalWidth = playerHand.length * CARD_WIDTH * 0.7;
var startX = (GAME_WIDTH - totalWidth) / 2;
// Add cards to display
for (var i = 0; i < playerHand.length; i++) {
var card = playerHand[i];
card.x = startX + i * (CARD_WIDTH * 0.7);
card.y = HAND_Y;
card.setPlayable(isPlayerTurn);
game.addChild(card);
}
}
// Start player turn
function startPlayerTurn() {
isPlayerTurn = true;
turnCounter++;
// Reset state
playerHero.resetTurnStats();
selectedCard = null;
hideCardButtons();
// Draw a card if possible
if (playerHand.length < maxHandSize) {
drawCard(true);
}
// Update player resources
playerHero.updateResources(Math.min(playerHero.maxResources, playerHero.resources + 2));
// Update UI
endTurnButton.setEnabled(true);
actionText.setText("Your Turn");
// Update player hand cards to be playable
for (var i = 0; i < playerHand.length; i++) {
playerHand[i].setPlayable(true);
}
// Position the turn indicator near player
tween(turnIndicator, {
x: playerHero.x,
y: playerHero.y - 250
}, {
duration: 500,
easing: tween.easeOut
});
// Log turn start
console.log("Player turn " + turnCounter + " started");
}
// End player turn and start enemy turn
function endPlayerTurn() {
isPlayerTurn = false;
// Update UI
endTurnButton.setEnabled(false);
actionText.setText("Enemy Turn");
hideCardButtons();
// Update player hand cards to not be playable
for (var i = 0; i < playerHand.length; i++) {
playerHand[i].setPlayable(false);
playerHand[i].setSelected(false);
}
// Position turn indicator near enemy
tween(turnIndicator, {
x: enemyHero.x,
y: enemyHero.y + 250
}, {
duration: 500,
easing: tween.easeOut
});
// Execute enemy turn with a delay
LK.setTimeout(function () {
executeEnemyTurn();
}, 1000);
}
// Execute enemy AI turn
function executeEnemyTurn() {
// Reset enemy stats
enemyHero.resetTurnStats();
// Draw a card
if (enemyHand.length < maxHandSize) {
drawCard(false);
}
// Update enemy resources (AI starts with some resources)
enemyHero.resources = Math.min(enemyHero.maxResources, enemyHero.resources + 2);
// AI decision making
var actions = planEnemyActions();
executeEnemyActions(actions);
}
// Plan enemy actions
function planEnemyActions() {
var actions = [];
var availableResources = enemyHero.resources;
// Sort cards by value
enemyHand.sort(function (a, b) {
// Prioritize attack cards
if (a.type === 'attack' && b.type !== 'attack') {
return -1;
}
if (a.type !== 'attack' && b.type === 'attack') {
return 1;
}
// Then by value
return b.value - a.value;
});
// First, check if we need to defend
if (playerHero.attack > 0) {
// Find defense cards
var defenseCards = enemyHand.filter(function (card) {
return card.type === 'defense';
});
// Use defense if available
if (defenseCards.length > 0) {
actions.push({
type: 'play',
card: defenseCards[0]
});
availableResources -= defenseCards[0].value;
// Remove this card from consideration
var index = enemyHand.indexOf(defenseCards[0]);
if (index !== -1) {
enemyHand.splice(index, 1);
}
}
}
// Then, try to play attack cards
var attackCards = enemyHand.filter(function (card) {
return card.type === 'attack' && card.value <= availableResources;
});
for (var i = 0; i < attackCards.length; i++) {
if (availableResources >= attackCards[i].value) {
actions.push({
type: 'play',
card: attackCards[i]
});
availableResources -= attackCards[i].value;
// Remove this card from consideration
var index = enemyHand.indexOf(attackCards[i]);
if (index !== -1) {
enemyHand.splice(index, 1);
}
}
}
// If we haven't used any cards but have some, discard one for resources
if (actions.length === 0 && enemyHand.length > 0) {
// Sort by resource value
enemyHand.sort(function (a, b) {
return b.resourceValue - a.resourceValue;
});
actions.push({
type: 'discard',
card: enemyHand[0]
});
// Remove this card from consideration
var index = enemyHand.indexOf(enemyHand[0]);
if (index !== -1) {
enemyHand.splice(index, 1);
}
}
return actions;
}
// Execute a list of enemy actions with delays
function executeEnemyActions(actions) {
if (actions.length === 0) {
// End enemy turn if no more actions
LK.setTimeout(startPlayerTurn, 1000);
return;
}
var action = actions.shift();
var card = action.card;
LK.setTimeout(function () {
if (action.type === 'play') {
// Create a visual representation of the card
var enemyCard = new Card(card.type, card.value, card.name, card.description);
enemyCard.x = enemyHero.x;
enemyCard.y = enemyHero.y + 100;
game.addChild(enemyCard);
// Animate it to play area
tween(enemyCard, {
x: GAME_WIDTH / 2,
y: PLAY_ZONE_Y - 200
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Apply card effect
applyCardEffect(card, false);
// Fade out card
tween(enemyCard, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(enemyCard);
// Continue with next action
executeEnemyActions(actions);
}
});
}
});
} else if (action.type === 'discard') {
// Create a visual representation of the card
var enemyCard = new Card(card.type, card.value, card.name, card.description);
enemyCard.x = enemyHero.x;
enemyCard.y = enemyHero.y + 100;
game.addChild(enemyCard);
// Animate discard
tween(enemyCard, {
x: GAME_WIDTH / 2 + 400,
y: PLAY_ZONE_Y,
rotation: Math.PI / 4
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Add resources
enemyHero.resources += card.resourceValue;
// Show resource gain
var resourceMsg = new Text2("+" + card.resourceValue + " R", {
size: 40,
fill: 0xFFCC00
});
resourceMsg.anchor.set(0.5, 0.5);
resourceMsg.x = enemyHero.x;
resourceMsg.y = enemyHero.y - 50;
game.addChild(resourceMsg);
// Fade out card
tween(enemyCard, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(enemyCard);
// Fade out resource message
tween(resourceMsg, {
alpha: 0,
y: resourceMsg.y - 50
}, {
duration: 500,
onFinish: function onFinish() {
game.removeChild(resourceMsg);
// Continue with next action
executeEnemyActions(actions);
}
});
}
});
}
});
}
}, 1000);
}
// Handle card selected by player
game.cardSelected = function (card, x, y) {
// Deselect previous card
if (selectedCard && selectedCard !== card) {
selectedCard.setSelected(false);
}
// Toggle selection
if (selectedCard === card) {
selectedCard.setSelected(false);
selectedCard = null;
hideCardButtons();
} else {
selectedCard = card;
showCardButtons();
}
};
// Show action buttons when a card is selected
function showCardButtons() {
if (!selectedCard) {
return;
}
// Check if the card can be played (enough resources)
var canPlay = playerHero.resources >= selectedCard.value;
playCardButton.setEnabled(canPlay);
// Show buttons
tween(playCardButton, {
alpha: 1
}, {
duration: 200
});
tween(discardCardButton, {
alpha: 1
}, {
duration: 200
});
}
// Hide action buttons
function hideCardButtons() {
tween(playCardButton, {
alpha: 0
}, {
duration: 200
});
tween(discardCardButton, {
alpha: 0
}, {
duration: 200
});
}
// Play selected card
function playCard(card) {
if (!isPlayerTurn || playerHero.resources < card.value) {
return;
}
// Subtract resources
playerHero.updateResources(playerHero.resources - card.value);
// Remove from hand
var index = playerHand.indexOf(card);
if (index !== -1) {
playerHand.splice(index, 1);
}
// Play sound
LK.getSound('cardPlay').play();
// Move card to play area
var originalX = card.x;
var originalY = card.y;
tween(card, {
x: GAME_WIDTH / 2,
y: PLAY_ZONE_Y
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Apply card effect
applyCardEffect(card, true);
// Fade out card
tween(card, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
// Remove card
game.removeChild(card);
// Reset selection
selectedCard = null;
hideCardButtons();
// Update hand display
updateHandDisplay();
}
});
}
});
}
// Discard card for resources
function discardForResources(card) {
if (!isPlayerTurn) {
return;
}
// Add resources
playerHero.updateResources(playerHero.resources + card.resourceValue);
// Remove from hand
var index = playerHand.indexOf(card);
if (index !== -1) {
playerHand.splice(index, 1);
}
// Play sound
LK.getSound('cardPlay').play();
// Move card to discard area
tween(card, {
x: GAME_WIDTH / 2 + 400,
y: PLAY_ZONE_Y,
rotation: Math.PI / 4
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Show resource gain
var resourceMsg = new Text2("+" + card.resourceValue + " Resources", {
size: 40,
fill: 0xFFCC00
});
resourceMsg.anchor.set(0.5, 0.5);
resourceMsg.x = playerHero.x;
resourceMsg.y = playerHero.y - 50;
game.addChild(resourceMsg);
// Fade out card
tween(card, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(card);
// Fade out resource message
tween(resourceMsg, {
alpha: 0,
y: resourceMsg.y - 50
}, {
duration: 500,
onFinish: function onFinish() {
game.removeChild(resourceMsg);
}
});
// Reset selection
selectedCard = null;
hideCardButtons();
// Update hand display
updateHandDisplay();
}
});
}
});
}
// Apply card effect based on type
function applyCardEffect(card, isPlayer) {
var hero = isPlayer ? playerHero : enemyHero;
var opponent = isPlayer ? enemyHero : playerHero;
// Create effect text
var effectMsg = new Text2("", {
size: 40,
style: {
fill: 0xFFFFFF
}
});
effectMsg.anchor.set(0.5, 0.5);
effectMsg.x = isPlayer ? playerHero.x : enemyHero.x;
effectMsg.y = isPlayer ? playerHero.y - 50 : enemyHero.y - 50;
switch (card.type) {
case 'attack':
// Add attack power
hero.addAttack(card.value);
// Deal damage immediately
var damageDone = opponent.takeDamage(card.value);
// Play sound
LK.getSound('attack').play();
// Show damage text
effectMsg.setText("-" + damageDone);
effectMsg.style.fill = "#ff3333";
break;
case 'defense':
// Add defense
hero.addDefense(card.value);
// Play sound
LK.getSound('defend').play();
// Show defense text
effectMsg.setText("+" + card.value + " DEF");
effectMsg.style.fill = "#3399ff";
break;
case 'utility':
// Handle utility effects
if (card.name.includes("Draw")) {
// Draw card
drawCard(isPlayer);
effectMsg.setText("Draw Card");
effectMsg.style.fill = "#33cc33";
} else if (card.name.includes("Gain")) {
// Add resources
var resourceGain = Math.floor(card.value / 2);
hero.updateResources(hero.resources + resourceGain);
effectMsg.setText("+" + resourceGain + " Resources");
effectMsg.style.fill = "#ffcc00";
} else if (card.name.includes("Restore")) {
// Heal
var healAmount = Math.floor(card.value / 2);
hero.updateHealth(hero.health + healAmount);
effectMsg.setText("+" + healAmount + " HP");
effectMsg.style.fill = "#33cc33";
}
break;
}
// Add effect message to game
game.addChild(effectMsg);
// Animate and remove effect message
tween(effectMsg, {
alpha: 0,
y: effectMsg.y - 50
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(effectMsg);
}
});
// Check for game over
if (opponent.health <= 0) {
LK.setTimeout(function () {
if (isPlayer) {
// Player won
storage.gamesPlayed = (storage.gamesPlayed || 0) + 1;
storage.highScore = Math.max(storage.highScore || 0, playerHero.health);
LK.setScore(playerHero.health);
LK.showYouWin();
} else {
// Enemy won
storage.gamesPlayed = (storage.gamesPlayed || 0) + 1;
LK.setScore(0);
LK.showGameOver();
}
}, 1000);
}
}
// Game update loop
game.update = function () {
if (!gameStarted) {
initializeGame();
}
};
// Handle touch/mouse movement
game.move = function (x, y, obj) {
// We could implement card dragging here if needed
};
// Start the game
LK.playMusic('battleMusic');