User prompt
Quiero que una vez que hayas usado una carta, y haya pasado un turno completo sin que la tengas en tu mano de selección, pueda volverte a salir, haciendo así que no sé agoten las cartas hasta quedarte sin cartas
User prompt
Quiero que crees un grupo de cartas llamadas Cartas de Invocación, estás serán el Fénix, Pirata, Serafín, Sarcófago y Hombre de nieve, no va a ser un elemento nuevo, pero quiero que las distingas bajo ese nombre
User prompt
Quiero que crees una carta del elemento roca llamada Muralla Rocosa, esta tendrá una vida de 4, evitando así que se dañe al usuario que la usó hasta que caiga destruida. En caso de que usen una carta con más daño que la vida de la Muralla Rocosa, esta absorberá el daño que tenga de vida, es decir si le queda 2 de vida y usan una carta de 3, la carta quitará 1 al usuario de Muralla Rocosa. Ponle el maná que consideres
User prompt
Quiero que crees una carta del elemento aire llamada Tormenta, esta quitará 3 de vida y tendrá un 10% de evitar que el adversario actúe en su turno. Agrégale el maná que consideres
User prompt
Crea una carta de aire llamada Tormenta, esta quitará 3 de vida y tiene un 10% de evitar que el rival ataque paralizándolo
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highestLevel: 0, completedCourses: 0, currentCourse: 0, currentBattleInCourse: 0, playerMaxHealth: 10 }); /**** * Classes ****/ var Card = Container.expand(function (element, damage, name, effect) { var self = Container.call(this); self.element = element; self.damage = damage; self.name = name || element; self.effect = effect || 'normal'; self.isUsed = false; // Card border background (slightly larger than content) var cardBorder = self.attachAsset('cardBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.05, scaleY: 1.05, tint: 0x444444 }); // Card main background var cardBg = self.attachAsset('cardBase', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(cardBg); // Use specific card name image if available, otherwise fallback to element graphic var cardImageId = getCardImageId(self.name); // TOP HALF: Card design image (scaled to fit top half of card) var cardDesign = self.attachAsset(cardImageId, { anchorX: 0.5, anchorY: 0.5, y: -105, // Position in top half scaleX: 0.93, scaleY: cardImageId === 'agua_oxigenada' ? 0.32 : 0.5 }); // Get element color var elementColor = getElementColor(element); // BOTTOM HALF: Element color background (covers bottom half of card) var elementColorBg = LK.getAsset('cardBase', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.93, scaleY: 0.5, tint: elementColor }); elementColorBg.y = 105; // Position in bottom half self.addChild(elementColorBg); // Get mana cost for this card self.manaCost = getCardManaCost(name, effect); // Create damage/healing text in the format "damage/+heal" or just "damage" var healAmount = getHealAmount(name, effect); var damageDisplayText = damage.toString(); if ((effect === 'heal' || effect === 'damageAndHeal' || effect === 'increaseMaxHealth') && healAmount > 0) { damageDisplayText = damage.toString() + '/+' + healAmount.toString(); } // Damage/healing text on the element color background var damageText = new Text2(damageDisplayText, { size: 48, fill: 0xFFFFFF, font: "'Arial Black', Arial, sans-serif" }); damageText.anchor.set(0.5, 0.5); damageText.y = 85; // Position slightly higher to make room for mana cost // Add dark stroke for better contrast damageText.stroke = 0x000000; damageText.strokeThickness = 3; self.addChild(damageText); // Mana cost text on the element color background var manaText = new Text2('⚡' + self.manaCost.toString(), { size: 36, fill: 0xFFD700, font: "'Arial Black', Arial, sans-serif" }); manaText.anchor.set(0.5, 0.5); manaText.y = 125; // Position below damage text manaText.stroke = 0x000000; manaText.strokeThickness = 3; self.addChild(manaText); self.down = function (x, y, obj) { if (!self.isUsed && gameState === 'playerTurn') { if (playerMana >= self.manaCost) { playCard(self); } else { // Flash card red to indicate insufficient mana tween(self, { tint: 0xff0000 }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 200 }); } }); } } }; return self; }); var Enemy = Container.expand(function (name, health, difficulty, battleIndex) { var self = Container.call(this); self.name = name; self.maxHealth = health; self.health = health; self.difficulty = difficulty; self.battleIndex = battleIndex; // Store battle index for wizard assignment self.isFrozen = false; self.hasExtraAttack = false; self.iceBlocked = false; self.mana = 10; self.maxMana = 10; self.deck = createEnemyDeck(difficulty); self.hand = []; // Use wizard sprite based on battle index for adventure mode var wizardSpriteId = 'academy'; // Default fallback if (gameMode === 'adventure' && typeof battleIndex !== 'undefined') { // Sequential mapping: battleIndex 0-17 maps to wizard1-wizard18 // Course 1 (battles 0-2): wizard1, wizard2, wizard3 // Course 2 (battles 3-5): wizard4, wizard5, wizard6 // Course 3 (battles 6-8): wizard7, wizard8, wizard9 // Course 4 (battles 9-11): wizard10, wizard11, wizard12 // Course 5 (battles 12-14): wizard13, wizard14, wizard15 // Course 6 (battles 15-17): wizard16, wizard17, wizard18 var wizardNumber = battleIndex + 1; // Direct 1:1 mapping wizardNumber = Math.max(1, Math.min(wizardNumber, 18)); // Ensure range 1-18 wizardSpriteId = 'wizard' + wizardNumber; } var enemyGraphic = self.attachAsset(wizardSpriteId, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); var nameText = new Text2(name, { size: 50, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = -200; self.addChild(nameText); var healthText = new Text2('HP: ' + health, { size: 40, fill: 0xFFFFFF }); healthText.anchor.set(0.5, 0.5); healthText.y = 200; self.addChild(healthText); self.healthText = healthText; self.drawHand = function () { // Clear existing hand visuals if (self.handCards) { for (var j = 0; j < self.handCards.length; j++) { if (self.handCards[j].parent) { self.handCards[j].parent.removeChild(self.handCards[j]); } } } self.handCards = []; self.hand = []; var handCardNames = []; // Track card names to prevent duplicates for (var i = 0; i < 3; i++) { if (self.deck.length > 0) { var attempts = 0; var foundValidCard = false; while (attempts < 50 && !foundValidCard) { // Limit attempts to prevent infinite loop var randomIndex = Math.floor(Math.random() * self.deck.length); var cardData = self.deck[randomIndex]; // Check if this card name is already in hand var isDuplicate = false; for (var j = 0; j < handCardNames.length; j++) { if (handCardNames[j] === (cardData.name || cardData.element)) { isDuplicate = true; break; } } // Use card if it's not a duplicate if (!isDuplicate) { self.hand.push(cardData); // Create visual card for enemy with same design as player cards var enemyCard = new Card(cardData.element, cardData.damage, cardData.name || cardData.element, cardData.effect || 'normal'); enemyCard.x = -400 + i * 200; enemyCard.y = -400; enemyCard.scaleX = 0.6; enemyCard.scaleY = 0.6; self.addChild(enemyCard); self.handCards.push(enemyCard); handCardNames.push(cardData.name || cardData.element); foundValidCard = true; } attempts++; } } } }; self.takeDamage = function (damage) { self.health -= damage; if (self.health < 0) self.health = 0; self.healthText.setText('HP: ' + self.health); tween(self, { tint: 0xff0000 }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 200 }); } }); }; self.removeCardFromHand = function (cardIndex) { if (cardIndex >= 0 && cardIndex < self.hand.length) { // Remove from hand array self.hand.splice(cardIndex, 1); // Remove visual card if (self.handCards && self.handCards[cardIndex]) { self.removeChild(self.handCards[cardIndex]); self.handCards.splice(cardIndex, 1); } } }; self.playTurn = function () { if (self.isFrozen) { self.isFrozen = false; endEnemyTurn(); return; } if (self.hand.length > 0) { // Check if enemy can afford any card var affordableCards = []; for (var i = 0; i < self.hand.length; i++) { var cardCost = getCardManaCost(self.hand[i].name || self.hand[i].element, self.hand[i].effect || 'normal'); if (self.mana >= cardCost) { affordableCards.push({ card: self.hand[i], index: i, cost: cardCost }); } } // If no affordable cards, pass turn to restore mana if (affordableCards.length === 0) { self.mana = self.maxMana; endEnemyTurn(); return; } var selectedCard = affordableCards[Math.floor(Math.random() * affordableCards.length)]; var cardIndex = selectedCard.index; var card = selectedCard.card; // If ice is blocked, find a non-ice card if (self.iceBlocked && card.element === 'Ice') { var nonIceCards = []; for (var i = 0; i < self.hand.length; i++) { if (self.hand[i].element !== 'Ice') { nonIceCards.push({ card: self.hand[i], index: i }); } } if (nonIceCards.length > 0) { var randomNonIce = nonIceCards[Math.floor(Math.random() * nonIceCards.length)]; card = randomNonIce.card; cardIndex = randomNonIce.index; } } // Reset ice block after turn self.iceBlocked = false; enemyPlayCard(card, cardIndex); // Check for extra attack from hombre de nieve effect if (self.hasExtraAttack && self.hand.length > 0) { self.hasExtraAttack = false; // Play another card with damage 1 LK.setTimeout(function () { if (self.hand.length > 0) { var extraCardIndex = Math.floor(Math.random() * self.hand.length); var extraCard = { element: 'Ice', damage: 1 }; enemyPlayCard(extraCard, extraCardIndex); } }, 500); } } else { endEnemyTurn(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2a1810 }); /**** * Game Code ****/ // Ice card images // Rock card images // Plant card images // Air card images // Water card images // Fire card images // Game state variables var playerUsedCards = []; // Track cards used in current turn var enemyUsedCards = []; // Track enemy cards used in current turn var playerUnavailableCards = []; // Track cards that can't be drawn yet (with turn counters) var playerShield = null; // Player's shield (Muralla Rocosa) var playerShieldBar = null; // Shield health bar var playerShieldText = null; // Shield health text // Fire card images // Water card images // Air card images // Plant card images // Rock card images // Ice card images // Adventure mode wizard sprites with different colored hats // Green hat // Lime green hat // Lawn green hat // Green yellow hat // Yellow hat // Gold hat // Orange hat // Dark orange hat // Coral hat // Tomato hat // Orange red hat // Red hat // Crimson hat // Fire brick hat // Dark red hat // Maroon hat // Golden hat (penultimate) // Astral purple hat (final) function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var gameState = 'menu'; // 'menu', 'modeSelect', 'battle', 'victory', 'defeat' var gameMode = 'adventure'; // 'adventure', 'roguelike' var roguelikeLevel = storage.highestLevel || 0; var currentCourse = storage.currentCourse || 0; var currentBattleInCourse = storage.currentBattleInCourse || 0; var completedCourses = storage.completedCourses || 0; // Helper function to map card names to image IDs function getCardImageId(cardName) { switch (cardName) { // Fire cards case 'Llamarada': return 'llamarada'; case 'Fénix': return 'fenix_invocation'; case 'Brasas': return 'brasas'; case 'Llama': return 'llama'; case 'Mechero': return 'mechero'; // Water cards case 'Gota de agua': return 'gota_de_agua'; case 'Luna roja': return 'luna_roja'; case 'Agua oxigenada': return 'agua_oxigenada'; case 'Marea': return 'marea'; case 'Pirata': return 'pirata_invocation'; // Air cards case 'Vendaval': return 'vendaval'; case 'Brisa': return 'brisa'; case 'Huracán': return 'huracan'; case 'Tormenta': return 'tormenta'; // Plant cards case 'Arboleda': return 'arboleda'; case 'Serafín': return 'serafin_invocation'; case 'Rama': return 'rama'; case 'Vida extra': return 'vida_extra'; case 'Aullidos del bosque': return 'aullidos_del_bosque'; // Rock cards case 'Pedrada': return 'pedrada'; case 'Tormenta de arena': return 'tormenta_de_arena'; case 'Sarcófago': return 'sarcofago_invocation'; case 'Muralla Rocosa': return 'muralla_rocosa'; case 'Terremoto': return 'terremoto'; // Ice cards case 'Nevada': return 'nevada'; case 'Ventisca': return 'ventisca'; case 'Bola de nieve': return 'bola_de_nieve'; case 'Hombre de nieve': return 'hombre_de_nieve_invocation'; default: return getElementCardId(cardName); } } // Helper function to get fallback element card ID function getElementCardId(element) { switch (element) { case 'Fire': return 'fireCard'; case 'Water': return 'waterCard'; case 'Air': return 'airCard'; case 'Plant': return 'plantCard'; case 'Rock': return 'rockCard'; case 'Ice': return 'iceCard'; default: return 'cardBase'; } } // Helper function to get element colors function getElementColor(element) { switch (element) { case 'Fire': return 0xff4500; case 'Water': return 0x4169e1; case 'Air': return 0x87ceeb; case 'Plant': return 0x228b22; case 'Rock': return 0x696969; case 'Ice': return 0xb0e0e6; default: return 0xf5f5dc; } } // Helper function to get healing amount for cards function getHealAmount(cardName, effect) { switch (cardName) { case 'Fénix': return 2; case 'Agua oxigenada': return 3; case 'Serafín': return 2; case 'Sarcófago': return 2; case 'Vida extra': return 1; // Max health increase default: return 0; } } // Helper function to get mana cost for cards based on their versatility function getCardManaCost(cardName, effect) { switch (cardName) { // High cost cards (8-10 mana) - very versatile/powerful case 'Muralla Rocosa': // Shield with 4 health return 7; case 'Terremoto': // Replaces all cards for both players return 10; case 'Huracán': // Replaces enemy cards return 8; case 'Tormenta': // Damage + chance to skip enemy turn return 6; case 'Vida extra': // Increases max health permanently return 9; case 'Aullidos del bosque': // Damage + skip enemy turn return 8; case 'Ventisca': // Damage + freeze chance return 7; // Medium-high cost cards (6-7 mana) - good versatility case 'Fénix': // Damage + heal return 7; case 'Llamarada': // High damage + burn card return 6; case 'Pirata': // Damage + steal card return 6; case 'Sarcófago': // Damage + heal return 6; case 'Hombre de nieve': // Damage + extra attack chance return 6; // Medium cost cards (4-5 mana) - moderate versatility case 'Mechero': // Damage + prevent ice return 4; case 'Nevada': // Damage + freeze return 5; case 'Bola de nieve': // Damage + freeze return 4; case 'Agua oxigenada': // Pure healing return 5; case 'Serafín': // Pure healing return 4; // Low-medium cost cards (2-3 mana) - basic with small effects case 'Brasas': // Damage + burn return 3; case 'Llama': // Damage + burn return 3; case 'Luna roja': // Pure damage (2) return 3; case 'Vendaval': // Pure damage (2) return 3; case 'Arboleda': // Pure damage (2) return 3; case 'Pedrada': // Pure damage (2) return 3; case 'Tormenta de arena': // Pure damage (2) return 3; case 'Marea': // Pure damage (2) return 3; // Low cost cards (1-2 mana) - basic effects case 'Gota de agua': // Pure damage (1) return 1; case 'Brisa': // Pure damage (1) return 2; case 'Rama': // Pure damage (1) return 1; // Default costs for generic elements default: if (effect === 'heal' || effect === 'damageAndHeal') { return 5; } else if (effect === 'replaceCards' || effect === 'replaceAllCards') { return 8; } else if (effect === 'skipEnemyTurn' || effect === 'steal') { return 6; } else if (effect === 'chooseBurn' || effect === 'preventIce') { return 4; } else { // Basic damage cards return 2; } } } // Helper function to play element-specific sounds function playElementSound(element) { var soundNumber = Math.floor(Math.random() * 5) + 1; var soundId = element.toLowerCase() + soundNumber; LK.getSound(soundId).play(); } var currentBattle = 0; var playerHealth = 10; var playerMaxHealth = 10; var playerMana = 10; var playerMaxMana = 10; var playerDeck = []; var playerHand = []; var currentEnemy = null; var enemies = []; var turnCounter = 0; // UI elements var menuContainer = new Container(); var battleContainer = new Container(); var playerHealthBar = null; var playerHealthText = null; var playerManaBar = null; var playerManaText = null; var passButton = null; var turnText = null; var battleText = null; // Initialize player deck function initializeDeck() { var elements = ['Fire', 'Water', 'Air', 'Plant', 'Rock', 'Ice']; playerDeck = []; for (var i = 0; i < elements.length; i++) { if (elements[i] === 'Fire') { // Add specific fire cards with names and effects var fireCards = [{ element: 'Fire', damage: 3, name: 'Llamarada', effect: 'chooseBurn' }, { element: 'Fire', damage: 2, name: 'Fénix', effect: 'heal' }, { element: 'Fire', damage: 2, name: 'Brasas', effect: 'normal' }, { element: 'Fire', damage: 2, name: 'Llama', effect: 'normal' }, { element: 'Fire', damage: 1, name: 'Mechero', effect: 'preventIce' }]; for (var k = 0; k < fireCards.length; k++) { playerDeck.push(fireCards[k]); } } else if (elements[i] === 'Air') { // Add specific air cards with names and effects var airCards = [{ element: 'Air', damage: 2, name: 'Vendaval', effect: 'normal' }, { element: 'Air', damage: 1, name: 'Brisa', effect: 'normal' }, { element: 'Air', damage: 2, name: 'Huracán', effect: 'replaceCards' }, { element: 'Air', damage: 3, name: 'Tormenta', effect: 'stormSkip' }]; for (var k = 0; k < airCards.length; k++) { playerDeck.push(airCards[k]); } // Add one more air card to make 5 total playerDeck.push({ element: 'Air', damage: 1, name: 'Brisa', effect: 'normal' }); } else if (elements[i] === 'Water') { // Add specific water cards with names and effects var waterCards = [{ element: 'Water', damage: 1, name: 'Gota de agua', effect: 'normal' }, { element: 'Water', damage: 2, name: 'Luna roja', effect: 'normal' }, { element: 'Water', damage: 0, name: 'Agua oxigenada', effect: 'heal' }, { element: 'Water', damage: 2, name: 'Marea', effect: 'normal' }, { element: 'Water', damage: 1, name: 'Pirata', effect: 'steal' }]; for (var k = 0; k < waterCards.length; k++) { playerDeck.push(waterCards[k]); } } else if (elements[i] === 'Rock') { // Add specific rock/earth cards with names and effects var rockCards = [{ element: 'Rock', damage: 2, name: 'Pedrada', effect: 'normal' }, { element: 'Rock', damage: 2, name: 'Tormenta de arena', effect: 'normal' }, { element: 'Rock', damage: 2, name: 'Sarcófago', effect: 'damageAndHeal' }, { element: 'Rock', damage: 0, name: 'Muralla Rocosa', effect: 'shield' }, { element: 'Rock', damage: 2, name: 'Terremoto', effect: 'replaceAllCards' }]; for (var k = 0; k < rockCards.length; k++) { playerDeck.push(rockCards[k]); } } else if (elements[i] === 'Plant') { // Add specific plant cards with names and effects var plantCards = [{ element: 'Plant', damage: 2, name: 'Arboleda', effect: 'normal' }, { element: 'Plant', damage: 0, name: 'Serafín', effect: 'heal' }, { element: 'Plant', damage: 1, name: 'Rama', effect: 'normal' }, { element: 'Plant', damage: 0, name: 'Vida extra', effect: 'increaseMaxHealth' }, { element: 'Plant', damage: 2, name: 'Aullidos del bosque', effect: 'skipEnemyTurn' }]; for (var k = 0; k < plantCards.length; k++) { playerDeck.push(plantCards[k]); } } else if (elements[i] === 'Ice') { // Add specific ice cards with names and effects var iceCards = [{ element: 'Ice', damage: 2, name: 'Nevada', effect: 'normal' }, { element: 'Ice', damage: 2, name: 'Ventisca', effect: 'blizzard' }, { element: 'Ice', damage: 1, name: 'Bola de nieve', effect: 'normal' }, { element: 'Ice', damage: 2, name: 'Hombre de nieve', effect: 'snowmanAttack' }]; for (var k = 0; k < iceCards.length; k++) { playerDeck.push(iceCards[k]); } // Add one more ice card to make 5 total playerDeck.push({ element: 'Ice', damage: 1, name: 'Bola de nieve', effect: 'normal' }); } else { for (var j = 0; j < 5; j++) { var damage = 1; playerDeck.push({ element: elements[i], damage: damage }); } } } } function createEnemyDeck(difficulty) { var deck = []; var elements = ['Fire', 'Water', 'Air', 'Plant', 'Rock', 'Ice']; var cardCount = 15 + difficulty * 5; for (var i = 0; i < cardCount; i++) { var element = elements[Math.floor(Math.random() * elements.length)]; var damage = 1 + Math.floor(Math.random() * (difficulty + 1)); deck.push({ element: element, damage: damage }); } return deck; } function initializeEnemies() { if (gameMode === 'adventure') { // Adventure mode: 6 courses with 3 battles each enemies = []; var courseNames = ['Apprentice', 'Novice', 'Scholar', 'Expert', 'Master', 'Grandmaster']; var battleTitles = ['Guard', 'Defender', 'Champion']; var battleIndex = 0; for (var course = 0; course < 6; course++) { for (var battle = 0; battle < 3; battle++) { var health = 5 + course * 3 + battle * 2; // Increasing health per course and battle var name = courseNames[course] + ' ' + battleTitles[battle]; enemies.push(new Enemy(name, health, course, battleIndex)); battleIndex++; } } } else { // Roguelike mode (original) enemies = [new Enemy('Tutorial Apprentice', 5, 0), new Enemy('Novice Mage', 8, 1), new Enemy('Advanced Scholar', 12, 2), new Enemy('Master Wizard', 15, 3)]; } } function createMenu() { menuContainer.removeChildren(); var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); menuContainer.addChild(bg); // Magical school background var magicSchool = LK.getAsset('magicSchool', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 900 }); menuContainer.addChild(magicSchool); // Add magical towers and buildings var leftTower = LK.getAsset('academy', { anchorX: 0.5, anchorY: 1, x: 400, y: 1200, scaleX: 0.8, scaleY: 1.2 }); menuContainer.addChild(leftTower); var rightTower = LK.getAsset('academy', { anchorX: 0.5, anchorY: 1, x: 1648, y: 1200, scaleX: 0.8, scaleY: 1.2 }); menuContainer.addChild(rightTower); var mainBuilding = LK.getAsset('academy', { anchorX: 0.5, anchorY: 1, x: 1024, y: 1300, scaleX: 1.5, scaleY: 1.0 }); menuContainer.addChild(mainBuilding); var titleText = new Text2('MAGICAL ACADEMY', { size: 120, fill: 0xFFD700, font: "'Arial Black', Arial, sans-serif", stroke: 0x4B0082, strokeThickness: 25 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 200; menuContainer.addChild(titleText); // Add magical glow effect with pulsing animation tween(titleText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(titleText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Create infinite loop by calling the animation again tween(titleText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(titleText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 2000, easing: tween.easeInOut }); } }); } }); } }); // Add magical color shifting effect var _colorCycle = function colorCycle() { tween(titleText, { tint: 0xFF69B4 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(titleText, { tint: 0x00FFFF }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(titleText, { tint: 0xFFD700 }, { duration: 1500, easing: tween.easeInOut, onFinish: _colorCycle }); } }); } }); }; _colorCycle(); var adventureButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1450 }); menuContainer.addChild(adventureButton); var adventureText = new Text2('Adventure Mode', { size: 50, fill: 0xFFFFFF }); adventureText.anchor.set(0.5, 0.5); adventureText.x = 1024; adventureText.y = 1450; menuContainer.addChild(adventureText); adventureButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); LK.setTimeout(function () { LK.playMusic('Academia3', { fade: { start: 0, end: 1, duration: 500 } }); }, 500); gameMode = 'adventure'; // Start from the next uncompleted course currentBattle = completedCourses * 3; startBattle(); }; var roguelikeButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1650 }); menuContainer.addChild(roguelikeButton); var roguelikeText = new Text2('Roguelike Mode', { size: 50, fill: 0xFFFFFF }); roguelikeText.anchor.set(0.5, 0.5); roguelikeText.x = 1024; roguelikeText.y = 1650; menuContainer.addChild(roguelikeText); roguelikeButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); LK.setTimeout(function () { LK.playMusic('Roguelite', { fade: { start: 0, end: 1, duration: 500 } }); }, 500); gameMode = 'roguelike'; startBattle(); }; if (roguelikeLevel > 0) { var recordText = new Text2('Roguelike Record: Level ' + roguelikeLevel, { size: 40, fill: 0xFFD700 }); recordText.anchor.set(0.5, 0.5); recordText.x = 1024; recordText.y = 1850; menuContainer.addChild(recordText); } if (completedCourses > 0) { var adventureText = new Text2('Adventure Progress: ' + completedCourses + '/6 Courses Completed', { size: 40, fill: 0x00FF00 }); adventureText.anchor.set(0.5, 0.5); adventureText.x = 1024; adventureText.y = 1900; menuContainer.addChild(adventureText); } // Fire Book Button var fireBookButton = LK.getAsset('fireCard', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 2100 }); menuContainer.addChild(fireBookButton); var fireBookText = new Text2('Fire\nBook', { size: 40, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); fireBookText.anchor.set(0.5, 0.5); fireBookText.x = 200; fireBookText.y = 2100; menuContainer.addChild(fireBookText); fireBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Fire'); }; // Water Book Button var waterBookButton = LK.getAsset('waterCard', { anchorX: 0.5, anchorY: 0.5, x: 400, y: 2100 }); menuContainer.addChild(waterBookButton); var waterBookText = new Text2('Water\nBook', { size: 40, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); waterBookText.anchor.set(0.5, 0.5); waterBookText.x = 400; waterBookText.y = 2100; menuContainer.addChild(waterBookText); waterBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Water'); }; // Air Book Button var airBookButton = LK.getAsset('airCard', { anchorX: 0.5, anchorY: 0.5, x: 600, y: 2100 }); menuContainer.addChild(airBookButton); var airBookText = new Text2('Air\nBook', { size: 40, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); airBookText.anchor.set(0.5, 0.5); airBookText.x = 600; airBookText.y = 2100; menuContainer.addChild(airBookText); airBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Air'); }; // Plant Book Button var plantBookButton = LK.getAsset('plantCard', { anchorX: 0.5, anchorY: 0.5, x: 800, y: 2100 }); menuContainer.addChild(plantBookButton); var plantBookText = new Text2('Plant\nBook', { size: 40, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); plantBookText.anchor.set(0.5, 0.5); plantBookText.x = 800; plantBookText.y = 2100; menuContainer.addChild(plantBookText); plantBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Plant'); }; // Rock Book Button var rockBookButton = LK.getAsset('rockCard', { anchorX: 0.5, anchorY: 0.5, x: 1000, y: 2100 }); menuContainer.addChild(rockBookButton); var rockBookText = new Text2('Rock\nBook', { size: 40, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); rockBookText.anchor.set(0.5, 0.5); rockBookText.x = 1000; rockBookText.y = 2100; menuContainer.addChild(rockBookText); rockBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Rock'); }; // Ice Book Button var iceBookButton = LK.getAsset('iceCard', { anchorX: 0.5, anchorY: 0.5, x: 1200, y: 2100 }); menuContainer.addChild(iceBookButton); var iceBookText = new Text2('Ice\nBook', { size: 40, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); iceBookText.anchor.set(0.5, 0.5); iceBookText.x = 1200; iceBookText.y = 2100; menuContainer.addChild(iceBookText); iceBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Ice'); }; // Invocation Cards Book Button var invocationBookButton = LK.getAsset('fenix_invocation_card', { anchorX: 0.5, anchorY: 0.5, x: 1400, y: 2100 }); menuContainer.addChild(invocationBookButton); var invocationBookText = new Text2('Invocation\nBook', { size: 35, fill: 0x000000, font: "'Arial Black', Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3 }); invocationBookText.anchor.set(0.5, 0.5); invocationBookText.x = 1400; invocationBookText.y = 2100; menuContainer.addChild(invocationBookText); invocationBookButton.down = function () { LK.playMusic('Academia', { fade: { start: 1, end: 0, duration: 500 } }); showElementBook('Invocation'); }; game.addChild(menuContainer); } function createBattle() { battleContainer.removeChildren(); // Background var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); battleContainer.addChild(bg); // Player health playerHealthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0, x: 100, y: 100 }); battleContainer.addChild(playerHealthBar); playerHealthText = new Text2('HP: ' + playerHealth + '/' + playerMaxHealth, { size: 30, fill: 0xFFFFFF }); playerHealthText.anchor.set(0, 0.5); playerHealthText.x = 420; playerHealthText.y = 120; battleContainer.addChild(playerHealthText); // Player mana bar playerManaBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0, x: 100, y: 200, tint: 0x0066FF }); battleContainer.addChild(playerManaBar); playerManaText = new Text2('⚡: ' + playerMana + '/' + playerMaxMana, { size: 30, fill: 0xFFFFFF }); playerManaText.anchor.set(0, 0.5); playerManaText.x = 420; playerManaText.y = 220; battleContainer.addChild(playerManaText); // Player shield bar (initially hidden) playerShieldBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0, x: 100, y: 300, tint: 0x696969, alpha: 0 }); battleContainer.addChild(playerShieldBar); playerShieldText = new Text2('🛡: 0/0', { size: 30, fill: 0xFFFFFF }); playerShieldText.anchor.set(0, 0.5); playerShieldText.x = 420; playerShieldText.y = 320; playerShieldText.alpha = 0; battleContainer.addChild(playerShieldText); // Pass turn button passButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 1750, y: 350, scaleX: 0.6, scaleY: 0.6 }); battleContainer.addChild(passButton); var passText = new Text2('Pass\n(+10 ⚡)', { size: 25, fill: 0xFFFFFF }); passText.anchor.set(0.5, 0.5); passText.x = 1750; passText.y = 350; battleContainer.addChild(passText); passButton.down = function () { if (gameState === 'playerTurn') { // Restore full mana playerMana = playerMaxMana; updatePlayerMana(); endPlayerTurn(); } }; // Exit button to return to menu var exitButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 1750, y: 150, scaleX: 0.6, scaleY: 0.6 }); battleContainer.addChild(exitButton); var exitText = new Text2('Exit', { size: 30, fill: 0xFFFFFF }); exitText.anchor.set(0.5, 0.5); exitText.x = 1750; exitText.y = 150; battleContainer.addChild(exitText); exitButton.down = function () { gameState = 'menu'; game.removeChild(battleContainer); createMenu(); LK.playMusic('Academia', { fade: { start: 0, end: 1, duration: 500 } }); }; // Reset button for adventure mode if (gameMode === 'adventure') { var resetButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 1750, y: 250, scaleX: 0.6, scaleY: 0.6 }); battleContainer.addChild(resetButton); var resetText = new Text2('Reset', { size: 25, fill: 0xFFFFFF }); resetText.anchor.set(0.5, 0.5); resetText.x = 1750; resetText.y = 250; battleContainer.addChild(resetText); resetButton.down = function () { // Reset adventure progress completedCourses = 0; currentBattle = 0; storage.completedCourses = 0; storage.currentCourse = 0; storage.currentBattleInCourse = 0; // Reset player health playerHealth = 10; playerMaxHealth = 10; // Restart the first battle gameState = 'menu'; game.removeChild(battleContainer); createMenu(); LK.playMusic('Academia', { fade: { start: 0, end: 1, duration: 500 } }); }; } // Course and battle indicator for adventure mode if (gameMode === 'adventure') { var courseNumber = Math.floor(currentBattle / 3) + 1; var battleInCourse = currentBattle % 3 + 1; var courseText = new Text2('Course ' + courseNumber + ' - Battle ' + battleInCourse, { size: 35, fill: 0xFFD700 }); courseText.anchor.set(0.5, 0.5); courseText.x = 1024; courseText.y = 150; battleContainer.addChild(courseText); } // Turn indicator turnText = new Text2('Your Turn - Turn 1', { size: 40, fill: 0xFFFFFF }); turnText.anchor.set(0.5, 0.5); turnText.x = 1024; turnText.y = 200; battleContainer.addChild(turnText); // Battle text (removed course/battle display for adventure mode) if (gameMode === 'roguelike') { battleText = new Text2('Battle ' + (currentBattle + 1), { size: 60, fill: 0xFFFFFF }); battleText.anchor.set(0.5, 0.5); battleText.x = 1024; battleText.y = 300; battleContainer.addChild(battleText); } // Enemy currentEnemy = enemies[currentBattle]; currentEnemy.x = 1024; currentEnemy.y = 800; battleContainer.addChild(currentEnemy); // Add deck pile (face down) var deckPile = LK.getAsset('deckPile', { anchorX: 0.5, anchorY: 0.5, x: 1750, y: 1800 }); battleContainer.addChild(deckPile); var deckText = new Text2('Deck', { size: 30, fill: 0xFFFFFF }); deckText.anchor.set(0.5, 0.5); deckText.x = 1750; deckText.y = 1950; battleContainer.addChild(deckText); game.addChild(battleContainer); updatePlayerMana(); drawPlayerHand(); currentEnemy.drawHand(); } function drawPlayerHand() { // Remove existing hand for (var i = battleContainer.children.length - 1; i >= 0; i--) { var child = battleContainer.children[i]; if (child instanceof Card) { battleContainer.removeChild(child); } } playerHand = []; var handCardNames = []; // Track card names to prevent duplicates for (var i = 0; i < 3; i++) { if (playerDeck.length > 0) { var attempts = 0; var foundValidCard = false; while (attempts < 50 && !foundValidCard) { // Limit attempts to prevent infinite loop var randomIndex = Math.floor(Math.random() * playerDeck.length); var cardData = playerDeck[randomIndex]; // Check if this card name is already in hand var isDuplicate = false; for (var j = 0; j < handCardNames.length; j++) { if (handCardNames[j] === cardData.name) { isDuplicate = true; break; } } // Use card if it's not a duplicate if (!isDuplicate) { var card = new Card(cardData.element, cardData.damage, cardData.name, cardData.effect); card.x = 400 + i * 350; card.y = 1800; playerHand.push(card); battleContainer.addChild(card); handCardNames.push(cardData.name); foundValidCard = true; } attempts++; } } } } function playCard(card) { if (gameState !== 'playerTurn') return; if (playerMana < card.manaCost) return; card.isUsed = true; // Consume mana playerMana -= card.manaCost; updatePlayerMana(); LK.getSound('cardPlay').play(); playElementSound(card.element); // Apply card effects var damage = card.damage; var element = card.element; // Fire element invocation animation if (element === 'Fire') { // Create the invoked asset that will fly to the enemy var invokedAsset = LK.getAsset(getCardImageId(card.name), { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, alpha: 0.9 }); // Start at card position invokedAsset.x = card.x; invokedAsset.y = card.y; battleContainer.addChild(invokedAsset); // Animate the asset flying to the enemy tween(invokedAsset, { x: currentEnemy.x, y: currentEnemy.y, scaleX: 1.2, scaleY: 1.2, rotation: Math.PI * 2 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Impact effect - flash the asset and make it bigger momentarily tween(invokedAsset, { scaleX: 2.0, scaleY: 2.0, alpha: 0.3, tint: 0xFFFFFF }, { duration: 200, onFinish: function onFinish() { // Remove the invoked asset after impact battleContainer.removeChild(invokedAsset); // Apply damage and effects after animation applyFireCardEffects(card, damage); } }); } }); } else { // Non-fire cards apply effects immediately applyCardEffects(card, damage, element); } } // Helper function to apply fire card effects after animation function applyFireCardEffects(card, damage) { switch (card.effect) { case 'chooseBurn': // Llamarada - deal 3 damage and let player choose card to burn if (currentEnemy.hand.length > 0) { var burnIndex = Math.floor(Math.random() * currentEnemy.hand.length); currentEnemy.removeCardFromHand(burnIndex); } break; case 'heal': // Fénix - deal 2 damage and heal 2 HP playerHealth = Math.min(playerHealth + 2, playerMaxHealth); updatePlayerHealth(); break; case 'preventIce': // Mechero - deal 1 damage and prevent enemy from using ice cards next turn currentEnemy.iceBlocked = true; break; default: // Brasas and Llama - deal 2 damage normally if (currentEnemy.hand.length > 0) { var burnIndex = Math.floor(Math.random() * currentEnemy.hand.length); currentEnemy.removeCardFromHand(burnIndex); } break; } // Apply damage and continue with battle logic currentEnemy.takeDamage(damage); LK.getSound('damage').play(); finishCardPlay(card); } // Helper function to apply non-fire card effects immediately function applyCardEffects(card, damage, element) { // Check if this is an entity card that needs invocation animation var entityCards = ['Fénix', 'Serafín', 'Aullidos del bosque', 'Pirata', 'Sarcófago', 'Hombre de nieve', 'Bola de nieve', 'Pedrada', 'Momia']; if (entityCards.indexOf(card.name) !== -1) { invokeEntityCard(card, damage, element); return; } switch (element) { case 'Water': // Handle special water card effects if (card.effect === 'heal') { // Agua oxigenada - heal 3 HP (no damage) playerHealth = Math.min(playerHealth + 3, playerMaxHealth); updatePlayerHealth(); damage = 0; // No damage dealt } else if (card.effect === 'steal') { // Pirata - let player choose which card to steal if (currentEnemy.hand.length > 0 && playerHand.length < 3) { showCardStealInterface(); return; // Don't continue with normal card play flow yet } } break; case 'Plant': // Handle special plant card effects if (card.effect === 'increaseMaxHealth') { // Vida extra - increase max health by 1 playerMaxHealth += 1; updatePlayerHealth(); damage = 0; // No damage dealt } // Standard damage for arboleda and rama break; case 'Air': // Handle special air card effects if (card.effect === 'replaceCards') { // Huracán - deal 2 damage and replace enemy's 3 cards with random ones from their deck currentEnemy.drawHand(); } else if (card.effect === 'stormSkip') { // Tormenta - deal 3 damage and 10% chance enemy can't attack next turn if (Math.random() < 0.1) { currentEnemy.isFrozen = true; } } else { // Vendaval and Brisa - standard damage without replacing cards } break; case 'Rock': // Handle special rock card effects if (card.effect === 'shield') { // Muralla Rocosa - create shield with 4 health if (!playerShield) { playerShield = { health: 4, maxHealth: 4 }; updateShieldDisplay(); damage = 0; // No damage dealt } } else if (card.effect === 'replaceAllCards') { // Terremoto - deal 2 damage to enemy and both players get new cards currentEnemy.drawHand(); drawPlayerHand(); } // Standard damage for all rock cards break; case 'Ice': // Handle special ice card effects if (card.effect === 'blizzard') { // Ventisca - deal 2 damage and 10% chance enemy can't attack next turn if (Math.random() < 0.1) { currentEnemy.isFrozen = true; } } else { // Nevada and Bola de nieve - freeze enemy for next turn + damage currentEnemy.isFrozen = true; } break; } // Apply damage and finish card play currentEnemy.takeDamage(damage); LK.getSound('damage').play(); finishCardPlay(card); } // Helper function to invoke entity cards with special animations function invokeEntityCard(card, damage, element) { var centerX = 1024; var centerY = 1366; switch (card.name) { case 'Fénix': // Phoenix rises from ashes in center and attacks with fire var ashes = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.2, tint: 0x404040, alpha: 0.8 }); ashes.x = centerX; ashes.y = centerY; battleContainer.addChild(ashes); var phoenix = LK.getAsset('Fenix', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); phoenix.x = centerX; phoenix.y = centerY; battleContainer.addChild(phoenix); // Phoenix emerges from ashes tween(phoenix, { scaleX: 1.2, scaleY: 1.2, alpha: 1 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Phoenix breathes fire at enemy tween(phoenix, { rotation: -0.3, scaleX: 1.4, scaleY: 1.4 }, { duration: 300, onFinish: function onFinish() { // Fire effect towards enemy var fireBreath = LK.getAsset('llamarada', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, alpha: 0.9 }); fireBreath.x = centerX; fireBreath.y = centerY; battleContainer.addChild(fireBreath); tween(fireBreath, { x: currentEnemy.x, y: currentEnemy.y, scaleX: 1.5, scaleY: 1.5, rotation: Math.PI }, { duration: 500, onFinish: function onFinish() { // White healing aura for player var healingAura = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, tint: 0xFFFFFF, alpha: 0.3 }); healingAura.x = 1024; healingAura.y = 1800; battleContainer.addChild(healingAura); tween(healingAura, { scaleX: 2.0, scaleY: 2.0, alpha: 0 }, { duration: 800, onFinish: function onFinish() { battleContainer.removeChild(healingAura); } }); // Apply effects currentEnemy.takeDamage(damage); playerHealth = Math.min(playerHealth + 2, playerMaxHealth); updatePlayerHealth(); LK.getSound('damage').play(); // Clean up battleContainer.removeChild(fireBreath); battleContainer.removeChild(phoenix); battleContainer.removeChild(ashes); finishCardPlay(card); } }); } }); } }); break; case 'Serafín': // Seraph appears facing player and heals with green aura var seraph = LK.getAsset('serafin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); seraph.x = centerX; seraph.y = centerY; battleContainer.addChild(seraph); tween(seraph, { scaleX: 1.3, scaleY: 1.3, alpha: 1 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Green healing aura towards player var greenAura = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, tint: 0x00FF00, alpha: 0.6 }); greenAura.x = 1024; greenAura.y = 1800; battleContainer.addChild(greenAura); tween(greenAura, { scaleX: 2.5, scaleY: 2.5, alpha: 0 }, { duration: 1000, onFinish: function onFinish() { battleContainer.removeChild(greenAura); } }); // Apply healing playerHealth = Math.min(playerHealth + 2, playerMaxHealth); updatePlayerHealth(); LK.getSound('Curar').play(); // Clean up LK.setTimeout(function () { battleContainer.removeChild(seraph); finishCardPlay(card); }, 800); } }); break; case 'Aullidos del bosque': // Environment becomes forest with wolf howls and two wolves attack var forestBg = LK.getAsset('arboleda', { anchorX: 0.5, anchorY: 0.5, scaleX: 7.0, scaleY: 4.0, alpha: 0 }); forestBg.x = centerX; forestBg.y = centerY; battleContainer.addChild(forestBg); tween(forestBg, { alpha: 0.7 }, { duration: 500, onFinish: function onFinish() { // Two wolves appear and attack enemy (using Lobos asset without background) var wolf1 = LK.getAsset('Lobos', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, alpha: 0 }); wolf1.x = centerX - 200; wolf1.y = centerY + 100; battleContainer.addChild(wolf1); var wolf2 = LK.getAsset('Lobos', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, alpha: 0 }); wolf2.x = centerX + 200; wolf2.y = centerY + 100; battleContainer.addChild(wolf2); // Wolves appear and leap at enemy tween(wolf1, { alpha: 1 }, { duration: 300 }); tween(wolf2, { alpha: 1 }, { duration: 300 }); LK.setTimeout(function () { tween(wolf1, { x: currentEnemy.x - 100, y: currentEnemy.y, scaleX: 1.2, scaleY: 1.2 }, { duration: 600 }); tween(wolf2, { x: currentEnemy.x + 100, y: currentEnemy.y, scaleX: -1.2, scaleY: 1.2 }, { duration: 600, onFinish: function onFinish() { // Apply effects currentEnemy.takeDamage(damage); currentEnemy.isFrozen = true; LK.getSound('Aullidos').play(); LK.getSound('Aullidos').play(null, 1.5); // Clean up LK.setTimeout(function () { tween(forestBg, { alpha: 0 }, { duration: 500 }); battleContainer.removeChild(wolf1); battleContainer.removeChild(wolf2); LK.setTimeout(function () { battleContainer.removeChild(forestBg); finishCardPlay(card); }, 500); }, 800); } }); }, 500); } }); break; case 'Pedrada': // Rock throw appears in center and flies to enemy (reusing snowball animation) var rock = LK.getAsset('pedrada', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); rock.x = centerX; rock.y = centerY; battleContainer.addChild(rock); tween(rock, { x: currentEnemy.x, y: currentEnemy.y, scaleX: 1.2, scaleY: 1.2, rotation: Math.PI * 3 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Apply effects currentEnemy.takeDamage(damage); LK.getSound('damage').play(); // Impact effect tween(rock, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { battleContainer.removeChild(rock); finishCardPlay(card); } }); } }); break; case 'Pirata': // Pirate appears and strikes enemy with hook, then offers card steal choice var pirate = LK.getAsset('Pirata', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); pirate.x = centerX; pirate.y = centerY; battleContainer.addChild(pirate); tween(pirate, { scaleX: 1.4, scaleY: 1.4, alpha: 1 }, { duration: 500, easing: tween.bounceOut, onFinish: function onFinish() { // Pirate swings hook at enemy tween(pirate, { x: currentEnemy.x - 150, y: currentEnemy.y, rotation: -0.5 }, { duration: 400, onFinish: function onFinish() { // Apply effects currentEnemy.takeDamage(damage); LK.getSound('damage').play(); // Card steal effect - show interface for player to choose if (currentEnemy.hand.length > 0 && playerHand.length < 3) { LK.setTimeout(function () { showCardStealInterface(); }, 800); // Delay to let pirate animation finish } // Clean up LK.setTimeout(function () { battleContainer.removeChild(pirate); finishCardPlay(card); }, 600); } }); } }); break; case 'Sarcófago': // Create sand pile (Arena asset) in center of battle var sandPile = LK.getAsset('Arena', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2, alpha: 0.8 }); sandPile.x = centerX; sandPile.y = centerY + 150; battleContainer.addChild(sandPile); // Sarcophagus starts buried under sand var sarcophagus = LK.getAsset('sarcofago', { anchorX: 0.5, anchorY: 1.0, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); sarcophagus.x = centerX; sarcophagus.y = centerY + 150; battleContainer.addChild(sarcophagus); // Sarcophagus emerges from sand pile tween(sarcophagus, { scaleX: 1.2, scaleY: 1.2, alpha: 1, y: centerY - 50 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Sarcophagus opens with dramatic effect tween(sarcophagus, { scaleX: 1.8, scaleY: 1.1 }, { duration: 500, easing: tween.bounceOut, onFinish: function onFinish() { // Mummy emerges from the sarcophagus and appears on top of Arena var mummy = LK.getAsset('Momia', { anchorX: 0.5, anchorY: 1.0, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); mummy.x = centerX; mummy.y = centerY + 100; // Position on top of Arena asset battleContainer.addChild(mummy); // Mummy appears with growing animation tween(mummy, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Mummy attacks enemy with right hand (slight rotation and movement) tween(mummy, { rotation: -0.3, x: centerX + 50 }, { duration: 300, onFinish: function onFinish() { // Apply damage from mummy's right hand attack currentEnemy.takeDamage(damage); LK.getSound('damage').play(); // Mummy extends left hand with healing bandages toward player tween(mummy, { rotation: 0.3, x: centerX - 50 }, { duration: 400, onFinish: function onFinish() { // Healing bandages fly from mummy's left hand to player var healingBandages = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 1.5, tint: 0xF5DEB3, alpha: 0.9 }); healingBandages.x = centerX - 50; healingBandages.y = centerY - 50; battleContainer.addChild(healingBandages); // Animate bandages wrapping around player tween(healingBandages, { x: 1024, y: 1800, scaleX: 1.5, scaleY: 2.5, rotation: Math.PI * 2 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Create green healing aura around player var greenAura = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, tint: 0x00FF00, alpha: 0.7 }); greenAura.x = 1024; greenAura.y = 1800; battleContainer.addChild(greenAura); // Green aura pulsing effect tween(greenAura, { scaleX: 3.0, scaleY: 3.0, alpha: 0 }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { battleContainer.removeChild(greenAura); } }); // Apply healing playerHealth = Math.min(playerHealth + 2, playerMaxHealth); updatePlayerHealth(); battleContainer.removeChild(healingBandages); } }); // Clean up after complete animation LK.setTimeout(function () { battleContainer.removeChild(mummy); battleContainer.removeChild(sarcophagus); battleContainer.removeChild(sandPile); finishCardPlay(card); }, 1500); } }); } }); } }); } }); } }); break; case 'Momia': // Mummy appears on top of Arena asset in battle center var arenaBase = LK.getAsset('Arena', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2, alpha: 0.8 }); arenaBase.x = centerX; arenaBase.y = centerY; battleContainer.addChild(arenaBase); var mummy = LK.getAsset('Momia', { anchorX: 0.5, anchorY: 1.0, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); mummy.x = centerX; mummy.y = centerY; battleContainer.addChild(mummy); // Mummy appears with growing animation on Arena tween(mummy, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Apply effects currentEnemy.takeDamage(damage); LK.getSound('damage').play(); // Clean up LK.setTimeout(function () { battleContainer.removeChild(mummy); battleContainer.removeChild(arenaBase); finishCardPlay(card); }, 800); } }); break; case 'Hombre de nieve': // Snowman appears and throws snowball at enemy var snowman = LK.getAsset('hombre_de_nieve', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); snowman.x = centerX; snowman.y = centerY; battleContainer.addChild(snowman); tween(snowman, { scaleX: 1.3, scaleY: 1.3, alpha: 1 }, { duration: 500, easing: tween.bounceOut, onFinish: function onFinish() { // Snowman throws snowball var snowball = LK.getAsset('bola_de_nieve', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); snowball.x = centerX; snowball.y = centerY; battleContainer.addChild(snowball); tween(snowball, { x: currentEnemy.x, y: currentEnemy.y, scaleX: 1.0, scaleY: 1.0, rotation: Math.PI * 3 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Apply effects currentEnemy.takeDamage(damage); currentEnemy.hasExtraAttack = true; LK.getSound('Bola_de_nieve').play(); // Impact effect tween(snowball, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { battleContainer.removeChild(snowball); } }); // Clean up LK.setTimeout(function () { battleContainer.removeChild(snowman); finishCardPlay(card); }, 800); } }); } }); break; case 'Bola de nieve': // Snowball appears in center and flies to enemy (reusing snowman animation) var snowball = LK.getAsset('bola_de_nieve', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); snowball.x = centerX; snowball.y = centerY; battleContainer.addChild(snowball); tween(snowball, { x: currentEnemy.x, y: currentEnemy.y, scaleX: 1.2, scaleY: 1.2, rotation: Math.PI * 3 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Apply effects currentEnemy.takeDamage(damage); currentEnemy.isFrozen = true; LK.getSound('Bola_de_nieve').play(); // Impact effect tween(snowball, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { battleContainer.removeChild(snowball); finishCardPlay(card); } }); } }); break; } } // Helper function to show card steal interface when Pirata is used function showCardStealInterface() { if (currentEnemy.hand.length === 0) return; // Create steal interface container var stealContainer = new Container(); // Semi-transparent background var stealBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, alpha: 0.8 }); stealContainer.addChild(stealBg); // Title text var stealTitleText = new Text2('Choose a card to steal:', { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); stealTitleText.anchor.set(0.5, 0.5); stealTitleText.x = 1024; stealTitleText.y = 600; stealContainer.addChild(stealTitleText); // Display enemy cards in center for selection var stealCards = []; for (var i = 0; i < currentEnemy.hand.length; i++) { var enemyCardData = currentEnemy.hand[i]; var stealCard = new Card(enemyCardData.element, enemyCardData.damage, enemyCardData.name || enemyCardData.element, enemyCardData.effect || 'normal'); stealCard.x = 1024 + (i - 1) * 350; // Center cards around screen center stealCard.y = 1200; stealCard.cardIndex = i; // Store original index for removal // Override down handler for stealing stealCard.down = function (x, y, obj) { var selectedIndex = obj.cardIndex; var stolenCardData = currentEnemy.hand[selectedIndex]; // Remove card from enemy hand currentEnemy.removeCardFromHand(selectedIndex); // Add stolen card to player hand var stolenCard = new Card(stolenCardData.element, stolenCardData.damage, stolenCardData.name || stolenCardData.element, stolenCardData.effect || 'normal'); stolenCard.x = 400 + playerHand.length * 350; stolenCard.y = 1800; playerHand.push(stolenCard); battleContainer.addChild(stolenCard); // Remove steal interface game.removeChild(stealContainer); // Continue with normal card play flow currentEnemy.takeDamage(1); // Pirata deals 1 damage LK.getSound('damage').play(); // Check if enemy is defeated if (currentEnemy.health === 0) { LK.getSound('victory').play(); currentBattle++; // Handle victory logic... if (gameMode === 'roguelike') { playerHealth = Math.min(playerHealth + 1, 10); if (currentBattle > roguelikeLevel) { roguelikeLevel = currentBattle; storage.highestLevel = roguelikeLevel; } } else { var courseNumber = Math.floor((currentBattle - 1) / 3); var battleInCourse = (currentBattle - 1) % 3 + 1; playerHealth = playerMaxHealth; if (battleInCourse === 3) { completedCourses = courseNumber + 1; storage.completedCourses = completedCourses; showCourseCompletionAnimation(courseNumber + 1); } } updatePlayerHealth(); if (currentBattle >= enemies.length) { LK.showYouWin(); } else { LK.setTimeout(function () { createBattle(); gameState = 'playerTurn'; turnText.setText('Your Turn - Turn 1'); }, 2000); } return; } // Continue to next turn endPlayerTurn(); }; stealContainer.addChild(stealCard); stealCards.push(stealCard); } game.addChild(stealContainer); } // Helper function for enemy pirata card steal interface function showEnemyCardStealInterface() { if (playerHand.length === 0) return; // Create steal interface container var enemyStealContainer = new Container(); // Semi-transparent background var enemyStealBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, alpha: 0.8 }); enemyStealContainer.addChild(enemyStealBg); // Title text var enemyStealTitleText = new Text2('Enemy is choosing a card to steal...', { size: 60, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 3 }); enemyStealTitleText.anchor.set(0.5, 0.5); enemyStealTitleText.x = 1024; enemyStealTitleText.y = 600; enemyStealContainer.addChild(enemyStealTitleText); // Display player cards in center (non-interactive) var displayCards = []; for (var i = 0; i < playerHand.length; i++) { var playerCardData = playerHand[i]; var displayCard = new Card(playerCardData.element, playerCardData.damage, playerCardData.name, playerCardData.effect); displayCard.x = 1024 + (i - 1) * 350; displayCard.y = 1200; displayCard.isUsed = true; // Make non-interactive enemyStealContainer.addChild(displayCard); displayCards.push(displayCard); } game.addChild(enemyStealContainer); // After 2 seconds, enemy makes selection and removes interface LK.setTimeout(function () { // Enemy steals a random card var stealIndex = Math.floor(Math.random() * playerHand.length); var stolenCard = playerHand[stealIndex]; var stolenCardData = { element: stolenCard.element, damage: stolenCard.damage, name: stolenCard.name, effect: stolenCard.effect }; // Remove from player hand playerHand.splice(stealIndex, 1); battleContainer.removeChild(stolenCard); // Add to enemy hand currentEnemy.hand.push(stolenCardData); var enemyCard = new Card(stolenCardData.element, stolenCardData.damage, stolenCardData.name, stolenCardData.effect); enemyCard.x = -400 + currentEnemy.hand.length * 200 - 200; enemyCard.y = -400; enemyCard.scaleX = 0.6; enemyCard.scaleY = 0.6; currentEnemy.addChild(enemyCard); if (!currentEnemy.handCards) currentEnemy.handCards = []; currentEnemy.handCards.push(enemyCard); // Remove steal interface game.removeChild(enemyStealContainer); }, 2000); } // Helper function to finish card play logic function finishCardPlay(card) { // Remove card from hand var cardIndex = playerHand.indexOf(card); if (cardIndex !== -1) { playerHand.splice(cardIndex, 1); } battleContainer.removeChild(card); // Add used card to tracking array with turn counter playerUsedCards.push({ element: card.element, damage: card.damage, name: card.name, effect: card.effect }); // Mark card as unavailable for the next turn playerUnavailableCards.push({ element: card.element, damage: card.damage, name: card.name, effect: card.effect, turnsUnavailable: 1 }); // Check if enemy is defeated (must reach exactly 0 health) if (currentEnemy.health === 0) { LK.getSound('victory').play(); currentBattle++; // Handle victory based on game mode if (gameMode === 'roguelike') { // Add 1 health for winning a battle playerHealth = Math.min(playerHealth + 1, 10); // Update roguelike progress if (currentBattle > roguelikeLevel) { roguelikeLevel = currentBattle; storage.highestLevel = roguelikeLevel; } } else { // Adventure mode - handle course progression var courseNumber = Math.floor((currentBattle - 1) / 3); var battleInCourse = (currentBattle - 1) % 3 + 1; // Always restore full health after winning any battle in adventure mode playerHealth = playerMaxHealth; // If this was the third battle of a course, mark course as completed but don't change max health if (battleInCourse === 3) { completedCourses = courseNumber + 1; storage.completedCourses = completedCourses; // Course completion animation showCourseCompletionAnimation(courseNumber + 1); } } // Restore full mana after battle victory playerMana = playerMaxMana; updatePlayerMana(); // Update player health display after victory updatePlayerHealth(); if (currentBattle >= enemies.length) { // All battles won LK.showYouWin(); } else { // Next battle LK.setTimeout(function () { createBattle(); gameState = 'playerTurn'; turnText.setText('Your Turn - Turn 1'); }, 2000); } return; } endPlayerTurn(); } function endPlayerTurn() { // Clear player used cards for this turn (don't return to deck yet) playerUsedCards = []; gameState = 'enemyTurn'; turnText.setText('Enemy Turn - Turn ' + turnCounter); LK.setTimeout(function () { currentEnemy.playTurn(); }, 1000); } function enemyPlayCard(cardData, cardIndex) { // Consume enemy mana var manaCost = getCardManaCost(cardData.name || cardData.element, cardData.effect || 'normal'); currentEnemy.mana -= manaCost; playElementSound(cardData.element); var damage = cardData.damage; var element = cardData.element; // Track used card before removing enemyUsedCards.push({ element: cardData.element, damage: cardData.damage, name: cardData.name || cardData.element, effect: cardData.effect || 'normal' }); // Remove the played card from enemy hand currentEnemy.removeCardFromHand(cardIndex); // Check for snowman effect - hombre de nieve deals 2 damage and sets up future 1 damage if (cardData.name === 'Hombre de nieve') { // Deal 2 damage now playerHealth -= 2; // Set up 10% chance for 1 damage next turn currentEnemy.snowmanPendingDamage = true; } else { // Check if there's pending snowman damage from previous turn if (currentEnemy.snowmanPendingDamage) { if (Math.random() < 0.1) { // 10% chance to deal 1 additional damage playerHealth -= 1; } // Reset the pending damage flag currentEnemy.snowmanPendingDamage = false; } switch (element) { case 'Fire': // Fire burns one random player card + damage if (playerHand.length > 0) { var burnIndex = Math.floor(Math.random() * playerHand.length); var cardToBurn = playerHand[burnIndex]; playerHand.splice(burnIndex, 1); battleContainer.removeChild(cardToBurn); } damage += 2; break; case 'Water': // Handle water card effects if (cardData.effect === 'steal') { // Pirata - enemy shows card steal interface if (playerHand.length > 0 && currentEnemy.hand.length < 3) { showEnemyCardStealInterface(); return; // Don't continue with normal enemy turn flow yet } } break; case 'Air': drawPlayerHand(); break; case 'Ice': // Player frozen (skip next turn - handled in game flow) break; } // Apply damage through shield first if (playerShield && playerShield.health > 0 && damage > 0) { var shieldAbsorbed = Math.min(damage, playerShield.health); playerShield.health -= shieldAbsorbed; damage -= shieldAbsorbed; updateShieldDisplay(); if (damage > 0) { playerHealth -= damage; } } else if (damage > 0) { playerHealth -= damage; } } if (playerHealth < 0) playerHealth = 0; updatePlayerHealth(); LK.getSound('damage').play(); if (playerHealth === 0) { // In roguelike mode, track the level where player died if (gameMode === 'roguelike' && currentBattle > roguelikeLevel) { roguelikeLevel = currentBattle; storage.highestLevel = roguelikeLevel; } // Reset mana to full when battle ends playerMana = playerMaxMana; updatePlayerMana(); LK.showGameOver(); return; } endEnemyTurn(); } function endEnemyTurn() { // Enemy's turn is complete - return their used cards to deck for (var i = 0; i < enemyUsedCards.length; i++) { currentEnemy.deck.push(enemyUsedCards[i]); } // Clear enemy used cards for this turn enemyUsedCards = []; // Complete turn cycle - both player and enemy have played, now start new complete turn turnCounter++; // Update player card availability system after complete turn cycle for (var i = playerUnavailableCards.length - 1; i >= 0; i--) { playerUnavailableCards[i].turnsUnavailable--; // If card has been unavailable for one complete turn, return it to deck if (playerUnavailableCards[i].turnsUnavailable <= 0) { playerDeck.push({ element: playerUnavailableCards[i].element, damage: playerUnavailableCards[i].damage, name: playerUnavailableCards[i].name, effect: playerUnavailableCards[i].effect }); playerUnavailableCards.splice(i, 1); } } // Restore mana after complete turn cycle (except first turn) if (turnCounter > 1) { // Restore 3-5 mana for player, but never exceed max var manaToRestore = 3 + Math.floor(Math.random() * 3); // Random between 3-5 playerMana = Math.min(playerMana + manaToRestore, playerMaxMana); // Restore 3-5 mana for enemy, but never exceed max var enemyManaToRestore = 3 + Math.floor(Math.random() * 3); // Random between 3-5 currentEnemy.mana = Math.min(currentEnemy.mana + enemyManaToRestore, currentEnemy.maxMana); updatePlayerMana(); } // Clear all remaining cards from both hands to start fresh // Clear player hand for (var i = playerHand.length - 1; i >= 0; i--) { var card = playerHand[i]; battleContainer.removeChild(card); } playerHand = []; // Clear enemy hand if (currentEnemy.handCards) { for (var i = 0; i < currentEnemy.handCards.length; i++) { if (currentEnemy.handCards[i].parent) { currentEnemy.handCards[i].parent.removeChild(currentEnemy.handCards[i]); } } } currentEnemy.handCards = []; currentEnemy.hand = []; // PLAYER CARD REDISTRIBUTION FOR NEW COMPLETE TURN - Always draw 3 unique cards var playerHandNames = []; // Track card names to prevent duplicates for (var i = 0; i < 3; i++) { if (playerDeck.length > 0) { var attempts = 0; var foundValidCard = false; while (attempts < 50 && !foundValidCard) { // Limit attempts to prevent infinite loop var randomIndex = Math.floor(Math.random() * playerDeck.length); var cardData = playerDeck[randomIndex]; // Check if this card name is already in hand var isDuplicate = false; for (var j = 0; j < playerHandNames.length; j++) { if (playerHandNames[j] === cardData.name) { isDuplicate = true; break; } } // Check if this card is still unavailable (shouldn't happen after filtering above, but safety check) var isUnavailable = false; for (var k = 0; k < playerUnavailableCards.length; k++) { if (playerUnavailableCards[k].name === cardData.name) { isUnavailable = true; break; } } // Use card if it's not a duplicate and is available if (!isDuplicate && !isUnavailable) { playerDeck.splice(randomIndex, 1); // Remove from deck var card = new Card(cardData.element, cardData.damage, cardData.name, cardData.effect); card.x = 400 + i * 350; card.y = 1800; playerHand.push(card); battleContainer.addChild(card); playerHandNames.push(cardData.name); foundValidCard = true; } attempts++; } } } // ENEMY CARD REDISTRIBUTION FOR NEW COMPLETE TURN - Always draw 3 unique cards var enemyHandNames = []; // Track card names to prevent duplicates for (var i = 0; i < 3; i++) { if (currentEnemy.deck.length > 0) { var attempts = 0; var foundValidCard = false; while (attempts < 50 && !foundValidCard) { // Limit attempts to prevent infinite loop var randomIndex = Math.floor(Math.random() * currentEnemy.deck.length); var cardData = currentEnemy.deck[randomIndex]; var cardName = cardData.name || cardData.element; // Check if this card name is already in hand var isDuplicate = false; for (var j = 0; j < enemyHandNames.length; j++) { if (enemyHandNames[j] === cardName) { isDuplicate = true; break; } } // Use card if it's not a duplicate if (!isDuplicate) { currentEnemy.deck.splice(randomIndex, 1); // Remove from deck currentEnemy.hand.push(cardData); // Create visual card for enemy var enemyCard = new Card(cardData.element, cardData.damage, cardData.name || cardData.element, cardData.effect || 'normal'); enemyCard.x = -400 + i * 200; enemyCard.y = -400; enemyCard.scaleX = 0.6; enemyCard.scaleY = 0.6; currentEnemy.addChild(enemyCard); if (!currentEnemy.handCards) currentEnemy.handCards = []; currentEnemy.handCards.push(enemyCard); enemyHandNames.push(cardName); foundValidCard = true; } attempts++; } } } gameState = 'playerTurn'; turnText.setText('Your Turn - Turn ' + turnCounter); } function updatePlayerHealth() { var healthPercentage = playerHealth / playerMaxHealth; playerHealthBar.scaleX = healthPercentage; playerHealthText.setText('HP: ' + playerHealth + '/' + playerMaxHealth); } function updatePlayerMana() { var manaPercentage = playerMana / playerMaxMana; playerManaBar.scaleX = manaPercentage; playerManaText.setText('⚡: ' + playerMana + '/' + playerMaxMana); } function updateShieldDisplay() { if (playerShield && playerShield.health > 0) { var shieldPercentage = playerShield.health / playerShield.maxHealth; playerShieldBar.scaleX = shieldPercentage; playerShieldBar.alpha = 1; playerShieldText.setText('🛡: ' + playerShield.health + '/' + playerShield.maxHealth); playerShieldText.alpha = 1; } else { playerShieldBar.alpha = 0; playerShieldText.alpha = 0; playerShield = null; } } function startBattle() { gameState = 'battle'; // Reset card availability system for new battle playerUnavailableCards = []; if (gameMode === 'adventure') { // Start from first uncompleted battle currentBattle = completedCourses * 3; // Set health based on last completed course's final wizard if (completedCourses > 0) { // Get the last wizard from the previous completed course var lastCompletedCourse = completedCourses - 1; var lastWizardIndex = lastCompletedCourse * 3 + 2; // Third wizard of the course (index 2) if (lastWizardIndex < enemies.length) { var lastWizard = enemies[lastWizardIndex]; playerHealth = lastWizard.maxHealth; playerMaxHealth = lastWizard.maxHealth; // Store the max health for future reference storage.playerMaxHealth = playerMaxHealth; } else { playerHealth = 10; playerMaxHealth = 10; } } else { // First course - start with default health playerHealth = 10; playerMaxHealth = 10; } } else { // Roguelike mode currentBattle = 0; playerHealth = 10; playerMaxHealth = 10; } turnCounter = 0; playerMana = playerMaxMana; game.removeChild(menuContainer); createBattle(); gameState = 'playerTurn'; } function showElementBook(element) { // Create book container var bookContainer = new Container(); // Background var bookBg = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); bookContainer.addChild(bookBg); // Title var titleText = new Text2(element + ' Element Cards', { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 300; bookContainer.addChild(titleText); // Get element cards based on element type var elementCards = []; switch (element) { case 'Fire': elementCards = [{ name: 'Llamarada', damage: 3, effect: 'Inflige 3 de daño y quema una carta enemiga' }, { name: 'Fénix', damage: 2, effect: 'Inflige 2 de daño y cura 2 puntos de vida' }, { name: 'Brasas', damage: 2, effect: 'Inflige 2 de daño y quema una carta enemiga' }, { name: 'Llama', damage: 2, effect: 'Inflige 2 de daño y quema una carta enemiga' }, { name: 'Mechero', damage: 1, effect: 'Inflige 1 de daño y evita que el enemigo use cartas de hielo' }]; break; case 'Water': elementCards = [{ name: 'Gota de agua', damage: 1, effect: 'Inflige 1 de daño' }, { name: 'Luna roja', damage: 2, effect: 'Inflige 2 de daño' }, { name: 'Agua oxigenada', damage: 0, effect: 'Cura 3 puntos de vida' }, { name: 'Marea', damage: 2, effect: 'Inflige 2 de daño' }, { name: 'Pirata', damage: 1, effect: 'Inflige 1 de daño y roba una carta enemiga' }]; break; case 'Air': elementCards = [{ name: 'Vendaval', damage: 2, effect: 'Inflige 2 de daño' }, { name: 'Brisa', damage: 1, effect: 'Inflige 1 de daño' }, { name: 'Huracán', damage: 2, effect: 'Inflige 2 de daño y reemplaza las cartas enemigas' }, { name: 'Tormenta', damage: 3, effect: 'Inflige 3 de daño, 10% de probabilidad de saltar turno enemigo' }]; break; case 'Plant': elementCards = [{ name: 'Arboleda', damage: 2, effect: 'Inflige 2 de daño' }, { name: 'Serafín', damage: 0, effect: 'Cura 2 puntos de vida' }, { name: 'Rama', damage: 1, effect: 'Inflige 1 de daño' }, { name: 'Vida extra', damage: 0, effect: 'Aumenta la vida máxima en 1' }, { name: 'Aullidos del bosque', damage: 2, effect: 'Inflige 2 de daño, el enemigo pierde su turno' }]; break; case 'Rock': elementCards = [{ name: 'Pedrada', damage: 2, effect: 'Inflige 2 de daño' }, { name: 'Tormenta de arena', damage: 2, effect: 'Inflige 2 de daño' }, { name: 'Sarcófago', damage: 2, effect: 'Inflige 2 de daño y cura 2 puntos de vida' }, { name: 'Muralla Rocosa', damage: 0, effect: 'Crea escudo con 4 puntos de vida que absorbe daño' }, { name: 'Terremoto', damage: 2, effect: 'Inflige 2 de daño, ambos jugadores obtienen cartas nuevas' }]; break; case 'Ice': elementCards = [{ name: 'Nevada', damage: 2, effect: 'Inflige 2 de daño y congela al enemigo' }, { name: 'Ventisca', damage: 2, effect: 'Inflige 2 de daño, 10% de probabilidad de congelar' }, { name: 'Bola de nieve', damage: 1, effect: 'Inflige 1 de daño y congela al enemigo' }, { name: 'Hombre de nieve', damage: 2, effect: 'Inflige 2 de daño, puede atacar de nuevo por 1 de daño' }]; break; case 'Invocation': elementCards = [{ name: 'Fénix', damage: 2, effect: 'Inflige 2 de daño y cura 2 puntos de vida' }, { name: 'Pirata', damage: 1, effect: 'Inflige 1 de daño y roba una carta enemiga' }, { name: 'Serafín', damage: 0, effect: 'Cura 2 puntos de vida' }, { name: 'Sarcófago', damage: 2, effect: 'Inflige 2 de daño y cura 2 puntos de vida' }, { name: 'Hombre de nieve', damage: 2, effect: 'Inflige 2 de daño, puede atacar de nuevo por 1 de daño' }]; break; } // Display cards for (var i = 0; i < elementCards.length; i++) { var cardInfo = elementCards[i]; var yPos = 500 + i * 320; // Card name var nameText = new Text2(cardInfo.name, { size: 65, fill: 0xffffff, stroke: 0xffffff, strokeThickness: 3 }); nameText.anchor.set(0, 0.5); nameText.x = 200; nameText.y = yPos; bookContainer.addChild(nameText); // Damage var damageText = new Text2('Daño: ' + cardInfo.damage, { size: 55, fill: 0xffffff, stroke: 0xffffff, strokeThickness: 3 }); damageText.anchor.set(0, 0.5); damageText.x = 200; damageText.y = yPos + 60; bookContainer.addChild(damageText); // Effect var effectText = new Text2('Efecto: ' + cardInfo.effect, { size: 50, fill: 0xffffff, stroke: 0xffffff, strokeThickness: 3 }); effectText.anchor.set(0, 0.5); effectText.x = 200; effectText.y = yPos + 120; bookContainer.addChild(effectText); } // Back button var backButton = LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2400 }); bookContainer.addChild(backButton); var backText = new Text2('Back to Menu', { size: 40, fill: 0xFFFFFF }); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 2400; bookContainer.addChild(backText); backButton.down = function () { game.removeChild(bookContainer); LK.playMusic('Academia', { fade: { start: 0, end: 1, duration: 500 } }); }; game.addChild(bookContainer); } function showCourseCompletionAnimation(courseNumber) { // Create animation container var animContainer = new Container(); // Semi-transparent background var animBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, alpha: 0.8 }); animContainer.addChild(animBg); // Course completed text var completionText = new Text2('COURSE ' + courseNumber + ' COMPLETED!', { size: 80, fill: 0xFFD700, font: "'Arial Black', Arial, sans-serif", stroke: 0x4B0082, strokeThickness: 4 }); completionText.anchor.set(0.5, 0.5); completionText.x = 1024; completionText.y = 1366; completionText.alpha = 0; completionText.scaleX = 0.1; completionText.scaleY = 0.1; animContainer.addChild(completionText); // Star effects var stars = []; for (var i = 0; i < 5; i++) { var star = LK.getAsset('academy', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, scaleY: 0.2, tint: 0xFFD700 }); star.x = 1024 + (i - 2) * 200; star.y = 1000; star.alpha = 0; star.rotation = 0; animContainer.addChild(star); stars.push(star); } game.addChild(animContainer); // Animate text appearance tween(completionText, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 800, easing: tween.elasticOut }); // Animate stars for (var i = 0; i < stars.length; i++) { (function (star, delay) { LK.setTimeout(function () { tween(star, { alpha: 1, rotation: Math.PI * 2 }, { duration: 600, easing: tween.easeOut }); }, delay); })(stars[i], i * 150); } // Pulsing effect LK.setTimeout(function () { tween(completionText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(completionText, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeInOut }); } }); }, 1000); // Remove animation after 3 seconds LK.setTimeout(function () { tween(animContainer, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { game.removeChild(animContainer); // Check if all courses completed for graduation if (completedCourses >= 6) { showGraduationAnimation(); } } }); }, 3000); } function showGraduationAnimation() { // Create graduation container var gradContainer = new Container(); // Background var gradBg = LK.getAsset('background', { anchorX: 0, anchorY: 0, tint: 0x000050 }); gradContainer.addChild(gradBg); // Graduation text var gradText = new Text2('GRADUATION!', { size: 120, fill: 0xFFD700, font: "'Arial Black', Arial, sans-serif", stroke: 0xFFFFFF, strokeThickness: 6 }); gradText.anchor.set(0.5, 0.5); gradText.x = 1024; gradText.y = 1000; gradText.alpha = 0; gradText.scaleX = 0.1; gradText.scaleY = 0.1; gradContainer.addChild(gradText); // Congratulations text var congratsText = new Text2('¡Congratulations, Master Wizard!', { size: 60, fill: 0xFFFFFF, font: "'Arial Black', Arial, sans-serif" }); congratsText.anchor.set(0.5, 0.5); congratsText.x = 1024; congratsText.y = 1200; congratsText.alpha = 0; gradContainer.addChild(congratsText); // Academy building as graduation cap var academy = LK.getAsset('academy', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, tint: 0xFFD700 }); academy.x = 1024; academy.y = 600; academy.alpha = 0; academy.rotation = -Math.PI / 4; gradContainer.addChild(academy); // Fireworks effects var fireworks = []; for (var i = 0; i < 8; i++) { var firework = LK.getAsset('academy', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, tint: [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFD700, 0xFF4500][i] }); var angle = i / 8 * Math.PI * 2; firework.x = 1024 + Math.cos(angle) * 400; firework.y = 1366 + Math.sin(angle) * 400; firework.alpha = 0; firework.scaleX = 0.1; firework.scaleY = 0.1; gradContainer.addChild(firework); fireworks.push(firework); } game.addChild(gradContainer); // Animate academy tween(academy, { alpha: 1, rotation: 0 }, { duration: 1000, easing: tween.elasticOut }); // Animate main text LK.setTimeout(function () { tween(gradText, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 1200, easing: tween.bounceOut }); }, 500); // Animate congratulations text LK.setTimeout(function () { tween(congratsText, { alpha: 1 }, { duration: 800, easing: tween.easeOut }); }, 1500); // Animate fireworks LK.setTimeout(function () { for (var i = 0; i < fireworks.length; i++) { (function (firework, delay) { LK.setTimeout(function () { tween(firework, { alpha: 1, scaleX: 0.5, scaleY: 0.5, rotation: Math.PI * 4 }, { duration: 1000, easing: tween.easeOut }); }, delay); })(fireworks[i], i * 100); } }, 2000); // Continuous celebration effects function celebrationPulse() { tween(gradText, { scaleX: 1.1, scaleY: 1.1, tint: 0xFF69B4 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(gradText, { scaleX: 1, scaleY: 1, tint: 0xFFD700 }, { duration: 800, easing: tween.easeInOut, onFinish: celebrationPulse }); } }); } LK.setTimeout(celebrationPulse, 3000); // Remove animation after 8 seconds LK.setTimeout(function () { tween(gradContainer, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { game.removeChild(gradContainer); } }); }, 8000); } // Initialize game initializeDeck(); initializeEnemies(); createMenu(); // Play menu music with fade in LK.playMusic('Academia', { fade: { start: 0, end: 1, duration: 1000 } }); game.update = function () { // Game loop handled by turn-based system };
===================================================================
--- original.js
+++ change.js
@@ -323,8 +323,9 @@
// Fire card images
// Game state variables
var playerUsedCards = []; // Track cards used in current turn
var enemyUsedCards = []; // Track enemy cards used in current turn
+var playerUnavailableCards = []; // Track cards that can't be drawn yet (with turn counters)
var playerShield = null; // Player's shield (Muralla Rocosa)
var playerShieldBar = null; // Shield health bar
var playerShieldText = null; // Shield health text
// Fire card images
@@ -2528,15 +2529,23 @@
if (cardIndex !== -1) {
playerHand.splice(cardIndex, 1);
}
battleContainer.removeChild(card);
- // Add used card to tracking array
+ // Add used card to tracking array with turn counter
playerUsedCards.push({
element: card.element,
damage: card.damage,
name: card.name,
effect: card.effect
});
+ // Mark card as unavailable for the next turn
+ playerUnavailableCards.push({
+ element: card.element,
+ damage: card.damage,
+ name: card.name,
+ effect: card.effect,
+ turnsUnavailable: 1
+ });
// Check if enemy is defeated (must reach exactly 0 health)
if (currentEnemy.health === 0) {
LK.getSound('victory').play();
currentBattle++;
@@ -2583,13 +2592,9 @@
}
endPlayerTurn();
}
function endPlayerTurn() {
- // Player's turn is now complete - return used cards to deck immediately
- for (var i = 0; i < playerUsedCards.length; i++) {
- playerDeck.push(playerUsedCards[i]);
- }
- // Clear player used cards for this turn
+ // Clear player used cards for this turn (don't return to deck yet)
playerUsedCards = [];
gameState = 'enemyTurn';
turnText.setText('Enemy Turn - Turn ' + turnCounter);
LK.setTimeout(function () {
@@ -2694,8 +2699,22 @@
// Clear enemy used cards for this turn
enemyUsedCards = [];
// Complete turn cycle - both player and enemy have played, now start new complete turn
turnCounter++;
+ // Update player card availability system after complete turn cycle
+ for (var i = playerUnavailableCards.length - 1; i >= 0; i--) {
+ playerUnavailableCards[i].turnsUnavailable--;
+ // If card has been unavailable for one complete turn, return it to deck
+ if (playerUnavailableCards[i].turnsUnavailable <= 0) {
+ playerDeck.push({
+ element: playerUnavailableCards[i].element,
+ damage: playerUnavailableCards[i].damage,
+ name: playerUnavailableCards[i].name,
+ effect: playerUnavailableCards[i].effect
+ });
+ playerUnavailableCards.splice(i, 1);
+ }
+ }
// Restore mana after complete turn cycle (except first turn)
if (turnCounter > 1) {
// Restore 3-5 mana for player, but never exceed max
var manaToRestore = 3 + Math.floor(Math.random() * 3); // Random between 3-5
@@ -2739,10 +2758,18 @@
isDuplicate = true;
break;
}
}
- // Use card if it's not a duplicate
- if (!isDuplicate) {
+ // Check if this card is still unavailable (shouldn't happen after filtering above, but safety check)
+ var isUnavailable = false;
+ for (var k = 0; k < playerUnavailableCards.length; k++) {
+ if (playerUnavailableCards[k].name === cardData.name) {
+ isUnavailable = true;
+ break;
+ }
+ }
+ // Use card if it's not a duplicate and is available
+ if (!isDuplicate && !isUnavailable) {
playerDeck.splice(randomIndex, 1); // Remove from deck
var card = new Card(cardData.element, cardData.damage, cardData.name, cardData.effect);
card.x = 400 + i * 350;
card.y = 1800;
@@ -2821,8 +2848,10 @@
}
}
function startBattle() {
gameState = 'battle';
+ // Reset card availability system for new battle
+ playerUnavailableCards = [];
if (gameMode === 'adventure') {
// Start from first uncompleted battle
currentBattle = completedCourses * 3;
// Set health based on last completed course's final wizard
Un bote de agua oxigenada. In-Game asset. 2d. High contrast. No shadows
Pila de cartas mágicas bocabajo. In-Game asset. 2d. High contrast. No shadows
Barra de vida. In-Game asset. 2d. High contrast. No shadows
Botón de videojuegos sin nada escrito. In-Game asset. 2d. High contrast. No shadows
Hombre de nieve con pipa y manos de ramas y tres botones negros verticalmente algo realista. In-Game asset. 2d. High contrast. No shadows
Llama fuego, algo realista. In-Game asset. 2d. High contrast. No shadows
Luna roja sobre cielo nocturno, sin bordes y algo realista, que se aprecie el fondo. In-Game asset. 2d. High contrast. No shadows
Terremoto, algo realista. In-Game asset. 2d. High contrast. No shadows
Howgarts, algo realista. In-Game asset. 2d. High contrast. No shadows
Noche estrellada, algo realista. In-Game asset. 2d. High contrast. No shadows
Marea, algo realista, sin nombre. In-Game asset. 2d. High contrast. No shadows
Mechero encendido, algo realista. In-Game asset. 2d. High contrast. No shadows
Nevada, evento atmosférico, algo realista. In-Game asset. 2d. High contrast. No shadows
Arboleda, con fondo, cielo nocturno, algo realista. In-Game asset. 2d. High contrast. No shadows
Aullidos del bosque, algo realista. In-Game asset. 2d. High contrast. No shadows
Bola de nieve, algo realista. In-Game asset. 2d. High contrast. No shadows
Brasas con llama, algo realista. In-Game asset. 2d. High contrast. No shadows
Fénix envuelto en llamas mirando al frente, algo realista, pero no poner un pájaro rojo cualquiera. In-Game asset. 2d. High contrast. No shadows
Pedrada, algo realista. In-Game asset. 2d. High contrast. No shadows
Pirata con sombrero pirata y garfio, en barco pirata, navegando sobre el mar en una noche estrellada, algo realista, pero fuera de lo caricaturesco. In-Game asset. 2d. High contrast. No shadows
Rama, algo realista. In-Game asset. 2d. High contrast. No shadows
Sarcófago, algo realista. In-Game asset. 2d. High contrast. No shadows
Tormenta de arena, algo realista. In-Game asset. 2d. High contrast. No shadows
Vendaval, algo realista. In-Game asset. 2d. High contrast. No shadows
Ventisca, algo realista. In-Game asset. 2d. High contrast. No shadows
Vida extra, algo realista. In-Game asset. 2d. High contrast. No shadows
Mago astral. In-Game asset. 2d. High contrast. No shadows
Mago principiante con sombrero verde y marrón. In-Game asset. 2d. High contrast. No shadows
Libro en la mano libre y cambiar la esfera de su varita por una estrella
Cambiar la esfera por una estrella y usar el diseño de varita de, cuarto asset
Mago con sombrero naranja y marrón sin barba con varita con estrella, de cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Light wizard con cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Darkness wizard, con cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Quitar fondo blanco
Mago con sombrero naranja y marrón sin barba con varita con estrella, de cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Mago con sombrero naranja y marrón sin barba con varita con estrella, de cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Mago con sombrero rojo y marrón sin barba con varita con estrella, de cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Mago con sombrero morado y marrón sin barba con varita con estrella, de cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Mago con sombrero morado oscuro y marrón sin barba con varita con estrella, de cuerpo entero. In-Game asset. 2d. High contrast. No shadows
Momia realista en 2D. In-Game asset. 2d. High contrast. No shadows
Montículo de arena realista 2D. In-Game asset. 2d. High contrast. No shadows
Nubes moradas de las que cae un rayo amarillo más realista en 2D. In-Game asset. 2d. High contrast. No shadows
Muralla hecha de piedras y rocas realista en 2D. In-Game asset. 2d. High contrast. No shadows