/**** * 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, 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');
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,1022 @@
-/****
+/****
+* 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: 0x000000
-});
\ No newline at end of file
+ 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,
+ 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');
\ No newline at end of file