User prompt
Ana menüye dönünce oynanan oyun resetlensin
User prompt
Kolay modda iki tarafın kulesinin canı da 50 orta zorlukta oyuncunun 50 rakibin 80 hard zorlukta rakibin 100 oyuncunun 50
User prompt
Tamam o zaman ayarlayalım
User prompt
Oyna tuşuna basınca kolay orta zor çıksın
User prompt
Durdur tuşunu kaldır sadece ana menü tuşu olsun
User prompt
Oyun içinde durdurma ana menüye git tuşları olsun
User prompt
Kartlara tıklayınca yakınlaştırsın ve pasifleri göstersin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tuşa basınca oyundaki kartları ve büyüleri göstersin
User prompt
Ana menüde oynamanın altında bi tuş olsun o tuşunda ismi deste olsun
User prompt
Ana menüde oynanın altında deste bölümü olsun ordan da kartları göstersin
User prompt
Waldo tarafından yapıldı yaz bide
User prompt
Ana menünün altına "Early Acess" yaz
User prompt
Oyuna kaliteli bir ana menü ekle
User prompt
Arkaplan müziği ekle
User prompt
Şifa büyüsü için farklı bir sound aç
User prompt
Rakipte büyü kullanılsın
User prompt
Şifa büyüsünün assetini ekle
User prompt
Büyülerin konumunu alt alta köy ve biraz daha aşağı köy
User prompt
Yeni büyü ekle seçtiğiniz karaktere 3 can versin ismi de şifa olsun
User prompt
Büyüleri oyuncu eliyle ittirip istediği rakibe vursun
User prompt
Lucifera pasif ekle her vuruşunda 2 sağlık yenilesin ama fazladan hasar falan vermesin ekstra hasar falan olmasın
User prompt
Kartlar ölünce desteye koyma aynı kartın yeni halini koy
User prompt
Bütün pasifleri kaldır
User prompt
Büyüler sadece seçilen kartlara hasar vermeli
User prompt
Yapay zekadaki büyülerin ui si gözükmesin
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Card = Container.expand(function (cardData) { var self = Container.call(this); // Card properties self.cardData = cardData || { name: "Basic Card", cost: 1, attack: 2, health: 2, description: "A basic creature card", passive: null // Passive ability type - all passives removed }; // Damage tracking to prevent duplicate triggers self.damageDealtThisTurn = 0; self.hasTriggeredLifeSteal = false; // Ensure cardData has valid numeric values if (typeof self.cardData.attack !== 'number' || isNaN(self.cardData.attack)) { self.cardData.attack = 2; } if (typeof self.cardData.health !== 'number' || isNaN(self.cardData.health)) { self.cardData.health = 2; } if (typeof self.cardData.cost !== 'number' || isNaN(self.cardData.cost)) { self.cardData.cost = 1; } self.maxHealth = self.cardData.health; self.currentHealth = self.cardData.health; self.isPlayable = false; self.isOnBattlefield = false; self.hasAttacked = false; // Create card graphics based on card type var cardAssetName = 'cardBack'; // default var symbolAssetName = null; // Determine assets based on card name switch (self.cardData.name) { case "Fire Imp": cardAssetName = 'fireImpBg'; symbolAssetName = 'fireImpSymbol'; break; case "Water Spirit": cardAssetName = 'waterSpiritBg'; symbolAssetName = 'waterSpiritSymbol'; break; case "Earth Golem": cardAssetName = 'earthGolemBg'; symbolAssetName = 'earthGolemSymbol'; break; case "Air Wisp": cardAssetName = 'airWispBg'; symbolAssetName = 'airWispSymbol'; break; case "Lightning Bolt": cardAssetName = 'lightningBoltBg'; symbolAssetName = 'lightningBoltSymbol'; break; case "Lucifer": cardAssetName = 'walterSpiritBg'; symbolAssetName = 'walterSpiritSymbol'; break; case "Shadow Drake": cardAssetName = 'shadowDrakeBg'; symbolAssetName = 'shadowDrakeSymbol'; break; case "Michael Demiurgos": cardAssetName = 'michaelDemiurgosBg'; symbolAssetName = 'michaelDemiurgosSymbol'; break; } var cardBg = self.attachAsset(cardAssetName, { anchorX: 0.5, anchorY: 0.5 }); // Add symbol if available if (symbolAssetName) { var cardSymbol = self.attachAsset(symbolAssetName, { anchorX: 0.5, anchorY: 0.5 }); cardSymbol.x = 0; cardSymbol.y = -20; // Position symbol in upper middle area } // Card text elements var nameText = new Text2(self.cardData.name, { size: 24, fill: 0x2C3E50 }); nameText.anchor.set(0.5, 0); nameText.x = 0; nameText.y = -100; self.addChild(nameText); var costText = new Text2(self.cardData.cost.toString(), { size: 32, fill: 0x9B59B6 }); costText.anchor.set(0.5, 0.5); costText.x = -70; costText.y = -100; self.addChild(costText); var attackText = new Text2(self.cardData.attack.toString(), { size: 28, fill: 0xE74C3C }); attackText.anchor.set(0.5, 0.5); attackText.x = -50; attackText.y = 90; self.addChild(attackText); // Store reference to attack text for potential updates self.attackText = attackText; var healthText = new Text2(self.currentHealth.toString(), { size: 28, fill: 0x27AE60 }); healthText.anchor.set(0.5, 0.5); healthText.x = 50; healthText.y = 90; self.addChild(healthText); // Store reference to health text self.healthText = healthText; self.updateHealthDisplay = function () { // Ensure we display a valid number, not NaN var displayHealth = isNaN(self.currentHealth) ? 0 : Math.max(0, self.currentHealth); // Ensure currentHealth is always a valid number if (isNaN(self.currentHealth)) { self.currentHealth = 0; } if (isNaN(self.maxHealth)) { self.maxHealth = self.cardData.health || 1; } // Update health text display if (self.healthText) { self.healthText.setText(displayHealth.toString()); } else if (healthText) { healthText.setText(displayHealth.toString()); } // Update attack text if it exists and attack value changed if (self.attackText && self.cardData.attack !== undefined) { self.attackText.setText(self.cardData.attack.toString()); } // Debug log for Lightning Bolt if (self.cardData.name === "Lightning Bolt") { console.log("Lightning Bolt health - current:", self.currentHealth, "max:", self.maxHealth, "display:", displayHealth); } if (self.currentHealth <= 0) { cardBg.alpha = 0.5; } }; self.takeDamage = function (damage, attacker) { // Ensure damage is a valid number but don't reduce it to 0 unnecessarily if (typeof damage !== 'number' || isNaN(damage)) { damage = 0; } if (damage < 0) { damage = 0; } // No passive damage reduction - all passives removed var finalDamage = Math.max(0, damage); self.currentHealth -= finalDamage; // Ensure currentHealth is always a valid number if (isNaN(self.currentHealth)) { self.currentHealth = 0; } self.updateHealthDisplay(); // If card dies, remove it immediately if (self.currentHealth <= 0) { // Check if card is on battlefield before trying to find player var ownerPlayer = null; if (self.isOnBattlefield) { // Safely check which player owns this card for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (humanPlayer.battlefield[i] === self) { ownerPlayer = humanPlayer; break; } } if (!ownerPlayer) { for (var i = 0; i < aiPlayer.battlefield.length; i++) { if (aiPlayer.battlefield[i] === self) { ownerPlayer = aiPlayer; break; } } } } // Trigger death passive before removing if (ownerPlayer) { self.triggerPassive("death", { player: ownerPlayer }); } // Remove from battlefield arrays and add new card to deck var humanIndex = humanPlayer.battlefield.indexOf(self); if (humanIndex >= 0) { humanPlayer.battlefield.splice(humanIndex, 1); // Create a new card with the same data instead of resetting this one var newCard = new Card(self.cardData); newCard.validateStats(); // Ensure stats are correct // Add new card to human player's deck humanPlayer.deck.push(newCard); } var aiIndex = aiPlayer.battlefield.indexOf(self); if (aiIndex >= 0) { aiPlayer.battlefield.splice(aiIndex, 1); // Create a new card with the same data instead of resetting this one var newCard = new Card(self.cardData); newCard.validateStats(); // Ensure stats are correct // Add new card to AI player's deck aiPlayer.deck.push(newCard); } // Clear lane assignment self.laneIndex = undefined; self.isOnBattlefield = false; // Death animation and removal from game animateCardDeath(self); LK.setTimeout(function () { if (game.children.includes(self)) { game.removeChild(self); } // Update battlefield layout after card removal arrangeBattlefield(); }, 600); // Match the death animation duration } // Lucifer passive: heal 2 health when dealing damage to other cards if (attacker && attacker.cardData.name === "Lucifer" && self.isOnBattlefield) { // Heal Lucifer by 2 health (not exceeding max health) var healAmount = 2; attacker.currentHealth = Math.min(attacker.maxHealth, attacker.currentHealth + healAmount); attacker.updateHealthDisplay(); // Create healing visual effect var healText = new Text2("+" + healAmount.toString(), { size: 40, fill: 0x00ff00 }); healText.anchor.set(0.5, 0.5); healText.x = attacker.x + (Math.random() - 0.5) * 60; healText.y = attacker.y - 50; healText.alpha = 1.0; game.addChild(healText); // Animate healing number floating up and fading tween(healText, { y: healText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(healText); } }); // Brief green flash on Lucifer LK.effects.flashObject(attacker, 0x00ff00, 300); } // Enhanced damage animation // Screen shake for significant damage if (damage >= 3) { LK.effects.flashScreen(0xff4444, 200); } // Damage number popup animation var damageText = new Text2("-" + damage.toString(), { size: 40, fill: 0xff0000 }); damageText.anchor.set(0.5, 0.5); damageText.x = self.x + (Math.random() - 0.5) * 60; damageText.y = self.y - 50; damageText.alpha = 1.0; game.addChild(damageText); // Animate damage number floating up and fading tween(damageText, { y: damageText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(damageText); } }); // Card damage animation - recoil and flash tween(self, { x: self.x + (Math.random() - 0.5) * 30, y: self.y + (Math.random() - 0.5) * 20, scaleX: 0.9, scaleY: 0.9, tint: 0xff4444 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { x: self.x, y: self.y, scaleX: 1.0, scaleY: 1.0, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); } }); // Flash red when taking damage LK.effects.flashObject(self, 0xff0000, 500); }; self.canAttack = function () { return self.isOnBattlefield && !self.hasAttacked && self.currentHealth > 0; }; self.attack = function (target) { if (self.canAttack() && target) { // Check if both cards are in the same lane if (self.laneIndex !== undefined && target.laneIndex !== undefined && self.laneIndex !== target.laneIndex) { return; // Cannot attack cards in different lanes } // Store original position var originalX = self.x; var originalY = self.y; // Calculate target position (move towards target) var targetX = target.x; var targetY = target.y; // Animate attack: move toward target, then back tween(self, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Collision animation - both cards shake and flash on impact var collisionDuration = 150; // Shake the attacking card tween(self, { x: targetX + 20 }, { duration: collisionDuration / 3, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { x: targetX - 20 }, { duration: collisionDuration / 3, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { x: targetX }, { duration: collisionDuration / 3, easing: tween.easeInOut }); } }); } }); // Shake the target card tween(target, { x: target.x - 15 }, { duration: collisionDuration / 3, easing: tween.easeInOut, onFinish: function onFinish() { tween(target, { x: target.x + 15 }, { duration: collisionDuration / 3, easing: tween.easeInOut, onFinish: function onFinish() { tween(target, { x: target.x }, { duration: collisionDuration / 3, easing: tween.easeInOut }); } }); } }); // Flash both cards white for collision effect tween(self, { tint: 0xFFFFFF }, { duration: collisionDuration, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { tint: 0xFFFFFF }, { duration: collisionDuration, easing: tween.easeInOut }); } }); tween(target, { tint: 0xFFFFFF }, { duration: collisionDuration, easing: tween.easeInOut, onFinish: function onFinish() { tween(target, { tint: 0xFFFFFF }, { duration: collisionDuration, easing: tween.easeInOut }); } }); // Use exactly the attack value shown on the card - no modifications var totalDamage = self.cardData.attack; // Ensure we're using a clean integer value if (typeof totalDamage !== 'number' || isNaN(totalDamage)) { totalDamage = self.cardData.attack; } // Debug logging for attacks console.log("Card attacking:", self.cardData.name, "(" + totalDamage + " damage) ->", target.cardData.name, "(" + target.currentHealth + " health)"); // Deal exact damage as written on card target.takeDamage(totalDamage, self); // After collision, animate return to original position LK.setTimeout(function () { tween(self, { x: originalX, y: originalY }, { duration: 300, easing: tween.easeIn }); }, collisionDuration); } }); self.hasAttacked = true; cardBg.alpha = 0.7; LK.getSound('attack').play(); } }; self.resetForNewTurn = function () { self.hasAttacked = false; self.damageDealtThisTurn = 0; self.hasTriggeredLifeSteal = false; if (self.currentHealth > 0) { cardBg.alpha = 1.0; } }; // Passive ability system - all passives removed self.triggerPassive = function (trigger, context) { return 0; }; self.hasPassive = function () { return false; // All passives removed }; // Method to validate and fix card stats self.validateStats = function () { // Ensure all stats are valid numbers if (typeof self.cardData.attack !== 'number' || isNaN(self.cardData.attack)) { self.cardData.attack = 1; } if (typeof self.cardData.health !== 'number' || isNaN(self.cardData.health)) { self.cardData.health = 1; } if (typeof self.cardData.cost !== 'number' || isNaN(self.cardData.cost)) { self.cardData.cost = 1; } if (typeof self.currentHealth !== 'number' || isNaN(self.currentHealth)) { self.currentHealth = self.cardData.health; } if (typeof self.maxHealth !== 'number' || isNaN(self.maxHealth)) { self.maxHealth = self.cardData.health; } // Ensure current health doesn't exceed max health if (self.currentHealth > self.maxHealth) { self.currentHealth = self.maxHealth; } // Update display after validation self.updateHealthDisplay(); }; return self; }); var Player = Container.expand(function (isHuman) { var self = Container.call(this); self.isHuman = isHuman || false; self.health = 50; self.maxMana = 10; self.currentMana = 3; self.hand = []; self.battlefield = []; self.deck = []; self.spells = []; // Initialize with Fire Ball spell var fireBallSpell = new Spell({ name: "Fire Ball", cost: 2, damage: 4, target: "enemy", description: "Deals 4 damage to target" }); self.spells.push(fireBallSpell); // Add heal spell var healSpell = new Spell({ name: "Şifa", cost: 2, damage: -3, // Negative damage for healing target: "ally", description: "Heals target for 3 health" }); self.spells.push(healSpell); // AI player also gets spells if not human if (!isHuman) { var aiFireBallSpell = new Spell({ name: "Fire Ball", cost: 2, damage: 4, target: "enemy", description: "Deals 4 damage to target" }); self.spells.push(aiFireBallSpell); } // Initialize deck with basic cards var cardTypes = [{ name: "Fire Imp", cost: 1, attack: 3, health: 12, description: "A small fire creature" }, { name: "Water Spirit", cost: 2, attack: 3, health: 13, description: "A defensive water creature" }, { name: "Earth Golem", cost: 6, attack: 3, health: 22, description: "A powerful earth creature" }, { name: "Air Wisp", cost: 1, attack: 2, health: 13, description: "A quick air creature" }, { name: "Lightning Bolt", cost: 3, attack: 3, health: 14, description: "A shocking creature" }, { name: "Lucifer", cost: 4, attack: 3, health: 15, description: "A mystical water spirit with high endurance" }, { name: "Shadow Drake", cost: 3, attack: 4, health: 14, description: "A powerful shadow dragon" }, { name: "Michael Demiurgos", cost: 4, attack: 5, health: 14, description: "An archangel with divine power" }]; // Add exactly one of each card type to the deck for (var i = 0; i < cardTypes.length; i++) { var newCard = new Card(cardTypes[i]); newCard.validateStats(); // Ensure stats are correct self.deck.push(newCard); } // Shuffle the deck to randomize card order for (var i = self.deck.length - 1; i > 0; i--) { var randomIndex = Math.floor(Math.random() * (i + 1)); var temp = self.deck[i]; self.deck[i] = self.deck[randomIndex]; self.deck[randomIndex] = temp; } self.drawCard = function () { if (self.deck.length > 0 && self.hand.length < 7) { var card = self.deck.pop(); self.hand.push(card); LK.getSound('cardDraw').play(); return card; } return null; }; self.canPlayCard = function (card) { return card && card.cardData.cost <= self.currentMana; }; self.playCard = function (card) { var handIndex = self.hand.indexOf(card); if (handIndex >= 0 && self.canPlayCard(card) && self.battlefield.length < 3) { self.hand.splice(handIndex, 1); self.battlefield.push(card); self.currentMana -= card.cardData.cost; card.isOnBattlefield = true; LK.getSound('cardPlay').play(); return true; } return false; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health < 0) self.health = 0; // Tower damage animation animateTowerDamage(!self.isHuman); // Damage number popup for tower var damageText = new Text2("-" + damage.toString(), { size: 60, fill: 0xff0000 }); damageText.anchor.set(0.5, 0.5); damageText.x = 1024 + (Math.random() - 0.5) * 100; damageText.y = self.isHuman ? 1700 : 400; damageText.alpha = 1.0; game.addChild(damageText); // Animate damage number tween(damageText, { y: damageText.y - 120, alpha: 0, scaleX: 2.0, scaleY: 2.0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(damageText); } }); }; self.canCastSpell = function (spell) { return spell && spell.spellData.cost <= self.currentMana; }; self.castSpell = function (spell, target) { if (self.canCastSpell(spell)) { self.currentMana -= spell.spellData.cost; return spell.castSpell(target); } return false; }; self.startTurn = function () { // Base mana gain: 1 per turn var manaGain = 1; // Check if this is every 3rd turn (turnCounter is global) if (turnCounter % 3 === 0) { manaGain += 2; // Add 2 extra mana every 3 turns } self.currentMana = Math.min(self.maxMana, self.currentMana + manaGain); if (self.maxMana < 10) self.maxMana++; // Reset battlefield cards and trigger turn start passives for (var i = 0; i < self.battlefield.length; i++) { self.battlefield[i].resetForNewTurn(); self.battlefield[i].triggerPassive("turn_start", { player: self }); } // Draw a card self.drawCard(); }; return self; }); var Spell = Container.expand(function (spellData) { var self = Container.call(this); // Spell properties self.spellData = spellData || { name: "Fire Ball", cost: 2, damage: 4, target: "enemy", // "enemy", "ally", "self" description: "Deals 4 damage to target" }; self.isUsable = false; // Create spell graphics var spellBg = self.attachAsset('spellSlot', { anchorX: 0.5, anchorY: 0.5 }); var spellIcon = self.attachAsset('fireballSpell', { anchorX: 0.5, anchorY: 0.5 }); // Spell text elements var nameText = new Text2(self.spellData.name, { size: 18, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0); nameText.x = 0; nameText.y = -50; self.addChild(nameText); var costText = new Text2(self.spellData.cost.toString(), { size: 24, fill: 0x9B59B6 }); costText.anchor.set(0.5, 0.5); costText.x = -40; costText.y = -40; self.addChild(costText); var damageText = new Text2(self.spellData.damage.toString(), { size: 20, fill: 0xE74C3C }); damageText.anchor.set(0.5, 0.5); damageText.x = 0; damageText.y = 35; self.addChild(damageText); self.castSpell = function (target) { if (!self.isUsable) return false; LK.getSound('spellCast').play(); // Animate spell casting var originalScale = self.scaleX; tween(self, { scaleX: 1.3, scaleY: 1.3, tint: 0xffff00 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: originalScale, scaleY: originalScale, tint: 0xFFFFFF }, { duration: 200, easing: tween.easeIn }); } }); // Create spell projectile animation var projectile = game.addChild(LK.getAsset('fireballSpell', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y })); var targetX = target ? target.x : 1024 + (Math.random() - 0.5) * 200; var targetY = target ? target.y : aiPlayer.battlefield.length > 0 ? 650 : 300; // Animate projectile to target tween(projectile, { x: targetX, y: targetY, scaleX: 1.5, scaleY: 1.5, rotation: Math.PI * 2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Impact effect LK.effects.flashScreen(0xff4444, 300); // Handle both damage and healing spells if (target && target.takeDamage && target.isOnBattlefield) { if (self.spellData.damage < 0) { // Healing spell var healAmount = Math.abs(self.spellData.damage); target.currentHealth = Math.min(target.maxHealth, target.currentHealth + healAmount); target.updateHealthDisplay(); // Create healing visual effect var healText = new Text2("+" + healAmount.toString(), { size: 40, fill: 0x00ff00 }); healText.anchor.set(0.5, 0.5); healText.x = target.x + (Math.random() - 0.5) * 60; healText.y = target.y - 50; healText.alpha = 1.0; game.addChild(healText); // Animate healing number floating up and fading tween(healText, { y: healText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(healText); } }); // Brief green flash on target LK.effects.flashObject(target, 0x00ff00, 300); } else { // Damage spell target.takeDamage(self.spellData.damage); } } // Remove projectile game.removeChild(projectile); } }); return true; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Game state variables // Fire Imp card assets // Water Spirit card assets // Earth Golem card assets // Air Wisp card assets // Lightning Bolt card assets // Walter Spirit card assets // Generic card back var currentPlayer = 0; // 0 = human, 1 = AI var gamePhase = "playing"; // "playing", "gameOver" var selectedCard = null; var draggedCard = null; var turnCounter = 0; // Track total turns taken var combatPhase = false; // Track if we're in combat phase // Create players var humanPlayer = new Player(true); var aiPlayer = new Player(false); var players = [humanPlayer, aiPlayer]; // Create game areas var opponentAreaBg = game.addChild(LK.getAsset('opponentArea', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.3 })); var battlefieldBg = game.addChild(LK.getAsset('battlefield', { anchorX: 0, anchorY: 0, x: 0, y: 400, alpha: 0.8 })); var playerAreaBg = game.addChild(LK.getAsset('playerArea', { anchorX: 0, anchorY: 0, x: 0, y: 1800, alpha: 0.3 })); // Create visible lane graphics var lanePositions = [600, 1024, 1448]; // Left, Center, Right lanes - centered var lanes = []; // Create lanes with borders for visual clarity for (var i = 0; i < 3; i++) { // Lane border (darker background) var laneBorder = game.addChild(LK.getAsset('laneBorder', { anchorX: 0.5, anchorY: 0.5, x: lanePositions[i], y: 985, alpha: 0.8 })); // Lane background (lighter) var lane = game.addChild(LK.getAsset('lane', { anchorX: 0.5, anchorY: 0.5, x: lanePositions[i], y: 985, alpha: 0.7 })); lanes.push({ border: laneBorder, background: lane }); // Add lane number text var laneText = new Text2("Lane " + (i + 1), { size: 24, fill: 0xECF0F1 }); laneText.anchor.set(0.5, 0.5); laneText.x = lanePositions[i]; laneText.y = 1255; laneText.alpha = 0.6; game.addChild(laneText); } // UI Elements var playerHealthText = new Text2("Health: 50", { size: 48, fill: 0xECF0F1 }); playerHealthText.anchor.set(0, 0.5); playerHealthText.x = 50; playerHealthText.y = 1950; game.addChild(playerHealthText); var opponentHealthText = new Text2("Enemy: 50", { size: 48, fill: 0xECF0F1 }); opponentHealthText.anchor.set(0, 0.5); opponentHealthText.x = 50; opponentHealthText.y = 150; game.addChild(opponentHealthText); var manaText = new Text2("Mana: 3/3", { size: 36, fill: 0x9B59B6 }); manaText.anchor.set(0, 0.5); manaText.x = 50; manaText.y = 2000; game.addChild(manaText); var aiManaText = new Text2("Enemy Mana: 3/3", { size: 36, fill: 0x9B59B6 }); aiManaText.anchor.set(0, 0.5); aiManaText.x = 50; aiManaText.y = 100; game.addChild(aiManaText); var turnText = new Text2("Your Turn", { size: 42, fill: 0xF39C12 }); turnText.anchor.set(0.5, 0.5); turnText.x = 1024; turnText.y = 100; game.addChild(turnText); // End turn button var endTurnBtn = game.addChild(LK.getAsset('endTurnButton', { anchorX: 0.5, anchorY: 0.5, x: 1800, y: 1950 })); var endTurnText = new Text2("End Turn", { size: 28, fill: 0x2C3E50 }); endTurnText.anchor.set(0.5, 0.5); endTurnText.x = 1800; endTurnText.y = 1950; game.addChild(endTurnText); // Initialize starting hands for (var i = 0; i < 4; i++) { humanPlayer.drawCard(); aiPlayer.drawCard(); } // Add spells to game display function arrangeSpells() { // Arrange human player spells var spells = humanPlayer.spells; for (var i = 0; i < spells.length; i++) { var spell = spells[i]; if (!game.children.includes(spell)) { game.addChild(spell); } spell.x = 150; spell.y = 2150 + i * 140; spell.isUsable = humanPlayer.canCastSpell(spell) && currentPlayer === 0 && !combatPhase; // Visual feedback for usable spells if (spell.isUsable) { spell.alpha = 1.0; } else { spell.alpha = 0.6; } } // AI spells are hidden from UI - no display for AI spells } function updateUI() { playerHealthText.setText("Health: " + humanPlayer.health); opponentHealthText.setText("Enemy: " + aiPlayer.health); manaText.setText("Mana: " + humanPlayer.currentMana + "/" + humanPlayer.maxMana); aiManaText.setText("Enemy Mana: " + aiPlayer.currentMana + "/" + aiPlayer.maxMana); if (combatPhase) { turnText.setText("Combat Phase"); turnText.fill = "#e67e22"; } else if (currentPlayer === 0) { turnText.setText("Your Turn"); turnText.fill = "#f39c12"; } else { turnText.setText("Enemy Turn"); turnText.fill = "#e74c3c"; } } function arrangeHand() { var handCards = humanPlayer.hand; var startX = 1024 - handCards.length * 100; for (var i = 0; i < handCards.length; i++) { var card = handCards[i]; if (!game.children.includes(card)) { game.addChild(card); } card.x = startX + i * 200; card.y = 2300; card.isPlayable = humanPlayer.canPlayCard(card); // Visual feedback for playable cards if (card.isPlayable && currentPlayer === 0) { card.alpha = 1.0; } else { card.alpha = 0.6; } } arrangeSpells(); } function arrangeBattlefield() { // Define 3 lane positions var lanePositions = [600, 1024, 1448]; // Left, Center, Right lanes - centered // Player battlefield - maintain lane assignments var playerCards = humanPlayer.battlefield; for (var i = 0; i < playerCards.length; i++) { var card = playerCards[i]; if (!game.children.includes(card)) { game.addChild(card); } // Use the card's assigned lane position instead of array index if (card.laneIndex !== undefined) { card.x = lanePositions[card.laneIndex]; card.y = 1120; } } // AI battlefield - maintain lane assignments var aiCards = aiPlayer.battlefield; for (var i = 0; i < aiCards.length; i++) { var card = aiCards[i]; if (!game.children.includes(card)) { game.addChild(card); } // Use the card's assigned lane position instead of array index if (card.laneIndex !== undefined) { card.x = lanePositions[card.laneIndex]; card.y = 650; } } } function resolveCombat() { // Process lanes sequentially - lane 1, then lane 2, then lane 3 processLaneCombat(0, function () { // Lane 1 complete, process lane 2 processLaneCombat(1, function () { // Lane 2 complete, process lane 3 processLaneCombat(2, function () { // All lanes complete, update battlefield LK.setTimeout(function () { arrangeBattlefield(); updateUI(); }, 500); }); }); }); } function processLaneCombat(laneIndex, onComplete) { var humanCard = null; var aiCard = null; // Find cards in this lane for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (humanPlayer.battlefield[i].laneIndex === laneIndex && humanPlayer.battlefield[i].currentHealth > 0) { humanCard = humanPlayer.battlefield[i]; break; } } for (var i = 0; i < aiPlayer.battlefield.length; i++) { if (aiPlayer.battlefield[i].laneIndex === laneIndex && aiPlayer.battlefield[i].currentHealth > 0) { aiCard = aiPlayer.battlefield[i]; break; } } // Determine combat outcome for this lane if (humanCard && humanCard.currentHealth > 0 && aiCard && aiCard.currentHealth > 0) { // Cards fight each other - use exact attack values as written on cards var humanDamage = humanCard.cardData.attack; var aiDamage = aiCard.cardData.attack; // Ensure we're using the exact attack values animateCardVsCard(humanCard, aiCard, humanDamage, aiDamage, 0); // Wait for combat animation to complete before continuing LK.setTimeout(onComplete, 1200); } else if (humanCard && humanCard.currentHealth > 0 && !aiCard) { // Human card attacks AI tower - use card's actual attack value animateCardToTower(humanCard, "ai", 0, 0); // Wait for tower attack animation to complete before continuing LK.setTimeout(onComplete, 1000); } else if (aiCard && aiCard.currentHealth > 0 && !humanCard) { // AI card attacks human tower - use card's actual attack value animateCardToTower(aiCard, "human", 0, 0); // Wait for tower attack animation to complete before continuing LK.setTimeout(onComplete, 1000); } else { // No combat in this lane, proceed immediately LK.setTimeout(onComplete, 100); } } function animateCardVsCard(card1, card2, damage1, damage2, delay) { LK.setTimeout(function () { // Store original positions var originalX1 = card1.x; var originalY1 = card1.y; var originalX2 = card2.x; var originalY2 = card2.y; // Calculate midpoint for collision var midX = (card1.x + card2.x) / 2; var midY = (card1.y + card2.y) / 2; // Phase 1: Both cards move toward each other tween(card1, { x: midX, y: midY - 20, scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeOut }); tween(card2, { x: midX, y: midY + 20, scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Phase 2: Collision effect - shake and flash LK.getSound('attack').play(); // Shake both cards tween(card1, { x: midX + 15, rotation: 0.1 }, { duration: 60, easing: tween.easeInOut, onFinish: function onFinish() { tween(card1, { x: midX - 15, rotation: -0.1 }, { duration: 60, easing: tween.easeInOut, onFinish: function onFinish() { tween(card1, { x: midX, rotation: 0 }, { duration: 60, easing: tween.easeInOut }); } }); } }); tween(card2, { x: midX - 15, rotation: -0.1 }, { duration: 60, easing: tween.easeInOut, onFinish: function onFinish() { tween(card2, { x: midX + 15, rotation: 0.1 }, { duration: 60, easing: tween.easeInOut, onFinish: function onFinish() { tween(card2, { x: midX, rotation: 0 }, { duration: 60, easing: tween.easeInOut }); } }); } }); // Flash white for collision tween(card1, { tint: 0xFFFFFF }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(card1, { tint: 0xFFFFFF }, { duration: 150, easing: tween.easeInOut }); } }); tween(card2, { tint: 0xFFFFFF }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(card2, { tint: 0xFFFFFF }, { duration: 150, easing: tween.easeInOut }); } }); // Apply damage after collision - use exact damage values passed to function LK.setTimeout(function () { // card1 takes damage2 (from card2), card2 takes damage1 (from card1) card1.takeDamage(damage2, card2); card2.takeDamage(damage1, card1); }, 180); // Phase 3: Return to original positions LK.setTimeout(function () { tween(card1, { x: originalX1, y: originalY1, scaleX: 1.0, scaleY: 1.0 }, { duration: 400, easing: tween.easeIn }); tween(card2, { x: originalX2, y: originalY2, scaleX: 1.0, scaleY: 1.0 }, { duration: 400, easing: tween.easeIn }); }, 300); } }); }, delay); } function animateCardToTower(card, target, damage, delay) { LK.setTimeout(function () { // Store original position var originalX = card.x; var originalY = card.y; // Determine tower position var towerX = 1024; // Center of screen var towerY = target === "ai" ? 100 : 1800; // AI or human area var targetX = towerX + (Math.random() - 0.5) * 200; // Add some randomness var targetY = towerY + (Math.random() - 0.5) * 100; // Phase 1: Card charges toward tower tween(card, { x: targetX, y: targetY, scaleX: 1.2, scaleY: 1.2, rotation: Math.PI * 0.1 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Phase 2: Impact effect LK.getSound('attack').play(); // Use card's actual attack value instead of passed damage parameter var actualDamage = card.cardData.attack; // Flash the tower area if (target === "ai") { LK.effects.flashObject(opponentAreaBg, 0xff0000, 400); LK.effects.flashScreen(0xff0000, 200); aiPlayer.takeDamage(actualDamage); } else { LK.effects.flashObject(playerAreaBg, 0xff0000, 400); LK.effects.flashScreen(0xff0000, 200); humanPlayer.takeDamage(actualDamage); } // Shake the card on impact tween(card, { x: targetX + 20, rotation: Math.PI * 0.15 }, { duration: 80, easing: tween.easeInOut, onFinish: function onFinish() { tween(card, { x: targetX - 20, rotation: Math.PI * 0.05 }, { duration: 80, easing: tween.easeInOut, onFinish: function onFinish() { tween(card, { x: targetX, rotation: Math.PI * 0.1 }, { duration: 80, easing: tween.easeInOut }); } }); } }); // Phase 3: Return to original position LK.setTimeout(function () { tween(card, { x: originalX, y: originalY, scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 500, easing: tween.easeIn }); }, 300); } }); }, delay); } function animateCardDeath(card) { // Death animation - fade out while spinning and shrinking tween(card, { alpha: 0, scaleX: 0.2, scaleY: 0.2, rotation: Math.PI * 2, y: card.y - 100 }, { duration: 600, easing: tween.easeIn }); } function animateTowerDamage(isAI) { // Tower damage animation - screen shake and flash var targetArea = isAI ? opponentAreaBg : playerAreaBg; var healthText = isAI ? opponentHealthText : playerHealthText; // Flash the area red LK.effects.flashObject(targetArea, 0xff0000, 500); // Screen shake effect LK.effects.flashScreen(0xff0000, 300); // Animate health text tween(healthText, { scaleX: 1.3, scaleY: 1.3, tint: 0xff0000 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(healthText, { scaleX: 1.0, scaleY: 1.0, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeIn }); } }); } function checkGameOver() { if (humanPlayer.health <= 0) { gamePhase = "gameOver"; LK.showGameOver(); return true; } else if (aiPlayer.health <= 0) { gamePhase = "gameOver"; LK.showYouWin(); return true; } return false; } function endTurn() { // Trigger end turn passives for current player var currentPlayerObj = players[currentPlayer]; for (var i = 0; i < currentPlayerObj.battlefield.length; i++) { currentPlayerObj.battlefield[i].triggerPassive("end_turn", { player: currentPlayerObj }); } // Switch to next player turnCounter++; currentPlayer = 1 - currentPlayer; // Check if both players have completed their turns (every 2 turns) if (turnCounter % 2 === 0) { // Combat happens only after both players finish their turns combatPhase = true; turnText.setText("Combat Phase"); turnText.fill = "#e67e22"; // Resolve combat after both players complete their turns LK.setTimeout(function () { resolveCombat(); combatPhase = false; // Continue with next player's turn after combat players[currentPlayer].startTurn(); if (currentPlayer === 1) { // AI turn LK.setTimeout(function () { performAITurn(); }, 1000); } if (!checkGameOver()) { updateUI(); arrangeHand(); arrangeBattlefield(); } }, 1000); } else { // Just switch player without combat players[currentPlayer].startTurn(); if (currentPlayer === 1) { // AI turn LK.setTimeout(function () { performAITurn(); }, 1000); } if (!checkGameOver()) { updateUI(); arrangeHand(); arrangeBattlefield(); } } } function performAITurn() { // AI can cast spells first if they have enough mana var usableSpells = aiPlayer.spells.filter(function (spell) { return aiPlayer.canCastSpell(spell); }); if (usableSpells.length > 0 && humanPlayer.battlefield.length > 0) { // Cast spell at random enemy card on battlefield only var randomSpell = usableSpells[Math.floor(Math.random() * usableSpells.length)]; var target = humanPlayer.battlefield[Math.floor(Math.random() * humanPlayer.battlefield.length)]; // Only cast if target is a valid battlefield card if (target && target.isOnBattlefield && aiPlayer.castSpell(randomSpell, target)) { updateUI(); arrangeHand(); arrangeBattlefield(); } } // Simple AI: play random playable card if battlefield has space var playableCards = aiPlayer.hand.filter(function (card) { return aiPlayer.canPlayCard(card); }); if (playableCards.length > 0 && aiPlayer.battlefield.length < 3) { var randomCard = playableCards[Math.floor(Math.random() * playableCards.length)]; // Find available lane for AI var availableLanes = [0, 1, 2]; for (var i = 0; i < aiPlayer.battlefield.length; i++) { var occupiedLane = aiPlayer.battlefield[i].laneIndex; if (occupiedLane !== undefined) { var laneIdx = availableLanes.indexOf(occupiedLane); if (laneIdx >= 0) availableLanes.splice(laneIdx, 1); } } if (availableLanes.length > 0 && aiPlayer.playCard(randomCard)) { // Filter out lanes where Lucifer would face another Lucifer var validLanes = availableLanes.slice(); // Copy array if (randomCard.cardData.name === "Lucifer") { validLanes = availableLanes.filter(function (lane) { // Check if human has Lucifer in this lane for (var k = 0; k < humanPlayer.battlefield.length; k++) { if (humanPlayer.battlefield[k].laneIndex === lane && humanPlayer.battlefield[k].cardData.name === "Lucifer") { return false; // This lane is blocked for Lucifer } } return true; // Lane is safe for Lucifer }); } // Use valid lanes, fallback to available lanes if no valid lanes for Lucifer var lanesToUse = validLanes.length > 0 ? validLanes : availableLanes; var selectedLane = lanesToUse[Math.floor(Math.random() * lanesToUse.length)]; randomCard.laneIndex = selectedLane; randomCard.targetLane = selectedLane; // Immediately update display after AI plays card updateUI(); arrangeHand(); arrangeBattlefield(); } } // Combat is now handled automatically at end of turn // AI just plays cards, combat resolution happens automatically // End AI turn LK.setTimeout(function () { if (!checkGameOver()) { endTurn(); } }, 1500); } // Card zoom preview variables var zoomPreviewCard = null; var zoomPreviewBg = null; var zoomPreviewTimeout = null; var isShowingZoom = false; // Double-tap tracking variables var lastTappedCard = null; var lastTapTime = 0; var doubleTapThreshold = 500; // milliseconds // Card info display variables var cardInfoDisplay = null; var cardInfoBg = null; var isShowingCardInfo = false; function createZoomPreview(card) { if (isShowingZoom) return; // Create dark background overlay zoomPreviewBg = game.addChild(LK.getAsset('battlefield', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8, tint: 0x000000 })); zoomPreviewBg.width = 2048; zoomPreviewBg.height = 2732; // Create zoomed card preview zoomPreviewCard = new Card(card.cardData); zoomPreviewCard.x = 1024; zoomPreviewCard.y = 1000; zoomPreviewCard.scaleX = 2.5; zoomPreviewCard.scaleY = 2.5; zoomPreviewCard.alpha = 0; game.addChild(zoomPreviewCard); // Add card name text var nameText = new Text2(card.cardData.name, { size: 60, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.x = 1024; nameText.y = 700; nameText.alpha = 0; game.addChild(nameText); zoomPreviewCard.nameDisplay = nameText; // Add passive description if card has passive if (card.hasPassive()) { var passiveText = new Text2("Passive: " + getPassiveDescription(card.cardData.passive), { size: 36, fill: 0xF39C12 }); passiveText.anchor.set(0.5, 0.5); passiveText.x = 1024; passiveText.y = 1400; passiveText.alpha = 0; game.addChild(passiveText); zoomPreviewCard.passiveDisplay = passiveText; } // Add description text var descText = new Text2(card.cardData.description, { size: 32, fill: 0xECF0F1 }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = card.hasPassive() ? 1500 : 1400; descText.alpha = 0; game.addChild(descText); zoomPreviewCard.descDisplay = descText; // Animate zoom in tween(zoomPreviewBg, { alpha: 0.8 }, { duration: 300, easing: tween.easeOut }); tween(zoomPreviewCard, { alpha: 1.0, scaleX: 2.5, scaleY: 2.5 }, { duration: 400, easing: tween.easeOut }); tween(nameText, { alpha: 1.0 }, { duration: 400, easing: tween.easeOut }); tween(descText, { alpha: 1.0 }, { duration: 400, easing: tween.easeOut }); if (zoomPreviewCard.passiveDisplay) { tween(zoomPreviewCard.passiveDisplay, { alpha: 1.0 }, { duration: 400, easing: tween.easeOut }); } isShowingZoom = true; } function destroyZoomPreview() { if (!isShowingZoom) return; if (zoomPreviewCard) { if (zoomPreviewCard.nameDisplay) { game.removeChild(zoomPreviewCard.nameDisplay); } if (zoomPreviewCard.passiveDisplay) { game.removeChild(zoomPreviewCard.passiveDisplay); } if (zoomPreviewCard.descDisplay) { game.removeChild(zoomPreviewCard.descDisplay); } game.removeChild(zoomPreviewCard); zoomPreviewCard = null; } if (zoomPreviewBg) { game.removeChild(zoomPreviewBg); zoomPreviewBg = null; } isShowingZoom = false; } function getPassiveDescription(passiveType) { return "No passive ability"; } function createCardInfoDisplay(card) { if (isShowingCardInfo) { destroyCardInfoDisplay(); } // Create semi-transparent background at bottom cardInfoBg = game.addChild(LK.getAsset('playerArea', { anchorX: 0, anchorY: 0, x: 0, y: 2200, alpha: 0.8, tint: 0x2c3e50 })); // Create card name text var nameText = new Text2(card.cardData.name, { size: 48, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.x = 1024; nameText.y = 2320; game.addChild(nameText); // Create passive text if card has passive var passiveText = null; if (card.hasPassive()) { var passiveDesc = getPassiveDescription(card.cardData.passive); passiveText = new Text2("Pasif: " + passiveDesc, { size: 36, fill: 0xF39C12 }); passiveText.anchor.set(0.5, 0.5); passiveText.x = 1024; passiveText.y = 2380; game.addChild(passiveText); } else { passiveText = new Text2("Pasif: Yok", { size: 36, fill: 0x95A5A6 }); passiveText.anchor.set(0.5, 0.5); passiveText.x = 1024; passiveText.y = 2380; game.addChild(passiveText); } // Store references for cleanup cardInfoDisplay = { background: cardInfoBg, nameText: nameText, passiveText: passiveText }; isShowingCardInfo = true; // Auto-hide after 3 seconds LK.setTimeout(function () { destroyCardInfoDisplay(); }, 3000); } function destroyCardInfoDisplay() { if (!isShowingCardInfo || !cardInfoDisplay) return; if (cardInfoDisplay.background) { game.removeChild(cardInfoDisplay.background); } if (cardInfoDisplay.nameText) { game.removeChild(cardInfoDisplay.nameText); } if (cardInfoDisplay.passiveText) { game.removeChild(cardInfoDisplay.passiveText); } cardInfoDisplay = null; cardInfoBg = null; isShowingCardInfo = false; } // Event handlers game.down = function (x, y, obj) { if (gamePhase !== "playing" || currentPlayer !== 0 || combatPhase) return; // Close zoom preview if showing if (isShowingZoom) { destroyZoomPreview(); return; } // Close card info display if showing if (isShowingCardInfo) { destroyCardInfoDisplay(); } // Check if end turn button was clicked if (x >= 1700 && x <= 1900 && y >= 1910 && y <= 1990) { endTurn(); return; } // Check if a spell was clicked for (var i = 0; i < humanPlayer.spells.length; i++) { var spell = humanPlayer.spells[i]; var spellBounds = { left: spell.x - 60, right: spell.x + 60, top: spell.y - 60, bottom: spell.y + 60 }; if (x >= spellBounds.left && x <= spellBounds.right && y >= spellBounds.top && y <= spellBounds.bottom) { if (spell.isUsable) { // Start dragging spell instead of auto-casting draggedCard = spell; selectedCard = spell; } return; } } // Check if a hand card was clicked for (var i = 0; i < humanPlayer.hand.length; i++) { var card = humanPlayer.hand[i]; var cardBounds = { left: card.x - 90, right: card.x + 90, top: card.y - 125, bottom: card.y + 125 }; if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) { // Check for double-tap var currentTime = Date.now(); if (lastTappedCard === card && currentTime - lastTapTime < doubleTapThreshold) { // Double-tap detected - show card info createCardInfoDisplay(card); lastTappedCard = null; lastTapTime = 0; return; } // Record this tap lastTappedCard = card; lastTapTime = currentTime; if (card.isPlayable) { selectedCard = card; draggedCard = card; // Start long press timer for zoom preview if (zoomPreviewTimeout) { LK.clearTimeout(zoomPreviewTimeout); } zoomPreviewTimeout = LK.setTimeout(function () { if (selectedCard === card) { createZoomPreview(card); draggedCard = null; // Cancel drag when showing zoom } }, 800); // 800ms long press } return; } } // Check battlefield cards for zoom preview var allBattlefieldCards = humanPlayer.battlefield.concat(aiPlayer.battlefield); for (var i = 0; i < allBattlefieldCards.length; i++) { var card = allBattlefieldCards[i]; var cardBounds = { left: card.x - 90, right: card.x + 90, top: card.y - 125, bottom: card.y + 125 }; if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) { // Check for double-tap on battlefield cards var currentTime = Date.now(); if (lastTappedCard === card && currentTime - lastTapTime < doubleTapThreshold) { // Double-tap detected - show card info createCardInfoDisplay(card); lastTappedCard = null; lastTapTime = 0; return; } // Record this tap lastTappedCard = card; lastTapTime = currentTime; // Start long press timer for battlefield card zoom if (zoomPreviewTimeout) { LK.clearTimeout(zoomPreviewTimeout); } zoomPreviewTimeout = LK.setTimeout(function () { createZoomPreview(card); }, 800); return; } } // Battlefield cards can no longer be manually selected for attacking // Combat is now automatic at end of turn }; game.move = function (x, y, obj) { // Cancel zoom preview if user starts moving if (zoomPreviewTimeout) { LK.clearTimeout(zoomPreviewTimeout); zoomPreviewTimeout = null; } if (draggedCard) { draggedCard.x = x; draggedCard.y = y; // If dragging a spell, highlight potential targets if (draggedCard.castSpell) { // Reset all card alphas first for (var i = 0; i < aiPlayer.battlefield.length; i++) { aiPlayer.battlefield[i].alpha = 1.0; } for (var i = 0; i < humanPlayer.battlefield.length; i++) { humanPlayer.battlefield[i].alpha = 1.0; } // Determine which cards to highlight based on spell target type var targetCards = []; if (draggedCard.spellData.target === "enemy") { targetCards = aiPlayer.battlefield; } else if (draggedCard.spellData.target === "ally") { targetCards = humanPlayer.battlefield; } // Highlight cards that are close to the spell for (var i = 0; i < targetCards.length; i++) { var card = targetCards[i]; var distance = Math.sqrt((card.x - x) * (card.x - x) + (card.y - y) * (card.y - y)); if (distance < 150) { card.alpha = 0.7; } } } } }; game.up = function (x, y, obj) { // Clear zoom preview timeout if (zoomPreviewTimeout) { LK.clearTimeout(zoomPreviewTimeout); zoomPreviewTimeout = null; } // Handle spell targeting if (draggedCard && draggedCard.castSpell) { var target = null; var targetCards = []; // Determine valid targets based on spell type if (draggedCard.spellData.target === "enemy") { targetCards = aiPlayer.battlefield; } else if (draggedCard.spellData.target === "ally") { targetCards = humanPlayer.battlefield; } // Check if spell was dropped on a valid target card for (var i = 0; i < targetCards.length; i++) { var card = targetCards[i]; var cardBounds = { left: card.x - 90, right: card.x + 90, top: card.y - 125, bottom: card.y + 125 }; if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) { target = card; break; } } // Cast spell if valid target found if (target && target.isOnBattlefield && humanPlayer.castSpell(draggedCard, target)) { updateUI(); arrangeHand(); } // Reset all card alphas after spell targeting for (var i = 0; i < aiPlayer.battlefield.length; i++) { aiPlayer.battlefield[i].alpha = 1.0; } for (var i = 0; i < humanPlayer.battlefield.length; i++) { humanPlayer.battlefield[i].alpha = 1.0; } // Return spell to original position arrangeSpells(); draggedCard = null; selectedCard = null; return; } if (draggedCard && y < 1350 && y > 700) { // Determine which lane the card was dropped in var targetLane = -1; if (x >= 380 && x < 812) targetLane = 0; // Left lane else if (x >= 812 && x < 1236) targetLane = 1; // Center lane else if (x >= 1236 && x < 1668) targetLane = 2; // Right lane // Check if lane is available and card can be played if (targetLane >= 0 && humanPlayer.battlefield.length < 3) { // Check if target lane is already occupied var laneOccupied = false; for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (humanPlayer.battlefield[i].laneIndex === targetLane) { laneOccupied = true; break; } } // Check if placing Lucifer would face another Lucifer in same lane var luciferBlocked = false; if (draggedCard.cardData.name === "Lucifer") { // Check if AI has Lucifer in the target lane for (var j = 0; j < aiPlayer.battlefield.length; j++) { if (aiPlayer.battlefield[j].laneIndex === targetLane && aiPlayer.battlefield[j].cardData.name === "Lucifer") { luciferBlocked = true; break; } } } if (!laneOccupied && !luciferBlocked && humanPlayer.playCard(draggedCard)) { draggedCard.laneIndex = targetLane; draggedCard.targetLane = targetLane; draggedCard = null; selectedCard = null; updateUI(); arrangeHand(); arrangeBattlefield(); } } } selectedCard = null; if (draggedCard) { arrangeHand(); draggedCard = null; } // Dead cards are now automatically removed in takeDamage function updateUI(); arrangeBattlefield(); checkGameOver(); }; // Mana regeneration timer var manaRegenTimer = 0; var manaRegenInterval = 500; // Regenerate mana every 500ms game.update = function () { if (gamePhase === "playing") { // Handle mana regeneration during active turn if (currentPlayer === 0 && !combatPhase) { // Only for human player during their turn manaRegenTimer += LK.deltaTime; if (manaRegenTimer >= manaRegenInterval) { if (humanPlayer.currentMana < humanPlayer.maxMana) { humanPlayer.currentMana = Math.min(humanPlayer.maxMana, humanPlayer.currentMana + 2); // Mana regeneration visual effect var manaOrbEffect = game.addChild(LK.getAsset('manaOrb', { anchorX: 0.5, anchorY: 0.5, x: 50, y: 2000, alpha: 0.8 })); tween(manaOrbEffect, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(manaOrbEffect); } }); } manaRegenTimer = 0; } } updateUI(); } }; // Initial setup updateUI(); arrangeHand(); arrangeBattlefield(); arrangeSpells();
===================================================================
--- original.js
+++ change.js
@@ -960,10 +960,10 @@
var spell = spells[i];
if (!game.children.includes(spell)) {
game.addChild(spell);
}
- spell.x = 150 + i * 140;
- spell.y = 2050;
+ spell.x = 150;
+ spell.y = 2150 + i * 140;
spell.isUsable = humanPlayer.canCastSpell(spell) && currentPlayer === 0 && !combatPhase;
// Visual feedback for usable spells
if (spell.isUsable) {
spell.alpha = 1.0;
End turn button fark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Kart alanı dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Ateş ruhu karakteri dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Lightning spirit character Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Kocaman kayadan oluşan golem kırmızı parıldayan gözlere sahip dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Air wisp character dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Arka planı doldur sadece aynısını yap
Koridor yukarıdan bakış dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Ateş 🔥 dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Ulan yatay tarsfa doğru geniş yap yüksekliğe doğru küçük yap
Shadow drake dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Michael demiurgos dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
İnfinity Minion character dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Fireball dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Magic stand dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Play button Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Deck yaz ama düzgün bir arka planla
Büyü asası logosu Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Suikastçı bıçağı logosu Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Kalkan logosu Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Warrior logo Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Sadece freeze büyüsü yap insan olmasın Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Sadece play yerine Wiki yaz
Spell icon Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
İpuçları icon Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Synergy icon Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Game Rules dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Frost Wolf Man Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Water spirit dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Phoenix woman Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Void Stalker Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows
Crystal guardian Dark souls style 2d pixel art. In-Game asset. 2d. High contrast. No shadows