/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.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 }; // 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; } // Initialize passive abilities based on card name if not already set if (!self.cardData.passive) { switch (self.cardData.name) { case "Fire Imp": self.cardData.passive = "burn"; break; case "Water Spirit": self.cardData.passive = "heal"; break; case "Earth Golem": self.cardData.passive = "stone_skin"; break; case "Air Wisp": self.cardData.passive = "evasion"; break; case "Lightning Bolt": self.cardData.passive = "shock"; break; case "Lucifer": self.cardData.passive = "lifesteal"; break; case "Shadow Drake": self.cardData.passive = "shadow"; break; case "Michael Demiurgos": self.cardData.passive = "divine_shield"; break; case "Frost Wolf": self.cardData.passive = "frost"; break; case "Phoenix": self.cardData.passive = "rebirth"; break; case "Void Stalker": self.cardData.passive = "void"; break; case "Crystal Guardian": self.cardData.passive = "crystal_shield"; break; } } self.maxHealth = self.cardData.health; self.currentHealth = self.cardData.health; self.synergyAttackBonus = 0; // Track synergy bonuses self.synergyHealthBonus = 0; self.synergyHealthRegen = 0; // Track health regeneration per turn self.synergyRage = false; // Track rage mechanic for Mage cards self.frozenTurns = 0; // Track frozen state duration 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; case "Frost Wolf": cardAssetName = 'frostWolfBg'; symbolAssetName = 'frostWolfSymbol'; break; case "Phoenix": cardAssetName = 'phoenixBg'; symbolAssetName = 'phoenixSymbol'; break; case "Void Stalker": cardAssetName = 'voidStalkerBg'; symbolAssetName = 'voidStalkerSymbol'; break; case "Crystal Guardian": cardAssetName = 'crystalGuardianBg'; symbolAssetName = 'crystalGuardianSymbol'; 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 } // Add class indicators for cards var classAsset = null; if (self.cardData.name === "Earth Golem" || self.cardData.name === "Lightning Bolt") { classAsset = self.attachAsset('tankClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Fire Imp" || self.cardData.name === "Water Spirit") { classAsset = self.attachAsset('mageClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Shadow Drake" || self.cardData.name === "Michael Demiurgos") { classAsset = self.attachAsset('rogueClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Air Wisp") { classAsset = self.attachAsset('warriorClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Lucifer") { classAsset = self.attachAsset('warriorClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Frost Wolf") { classAsset = self.attachAsset('warriorClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Phoenix") { classAsset = self.attachAsset('mageClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Void Stalker") { classAsset = self.attachAsset('rogueClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } else if (self.cardData.name === "Crystal Guardian") { classAsset = self.attachAsset('tankClass', { anchorX: 1, anchorY: 0 }); classAsset.x = 80; // Top right corner classAsset.y = -100; } // Card text elements - name removed 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 () { // Calculate health with synergy bonus (Tank cards now get health bonus display) var cardClass = getCardClass(self.cardData.name); var healthBonus = self.synergyHealthBonus || 0; var synergyMaxHealth = self.cardData.health + healthBonus; var adjustedCurrentHealth = self.currentHealth + healthBonus; var displayHealth = isNaN(adjustedCurrentHealth) ? 0 : Math.max(0, adjustedCurrentHealth); // 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 with synergy bonus if (self.healthText) { self.healthText.setText(displayHealth.toString()); // Change color if synergy bonus is active (including Tank cards) var cardClass = getCardClass(self.cardData.name); if (healthBonus > 0) { self.healthText.fill = 0x00ff00; // Green for boosted health } else { self.healthText.fill = 0x27AE60; // Normal green } } else if (healthText) { healthText.setText(displayHealth.toString()); } // Update attack text with synergy bonus if (self.attackText && self.cardData.attack !== undefined) { var displayAttack = self.cardData.attack + (self.synergyAttackBonus || 0); self.attackText.setText(displayAttack.toString()); // Change color if synergy bonus is active (but not for Mage rage) var cardClass = getCardClass(self.cardData.name); if (self.synergyAttackBonus > 0) { self.attackText.fill = 0x00ff00; // Green for boosted attack } else if (self.synergyRage && cardClass === "Mage") { self.attackText.fill = 0xFF4444; // Red glow for rage-enabled Mage cards } else { self.attackText.fill = 0xE74C3C; // Normal red } } // 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; } // Check for damage prevention passives var damageContext = { attacker: attacker, damage: damage }; var passiveResult = self.triggerPassive("before_damage", damageContext); if (passiveResult === -1) { // Damage was negated by passive ability return; } // Update damage if it was modified by passive (like stone_skin) if (damageContext.damage !== undefined) { damage = damageContext.damage; } // Check for Rogue synergy dodge var cardClass = getCardClass(self.cardData.name); if (cardClass === "Rogue" && self.isOnBattlefield) { // Find which player owns this card var ownerPlayer = null; 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; } } } if (ownerPlayer) { // Count Rogue cards on battlefield var rogueCount = 0; for (var i = 0; i < ownerPlayer.battlefield.length; i++) { if (getCardClass(ownerPlayer.battlefield[i].cardData.name) === "Rogue") { rogueCount++; } } // Rogue synergy triggers with 2 or more Rogue cards if (rogueCount >= 2 && Math.random() < 0.2) { // 20% chance to dodge var dodgeText = new Text2("ROGUE DODGE!", { size: 35, fill: 0x8e44ad }); dodgeText.anchor.set(0.5, 0.5); dodgeText.x = self.x; dodgeText.y = self.y - 50; dodgeText.alpha = 1.0; game.addChild(dodgeText); tween(dodgeText, { y: dodgeText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(dodgeText); } }); LK.effects.flashObject(self, 0x8e44ad, 300); return; // Damage was dodged } } } // Check for Crystal Guardian damage reduction var ownerPlayer = null; 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; } } } // Apply Crystal Guardian damage reduction if (ownerPlayer) { for (var i = 0; i < ownerPlayer.battlefield.length; i++) { if (ownerPlayer.battlefield[i].cardData.name === "Crystal Guardian" && ownerPlayer.battlefield[i].currentHealth > 0) { damage = Math.max(0, damage - 1); // Show crystal shield effect var shieldText = new Text2("CRYSTAL SHIELD!", { size: 35, fill: 0x00FFFF }); shieldText.anchor.set(0.5, 0.5); shieldText.x = self.x; shieldText.y = self.y - 50; shieldText.alpha = 1.0; game.addChild(shieldText); tween(shieldText, { y: shieldText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(shieldText); } }); LK.effects.flashObject(self, 0x00FFFF, 300); break; } } } 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 1 health when dealing damage to other cards if (attacker && attacker.cardData.name === "Lucifer" && self.isOnBattlefield) { // Heal Lucifer by 1 health (not exceeding max health) var healAmount = 1; 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); } // Vampire passive: heal equal to damage dealt if (attacker && attacker.isOnBattlefield && getCardClass(attacker.cardData.name) === "Vampire") { // Check if vampire synergy is active (2 or more vampire cards) var attackerPlayer = null; // Find which player owns the attacker for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (humanPlayer.battlefield[i] === attacker) { attackerPlayer = humanPlayer; break; } } if (!attackerPlayer) { for (var i = 0; i < aiPlayer.battlefield.length; i++) { if (aiPlayer.battlefield[i] === attacker) { attackerPlayer = aiPlayer; break; } } } if (attackerPlayer) { // Count vampire cards on battlefield var vampireCount = 0; for (var i = 0; i < attackerPlayer.battlefield.length; i++) { if (getCardClass(attackerPlayer.battlefield[i].cardData.name) === "Vampire") { vampireCount++; } } // Vampire synergy triggers with 2 or more vampire cards if (vampireCount >= 2) { var healAmount = finalDamage; // Heal equal to damage dealt var oldHealth = attacker.currentHealth; attacker.currentHealth = Math.min(attacker.maxHealth, attacker.currentHealth + healAmount); // Only show effect if health was actually restored if (attacker.currentHealth > oldHealth) { var actualHeal = attacker.currentHealth - oldHealth; attacker.updateHealthDisplay(); // Create vampire healing visual effect var vampireHealText = new Text2("+" + actualHeal.toString(), { size: 38, fill: 0x8B0000 // Dark red for vampire heal }); vampireHealText.anchor.set(0.5, 0.5); vampireHealText.x = attacker.x + (Math.random() - 0.5) * 60; vampireHealText.y = attacker.y - 60; vampireHealText.alpha = 1.0; game.addChild(vampireHealText); // Animate vampire healing with blood-like effect tween(vampireHealText, { y: vampireHealText.y - 90, alpha: 0, scaleX: 1.4, scaleY: 1.4 }, { duration: 900, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(vampireHealText); } }); // Dark red flash on vampire card LK.effects.flashObject(attacker, 0x8B0000, 400); } } } } // 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.frozenTurns || self.frozenTurns <= 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 base attack value plus synergy bonus var totalDamage = self.cardData.attack + (self.synergyAttackBonus || 0); // Apply Mage rage mechanic if enabled var isCriticalHit = false; if (self.synergyRage && Math.random() < 0.25) { totalDamage *= 2; // Double damage on rage proc isCriticalHit = true; // Critical hit screen flash LK.effects.flashScreen(0xFFD700, 400); // Show critical hit effect var critText = new Text2("KRİTİK VURUŞ!", { size: 50, fill: 0xFFD700 }); critText.anchor.set(0.5, 0.5); critText.x = self.x + (Math.random() - 0.5) * 60; critText.y = self.y - 80; critText.alpha = 1.0; game.addChild(critText); // Create sparkle effects around the attacking card for (var sparkle = 0; sparkle < 6; sparkle++) { var spark = game.addChild(LK.getAsset('manaOrb', { anchorX: 0.5, anchorY: 0.5, x: self.x + (Math.random() - 0.5) * 120, y: self.y + (Math.random() - 0.5) * 120, scaleX: 0.3, scaleY: 0.3, alpha: 1.0, tint: 0xFFD700 })); // Animate sparkles tween(spark, { scaleX: 0.8, scaleY: 0.8, alpha: 0, x: spark.x + (Math.random() - 0.5) * 200, y: spark.y + (Math.random() - 0.5) * 200 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { if (game.children.includes(spark)) { game.removeChild(spark); } } }); } // Animate critical text with glow effect tween(critText, { y: critText.y - 80, alpha: 0, scaleX: 2.0, scaleY: 2.0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(critText); } }); // Enhanced card flash for critical hit tween(self, { tint: 0xFFD700, scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { tint: 0xFFFFFF, scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn }); } }); } // 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; // Handle frozen state if (self.frozenTurns > 0) { self.frozenTurns--; if (self.frozenTurns <= 0) { // Return to normal state when freeze ends self.alpha = 1.0; self.tint = 0xFFFFFF; // Remove blue tint } } if (self.currentHealth > 0) { cardBg.alpha = 1.0; } }; // Passive ability system self.triggerPassive = function (trigger, context) { if (!self.hasPassive()) return 0; var passiveType = self.cardData.passive; var effect = 0; switch (passiveType) { case "burn": if (trigger === "end_turn" && self.isOnBattlefield) { // Fire Imp: Burns all enemy cards for 1 damage at end of turn var enemyPlayer = context.player.isHuman ? aiPlayer : humanPlayer; for (var i = 0; i < enemyPlayer.battlefield.length; i++) { var enemyCard = enemyPlayer.battlefield[i]; if (enemyCard.currentHealth > 0) { enemyCard.takeDamage(1, self); // Create burn visual effect var burnEffect = game.addChild(LK.getAsset('burnEffect', { anchorX: 0.5, anchorY: 0.5, x: enemyCard.x + (Math.random() - 0.5) * 40, y: enemyCard.y - 30, alpha: 0.8, tint: 0xff4400 })); tween(burnEffect, { y: burnEffect.y - 60, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(burnEffect); } }); } } effect = 1; } break; case "heal": if (trigger === "turn_start" && self.isOnBattlefield) { // Water Spirit: Heals 1 health at start of turn var oldHealth = self.currentHealth; self.currentHealth = Math.min(self.maxHealth, self.currentHealth + 1); if (self.currentHealth > oldHealth) { self.updateHealthDisplay(); // Create healing visual effect var healText = new Text2("+1", { size: 30, fill: 0x00ff00 }); healText.anchor.set(0.5, 0.5); healText.x = self.x + (Math.random() - 0.5) * 40; healText.y = self.y - 30; healText.alpha = 1.0; game.addChild(healText); tween(healText, { y: healText.y - 60, alpha: 0, scaleX: 1.2, scaleY: 1.2 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(healText); } }); LK.effects.flashObject(self, 0x00ff00, 200); effect = 1; } } break; case "shock": if (trigger === "played") { // Lightning Bolt: Deals 3 damage to all enemies when played var enemyPlayer = context.player.isHuman ? aiPlayer : humanPlayer; for (var i = 0; i < enemyPlayer.battlefield.length; i++) { var enemyCard = enemyPlayer.battlefield[i]; if (enemyCard.currentHealth > 0) { enemyCard.takeDamage(3, self); } } // Screen flash for shock effect LK.effects.flashScreen(0xffff00, 300); effect = 1; } break; case "evasion": // Check if Warrior synergy is active for Air Wisp var evasionChance = 0.25; // Default 25% chance if (self.cardData.name === "Air Wisp" && self.isOnBattlefield) { // Find which player owns this card var ownerPlayer = null; 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; } } } if (ownerPlayer) { // Count Warrior cards on battlefield var warriorCount = 0; for (var i = 0; i < ownerPlayer.battlefield.length; i++) { if (getCardClass(ownerPlayer.battlefield[i].cardData.name) === "Warrior") { warriorCount++; } } // Warrior synergy triggers with 2 or more Warrior cards if (warriorCount >= 2) { evasionChance = 0.60; // Increase to 60% with synergy } } } if (trigger === "before_damage" && Math.random() < evasionChance) { // Air Wisp: evasion chance (25% base, 60% with Warrior synergy) var dodgeText = new Text2("DODGE!", { size: 35, fill: 0x00ffff }); dodgeText.anchor.set(0.5, 0.5); dodgeText.x = self.x; dodgeText.y = self.y - 50; dodgeText.alpha = 1.0; game.addChild(dodgeText); tween(dodgeText, { y: dodgeText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(dodgeText); } }); LK.effects.flashObject(self, 0x00ffff, 300); return -1; // Negative return indicates damage should be negated } break; case "divine_shield": if (trigger === "played" && !self.shieldUsed) { // Initialize divine shield when card is played self.shieldUsed = false; self.alpha = 0.9; // Slight transparency to indicate shield } if (trigger === "before_damage" && !self.shieldUsed) { // Michael Demiurgos: Ignores first damage taken self.shieldUsed = true; self.alpha = 1.0; // Return to normal transparency var shieldText = new Text2("DIVINE SHIELD!", { size: 35, fill: 0xffd700 }); shieldText.anchor.set(0.5, 0.5); shieldText.x = self.x; shieldText.y = self.y - 50; shieldText.alpha = 1.0; game.addChild(shieldText); tween(shieldText, { y: shieldText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(shieldText); } }); LK.effects.flashObject(self, 0xffd700, 400); return -1; // Negative return indicates damage should be negated } if (trigger === "before_damage" && self.shieldUsed && turnCounter > 1 && Math.random() < 0.1) { // Michael Demiurgos: 10% chance to avoid damage after first turn var dodgeText = new Text2("DIVINE PROTECTION!", { size: 35, fill: 0xffd700 }); dodgeText.anchor.set(0.5, 0.5); dodgeText.x = self.x; dodgeText.y = self.y - 50; dodgeText.alpha = 1.0; game.addChild(dodgeText); tween(dodgeText, { y: dodgeText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(dodgeText); } }); LK.effects.flashObject(self, 0xffd700, 300); return -1; // Negative return indicates damage should be negated } break; case "stealth": if (trigger === "played") { // Shadow Drake: Cannot be targeted by spells for first turn self.stealthTurns = 1; var stealthText = new Text2("STEALTH", { size: 30, fill: 0x8b008b }); stealthText.anchor.set(0.5, 0.5); stealthText.x = self.x; stealthText.y = self.y - 50; stealthText.alpha = 1.0; game.addChild(stealthText); tween(stealthText, { y: stealthText.y - 60, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(stealthText); } }); self.alpha = 0.7; // Visual indicator of stealth effect = 1; } else if (trigger === "turn_start" && self.stealthTurns > 0) { self.stealthTurns--; if (self.stealthTurns <= 0) { self.alpha = 1.0; // Return to normal visibility } } break; case "taunt": // Earth Golem: Forces enemies to attack this card first // This is handled in AI targeting logic and combat resolution break; case "frost": // Frost Wolf: Slows enemy cards when attacking them if (trigger === "attack_dealt" && context.target && context.target.isOnBattlefield) { // Add slow effect - reduce attack by 1 for 2 turns context.target.frostSlowTurns = 2; context.target.frostSlowAmount = 1; var frostText = new Text2("FROST SLOW!", { size: 35, fill: 0x87CEEB }); frostText.anchor.set(0.5, 0.5); frostText.x = context.target.x; frostText.y = context.target.y - 50; frostText.alpha = 1.0; game.addChild(frostText); tween(frostText, { y: frostText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(frostText); } }); LK.effects.flashObject(context.target, 0x87CEEB, 400); effect = 1; } break; case "rebirth": if (trigger === "death" && !self.hasRebirthed && self.isOnBattlefield) { // Phoenix: Revives once when destroyed with half health self.hasRebirthed = true; self.currentHealth = Math.ceil(self.maxHealth / 2); self.updateHealthDisplay(); // Create rebirth visual effect var rebirthText = new Text2("REBIRTH!", { size: 45, fill: 0xFF6B00 }); rebirthText.anchor.set(0.5, 0.5); rebirthText.x = self.x; rebirthText.y = self.y - 50; rebirthText.alpha = 1.0; game.addChild(rebirthText); // Create fire effect around Phoenix for (var flame = 0; flame < 8; flame++) { var fireEffect = game.addChild(LK.getAsset('burnEffect', { anchorX: 0.5, anchorY: 0.5, x: self.x + Math.cos(flame * Math.PI / 4) * 60, y: self.y + Math.sin(flame * Math.PI / 4) * 60, scaleX: 0.8, scaleY: 0.8, alpha: 0.9, tint: 0xFF4500 })); tween(fireEffect, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { if (game.children.includes(fireEffect)) { game.removeChild(fireEffect); } } }); } // Animate rebirth text tween(rebirthText, { y: rebirthText.y - 80, alpha: 0, scaleX: 2.0, scaleY: 2.0 }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(rebirthText); } }); // Flash Phoenix with fire colors LK.effects.flashObject(self, 0xFF6B00, 600); effect = 1; } break; case "void": if (trigger === "before_damage" && self.isOnBattlefield && Math.random() < 0.3) { // Void Stalker: 30% chance to teleport to different lane when taking damage var ownerPlayer = null; 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; } } } if (ownerPlayer) { // Find available lanes var availableLanes = [0, 1, 2]; var currentLane = self.laneIndex; // Remove current lane and occupied lanes for (var i = 0; i < ownerPlayer.battlefield.length; i++) { var occupiedLane = ownerPlayer.battlefield[i].laneIndex; if (occupiedLane !== undefined) { var laneIdx = availableLanes.indexOf(occupiedLane); if (laneIdx >= 0) availableLanes.splice(laneIdx, 1); } } // If there are available lanes, teleport if (availableLanes.length > 0) { var newLane = availableLanes[Math.floor(Math.random() * availableLanes.length)]; self.laneIndex = newLane; var lanePositions = [600, 1024, 1448]; // Teleport animation var voidText = new Text2("VOID TELEPORT!", { size: 35, fill: 0x8B008B }); voidText.anchor.set(0.5, 0.5); voidText.x = self.x; voidText.y = self.y - 50; voidText.alpha = 1.0; game.addChild(voidText); // Fade out at current position tween(self, { alpha: 0.2, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Move to new lane self.x = lanePositions[newLane]; // Fade back in at new position tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut }); } }); tween(voidText, { y: voidText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(voidText); } }); LK.effects.flashObject(self, 0x8B008B, 400); effect = 1; return -1; // Negative return indicates damage should be negated } } } break; case "crystal_shield": // Crystal Guardian: Reduces damage taken by all friendly cards by 1 // This is implemented in the damage calculation of other cards break; case "stone_skin": if (trigger === "before_damage" && self.isOnBattlefield) { // Earth Golem: Reduces all damage taken by 1 (minimum 1 damage) if (context.damage && context.damage > 1) { context.damage = Math.max(1, context.damage - 1); var stoneText = new Text2("STONE SKIN!", { size: 35, fill: 0x8B4513 }); stoneText.anchor.set(0.5, 0.5); stoneText.x = self.x; stoneText.y = self.y - 50; stoneText.alpha = 1.0; game.addChild(stoneText); tween(stoneText, { y: stoneText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(stoneText); } }); LK.effects.flashObject(self, 0x8B4513, 400); effect = 1; } } break; case "shadow": if (trigger === "played") { // Shadow Drake: Becomes invisible for 2 turns, cannot be targeted by spells or direct attacks self.shadowTurns = 2; self.alpha = 0.5; // Visual indicator of shadow state var shadowText = new Text2("SHADOW CLOAK!", { size: 35, fill: 0x8B008B }); shadowText.anchor.set(0.5, 0.5); shadowText.x = self.x; shadowText.y = self.y - 50; shadowText.alpha = 1.0; game.addChild(shadowText); tween(shadowText, { y: shadowText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(shadowText); } }); LK.effects.flashObject(self, 0x8B008B, 600); effect = 1; } else if (trigger === "turn_start" && self.shadowTurns > 0) { // Reduce shadow duration self.shadowTurns--; if (self.shadowTurns <= 0) { self.alpha = 1.0; // Return to normal visibility var unshadowText = new Text2("SHADOW FADES", { size: 30, fill: 0x8B008B }); unshadowText.anchor.set(0.5, 0.5); unshadowText.x = self.x; unshadowText.y = self.y - 50; unshadowText.alpha = 1.0; game.addChild(unshadowText); tween(unshadowText, { y: unshadowText.y - 60, alpha: 0, scaleX: 1.2, scaleY: 1.2 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(unshadowText); } }); } } break; } return effect; }; self.hasPassive = function () { return self.cardData.passive !== null && self.cardData.passive !== undefined; }; // 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 DeckView = Container.expand(function () { var self = Container.call(this); // Dark overlay background var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.9 }); // Title var titleText = new Text2("KART VE BÜYÜ KOLEKSİYONU", { size: 80, fill: 0xf39c12 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 200; self.addChild(titleText); // Cards section title var cardsTitle = new Text2("KARTLAR", { size: 60, fill: 0x3498db }); cardsTitle.anchor.set(0.5, 0.5); cardsTitle.x = 1024; cardsTitle.y = 350; self.addChild(cardsTitle); // Spells section title var spellsTitle = new Text2("BÜYÜLER", { size: 60, fill: 0x9b59b6 }); spellsTitle.anchor.set(0.5, 0.5); spellsTitle.x = 1024; spellsTitle.y = 1800; self.addChild(spellsTitle); // Close button var closeBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2400, scaleX: 0.8, scaleY: 0.8 }); // Create sample cards for display var cardTypes = [{ name: "Fire Imp", cost: 3, attack: 2, health: 5, description: "A small fire creature", passive: "burn" }, { name: "Water Spirit", cost: 2, attack: 2, health: 4, description: "A defensive water creature", passive: "heal" }, { name: "Earth Golem", cost: 3, attack: 1, health: 10, description: "A powerful earth creature", passive: "taunt" }, { name: "Air Wisp", cost: 1, attack: 1, health: 3, description: "A quick air creature", passive: "evasion" }, { name: "Lightning Bolt", cost: 2, attack: 1, health: 5, description: "A shocking creature", passive: "shock" }, { name: "Lucifer", cost: 4, attack: 3, health: 6, description: "A mystical water spirit with high endurance", passive: "lifesteal" }, { name: "Shadow Drake", cost: 3, attack: 3, health: 4, description: "A powerful shadow dragon", passive: "stealth" // Cannot be targeted by spells for first turn }, { name: "Michael Demiurgos", cost: 4, attack: 2, health: 7, description: "An archangel with divine power", passive: "divine_shield" }, { name: "Frost Wolf", cost: 3, attack: 2, health: 6, description: "A fierce ice wolf with freezing attacks", passive: "frost" }, { name: "Phoenix", cost: 4, attack: 3, health: 4, description: "A legendary fire bird that can rise from ashes", passive: "rebirth" }, { name: "Void Stalker", cost: 3, attack: 2, health: 5, description: "A shadowy creature from the void with teleportation abilities", passive: "void" }, { name: "Crystal Guardian", cost: 4, attack: 1, health: 8, description: "A mystical crystal protector that shields nearby allies", passive: "crystal_shield" }]; // Display cards in a grid (4 cards per row) self.displayCards = []; for (var i = 0; i < cardTypes.length; i++) { var displayCard = new Card(cardTypes[i]); var row = Math.floor(i / 4); var col = i % 4; var startX = 1024 - 3 * 100; // Center 4 cards displayCard.x = startX + col * 200; displayCard.y = 500 + row * 300; displayCard.scaleX = 0.6; displayCard.scaleY = 0.6; self.addChild(displayCard); self.displayCards.push(displayCard); // Add class logos to cards in deck view var classAsset = null; if (cardTypes[i].name === "Earth Golem" || cardTypes[i].name === "Lightning Bolt") { classAsset = self.attachAsset('tankClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Fire Imp" || cardTypes[i].name === "Water Spirit") { classAsset = self.attachAsset('mageClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Shadow Drake" || cardTypes[i].name === "Michael Demiurgos") { classAsset = self.attachAsset('rogueClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Air Wisp") { classAsset = self.attachAsset('warriorClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Lucifer") { classAsset = self.attachAsset('warriorClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Frost Wolf") { classAsset = self.attachAsset('warriorClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Phoenix") { classAsset = self.attachAsset('mageClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Void Stalker") { classAsset = self.attachAsset('rogueClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } else if (cardTypes[i].name === "Crystal Guardian") { classAsset = self.attachAsset('tankClass', { anchorX: 1, anchorY: 0 }); classAsset.x = displayCard.x + 48; // Adjusted for scaled card classAsset.y = displayCard.y - 60; classAsset.scaleX = 0.6; classAsset.scaleY = 0.6; } } // Create sample spells for display var spellTypes = [{ name: "Fire Ball", cost: 2, damage: 2, target: "enemy", description: "Deals 2 damage to target" }, { name: "Şifa", cost: 2, damage: -2, target: "ally", description: "Heals target for 2 health" }, { name: "Freeze", cost: 2, damage: 0, target: "enemy", description: "Freezes target enemy for 1 turn" }]; // Display spells self.displaySpells = []; for (var i = 0; i < spellTypes.length; i++) { var displaySpell = new Spell(spellTypes[i]); displaySpell.x = 1024 - 100 + i * 200; displaySpell.y = 1950; displaySpell.scaleX = 0.8; displaySpell.scaleY = 0.8; self.addChild(displaySpell); self.displaySpells.push(displaySpell); } self.closeButtonHover = false; self.down = function (x, y, obj) { // If showing zoom, hide it first if (self.isShowingZoom) { self.hideCardZoom(); return; } // Check if close button was clicked if (x >= 824 && x <= 1224 && y >= 2360 && y <= 2440) { // Button press effect tween(closeBtn, { scaleX: 0.75, scaleY: 0.75, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(closeBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Close deck view after animation LK.setTimeout(function () { self.closeDeckView(); }, 200); return; } // Check if any card was clicked for zoom preview for (var i = 0; i < self.displayCards.length; i++) { var card = self.displayCards[i]; var cardBounds = { left: card.x - 54, // card.scaleX is 0.6, so bounds are 90*0.6 = 54 right: card.x + 54, top: card.y - 75, // card.scaleY is 0.6, so bounds are 125*0.6 = 75 bottom: card.y + 75 }; if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) { self.showCardZoom(card); return; } } // Check if any spell was clicked for zoom preview for (var i = 0; i < self.displaySpells.length; i++) { var spell = self.displaySpells[i]; var spellBounds = { left: spell.x - 48, // spell.scaleX is 0.8, so bounds are 60*0.8 = 48 right: spell.x + 48, top: spell.y - 48, // spell.scaleY is 0.8, so bounds are 60*0.8 = 48 bottom: spell.y + 48 }; if (x >= spellBounds.left && x <= spellBounds.right && y >= spellBounds.top && y <= spellBounds.bottom) { self.showSpellZoom(spell); return; } } }; self.move = function (x, y, obj) { // Check if mouse is over close button var isOverCloseButton = x >= 824 && x <= 1224 && y >= 2360 && y <= 2440; if (isOverCloseButton && !self.closeButtonHover) { self.closeButtonHover = true; tween(closeBtn, { scaleX: 0.9, scaleY: 0.9, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverCloseButton && self.closeButtonHover) { self.closeButtonHover = false; tween(closeBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } }; self.closeDeckView = function () { // Fade out deck view tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove deck view and return to menu game.removeChild(self); } }); }; // Entrance animation self.alpha = 0; self.scaleX = 0.8; self.scaleY = 0.8; tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeOut }); // Card zoom preview variables for deck view self.zoomCard = null; self.zoomBg = null; self.zoomTexts = []; self.isShowingZoom = false; self.showCardZoom = function (card) { if (self.isShowingZoom) { self.hideCardZoom(); } // Create dark overlay self.zoomBg = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.95 }); // Create zoomed card self.zoomCard = new Card(card.cardData); self.zoomCard.x = 1024; self.zoomCard.y = 1200; self.zoomCard.scaleX = 3.0; self.zoomCard.scaleY = 3.0; self.addChild(self.zoomCard); // Card name var nameText = new Text2(card.cardData.name, { size: 80, fill: 0xf39c12 }); nameText.anchor.set(0.5, 0.5); nameText.x = 1024; nameText.y = 800; self.addChild(nameText); self.zoomTexts.push(nameText); // Card stats var statsText = new Text2("Mana: " + card.cardData.cost + " | Saldırı: " + card.cardData.attack + " | Can: " + card.cardData.health, { size: 48, fill: 0x3498db }); statsText.anchor.set(0.5, 0.5); statsText.x = 1024; statsText.y = 900; self.addChild(statsText); self.zoomTexts.push(statsText); // Card description var descText = new Text2(card.cardData.description, { size: 40, fill: 0xecf0f1 }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = 1600; self.addChild(descText); self.zoomTexts.push(descText); // Passive abilities var passiveDesc = card.hasPassive() ? getPassiveDescription(card.cardData.passive) : "Yok"; var passiveText = new Text2("Pasif Yetenek: " + passiveDesc, { size: 36, fill: card.hasPassive() ? 0xf39c12 : 0x95a5a6 }); passiveText.anchor.set(0.5, 0.5); passiveText.x = 1024; passiveText.y = 1700; self.addChild(passiveText); self.zoomTexts.push(passiveText); // Close instruction var closeText = new Text2("Kapatmak için herhangi bir yere tıklayın", { size: 32, fill: 0x7f8c8d }); closeText.anchor.set(0.5, 0.5); closeText.x = 1024; closeText.y = 2000; self.addChild(closeText); self.zoomTexts.push(closeText); // Animate zoom in self.zoomCard.alpha = 0; self.zoomCard.scaleX = 1.0; self.zoomCard.scaleY = 1.0; tween(self.zoomCard, { alpha: 1.0, scaleX: 3.0, scaleY: 3.0 }, { duration: 400, easing: tween.easeOut }); for (var i = 0; i < self.zoomTexts.length; i++) { self.zoomTexts[i].alpha = 0; tween(self.zoomTexts[i], { alpha: 1.0 }, { duration: 400, easing: tween.easeOut }); } self.isShowingZoom = true; }; self.showSpellZoom = function (spell) { if (self.isShowingZoom) { self.hideCardZoom(); } // Create dark overlay self.zoomBg = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.95 }); // Create zoomed spell self.zoomCard = new Spell(spell.spellData); self.zoomCard.x = 1024; self.zoomCard.y = 1200; self.zoomCard.scaleX = 4.0; self.zoomCard.scaleY = 4.0; self.addChild(self.zoomCard); // Spell name var nameText = new Text2(spell.spellData.name, { size: 80, fill: 0x9b59b6 }); nameText.anchor.set(0.5, 0.5); nameText.x = 1024; nameText.y = 800; self.addChild(nameText); self.zoomTexts.push(nameText); // Spell stats var effectText = spell.spellData.damage >= 0 ? "Hasar: " + spell.spellData.damage : "İyileştirme: " + Math.abs(spell.spellData.damage); var statsText = new Text2("Mana: " + spell.spellData.cost + " | " + effectText + " | Hedef: " + (spell.spellData.target === "enemy" ? "Düşman" : "Müttefik"), { size: 48, fill: 0x3498db }); statsText.anchor.set(0.5, 0.5); statsText.x = 1024; statsText.y = 900; self.addChild(statsText); self.zoomTexts.push(statsText); // Spell description var descText = new Text2(spell.spellData.description, { size: 40, fill: 0xecf0f1 }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = 1600; self.addChild(descText); self.zoomTexts.push(descText); // Close instruction var closeText = new Text2("Kapatmak için herhangi bir yere tıklayın", { size: 32, fill: 0x7f8c8d }); closeText.anchor.set(0.5, 0.5); closeText.x = 1024; closeText.y = 2000; self.addChild(closeText); self.zoomTexts.push(closeText); // Animate zoom in self.zoomCard.alpha = 0; self.zoomCard.scaleX = 1.0; self.zoomCard.scaleY = 1.0; tween(self.zoomCard, { alpha: 1.0, scaleX: 4.0, scaleY: 4.0 }, { duration: 400, easing: tween.easeOut }); for (var i = 0; i < self.zoomTexts.length; i++) { self.zoomTexts[i].alpha = 0; tween(self.zoomTexts[i], { alpha: 1.0 }, { duration: 400, easing: tween.easeOut }); } self.isShowingZoom = true; }; self.hideCardZoom = function () { if (!self.isShowingZoom) return; // Animate zoom out if (self.zoomCard) { tween(self.zoomCard, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.removeChild(self.zoomCard); self.zoomCard = null; } }); } // Animate text fade out for (var i = 0; i < self.zoomTexts.length; i++) { var text = self.zoomTexts[i]; tween(text, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.removeChild(text); } }); } // Remove background if (self.zoomBg) { tween(self.zoomBg, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.removeChild(self.zoomBg); self.zoomBg = null; } }); } self.zoomTexts = []; self.isShowingZoom = false; }; return self; }); var DifficultySelection = Container.expand(function () { var self = Container.call(this); // Dark overlay background var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.9 }); // Title var titleText = new Text2("ZORLUK SEÇİN", { size: 100, fill: 0xf39c12 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; self.addChild(titleText); // Easy button var easyBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1000, tint: 0x27ae60 }); var easyBtnText = new Text2("KOLAY", { size: 56, fill: 0xffffff }); easyBtnText.anchor.set(0.5, 0.5); easyBtnText.x = 1024; easyBtnText.y = 1080; self.addChild(easyBtnText); // Medium button var mediumBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1300, tint: 0xf39c12 }); var mediumBtnText = new Text2("ORTA", { size: 56, fill: 0xffffff }); mediumBtnText.anchor.set(0.5, 0.5); mediumBtnText.x = 1024; mediumBtnText.y = 1380; self.addChild(mediumBtnText); // Hard button var hardBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1600, tint: 0xe74c3c }); var hardBtnText = new Text2("ZOR", { size: 56, fill: 0xffffff }); hardBtnText.anchor.set(0.5, 0.5); hardBtnText.x = 1024; hardBtnText.y = 1680; self.addChild(hardBtnText); // Back button var backBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1850, scaleX: 0.8, scaleY: 0.8, tint: 0x95a5a6 }); // Button hover tracking self.easyButtonHover = false; self.mediumButtonHover = false; self.hardButtonHover = false; self.backButtonHover = false; self.down = function (x, y, obj) { // Check if easy button was clicked if (x >= 824 && x <= 1224 && y >= 940 && y <= 1060) { // Button press effect tween(easyBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0x2ecc71 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(easyBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x27ae60 }, { duration: 100, easing: tween.easeOut }); } }); // Start game with easy difficulty LK.setTimeout(function () { self.startGameWithDifficulty("easy"); }, 200); } // Check if medium button was clicked else if (x >= 824 && x <= 1224 && y >= 1240 && y <= 1360) { // Button press effect tween(mediumBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0xe67e22 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(mediumBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0xf39c12 }, { duration: 100, easing: tween.easeOut }); } }); // Start game with medium difficulty LK.setTimeout(function () { self.startGameWithDifficulty("medium"); }, 200); } // Check if hard button was clicked else if (x >= 824 && x <= 1224 && y >= 1540 && y <= 1660) { // Button press effect tween(hardBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0xc0392b }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(hardBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0xe74c3c }, { duration: 100, easing: tween.easeOut }); } }); // Start game with hard difficulty LK.setTimeout(function () { self.startGameWithDifficulty("hard"); }, 200); } // Check if back button was clicked else if (x >= 904 && x <= 1144 && y >= 1810 && y <= 1890) { // Button press effect tween(backBtn, { scaleX: 0.75, scaleY: 0.75, tint: 0x7f8c8d }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(backBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x95a5a6 }, { duration: 100, easing: tween.easeOut }); } }); // Go back to main menu LK.setTimeout(function () { self.goBackToMenu(); }, 200); } }; self.move = function (x, y, obj) { // Check if mouse is over easy button var isOverEasyButton = x >= 824 && x <= 1224 && y >= 940 && y <= 1060; if (isOverEasyButton && !self.easyButtonHover) { self.easyButtonHover = true; tween(easyBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0x2ecc71 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverEasyButton && self.easyButtonHover) { self.easyButtonHover = false; tween(easyBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x27ae60 }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over medium button var isOverMediumButton = x >= 824 && x <= 1224 && y >= 1240 && y <= 1360; if (isOverMediumButton && !self.mediumButtonHover) { self.mediumButtonHover = true; tween(mediumBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0xe67e22 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverMediumButton && self.mediumButtonHover) { self.mediumButtonHover = false; tween(mediumBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0xf39c12 }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over hard button var isOverHardButton = x >= 824 && x <= 1224 && y >= 1540 && y <= 1660; if (isOverHardButton && !self.hardButtonHover) { self.hardButtonHover = true; tween(hardBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0xc0392b }, { duration: 200, easing: tween.easeOut }); } else if (!isOverHardButton && self.hardButtonHover) { self.hardButtonHover = false; tween(hardBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0xe74c3c }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over back button var isOverBackButton = x >= 904 && x <= 1144 && y >= 1810 && y <= 1890; if (isOverBackButton && !self.backButtonHover) { self.backButtonHover = true; tween(backBtn, { scaleX: 0.9, scaleY: 0.9, tint: 0xbdc3c7 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverBackButton && self.backButtonHover) { self.backButtonHover = false; tween(backBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x95a5a6 }, { duration: 200, easing: tween.easeOut }); } }; self.startGameWithDifficulty = function (difficulty) { // Store difficulty for later use gameDifficulty = difficulty; // Update player health based on selected difficulty if (gameDifficulty === "easy") { humanPlayer.health = 20; aiPlayer.health = 15; } else if (gameDifficulty === "medium") { humanPlayer.health = 20; aiPlayer.health = 20; } else if (gameDifficulty === "hard") { humanPlayer.health = 20; aiPlayer.health = 25; } // Fade out difficulty selection tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove difficulty selection and start game game.removeChild(self); gameState = "playing"; initializeGameplay(); } }); }; self.goBackToMenu = function () { // Fade out difficulty selection tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove difficulty selection and return to menu game.removeChild(self); showMainMenu(); } }); }; // Entrance animation self.alpha = 0; self.scaleX = 0.8; self.scaleY = 0.8; tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeOut }); return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Menu background var menuBg = self.attachAsset('menuBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8 }); // Dark overlay for better text visibility var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.6 }); // Game title var titleText = new Text2("Arsenic", { size: 120, fill: 0xf39c12 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; self.addChild(titleText); // Subtitle var subtitleText = new Text2("Rakibini Yenmek İçin Kartlarını Kullan", { size: 48, fill: 0xecf0f1 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 950; self.addChild(subtitleText); // Play button var playBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1250 }); // Deck button var deckBtn = self.attachAsset('deckButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1500 }); // Wiki button at bottom var wikiBtn = self.attachAsset('wikiButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2000 }); // Wiki icon removed // Wiki button text removed // Medal display var medalCount = storage.gamesWon || 0; var medalText = new Text2("🏆 Kazanılan Oyunlar: " + medalCount, { size: 48, fill: 0xf39c12 }); medalText.anchor.set(0.5, 0.5); medalText.x = 1024; medalText.y = 1650; self.addChild(medalText); // Instructions var instructionText = new Text2("• Kartları sürükleyerek oynat\n• Büyüleri rakip kartlara hedefle\n• Rakibin canını 0'a düşür", { size: 36, fill: 0xbdc3c7 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 1880; self.addChild(instructionText); // Early Access text var earlyAccessText = new Text2("Early Access", { size: 36, fill: 0xe74c3c }); earlyAccessText.anchor.set(0.5, 0.5); earlyAccessText.x = 1024; earlyAccessText.y = 2150; self.addChild(earlyAccessText); // Waldo credit text var waldoText = new Text2("Waldo tarafından yapıldı", { size: 32, fill: 0x3498db }); waldoText.anchor.set(0.5, 0.5); waldoText.x = 1024; waldoText.y = 2220; self.addChild(waldoText); // Credits var creditsText = new Text2("FRVR Tarafından Yapıldı", { size: 28, fill: 0x95a5a6 }); creditsText.anchor.set(0.5, 0.5); creditsText.x = 1024; creditsText.y = 2280; self.addChild(creditsText); // Button hover effect self.playButtonHover = false; self.deckButtonHover = false; self.wikiButtonHover = false; self.down = function (x, y, obj) { // Check if play button was clicked if (x >= 824 && x <= 1224 && y >= 1190 && y <= 1310) { // Button press effect tween(playBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Show training mode selection overlay LK.setTimeout(function () { self.showTrainingModeSelection(); }, 200); } // Check if deck button was clicked else if (x >= 824 && x <= 1224 && y >= 1440 && y <= 1560) { // Button press effect tween(deckBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(deckBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Show deck view after animation LK.setTimeout(function () { self.showDeckView(); }, 200); } // Check if wiki button was clicked else if (x >= 824 && x <= 1224 && y >= 1960 && y <= 2040) { // Button press effect tween(wikiBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(wikiBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Show wiki view after animation LK.setTimeout(function () { self.showWikiView(); }, 200); } // Check if medal was clicked else if (x >= 824 && x <= 1224 && y >= 1610 && y <= 1690) { self.showMedalDetails(); } }; self.move = function (x, y, obj) { var isOverPlayButton = x >= 824 && x <= 1224 && y >= 1190 && y <= 1310; if (isOverPlayButton && !self.playButtonHover) { self.playButtonHover = true; tween(playBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverPlayButton && self.playButtonHover) { self.playButtonHover = false; tween(playBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over deck button var isOverDeckButton = x >= 824 && x <= 1224 && y >= 1440 && y <= 1560; if (isOverDeckButton && !self.deckButtonHover) { self.deckButtonHover = true; tween(deckBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverDeckButton && self.deckButtonHover) { self.deckButtonHover = false; tween(deckBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over wiki button var isOverWikiButton = x >= 824 && x <= 1224 && y >= 1960 && y <= 2040; if (isOverWikiButton && !self.wikiButtonHover) { self.wikiButtonHover = true; tween(wikiBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverWikiButton && self.wikiButtonHover) { self.wikiButtonHover = false; tween(wikiBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } }; self.startGame = function () { // Fade out menu tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove menu and show difficulty selection game.removeChild(self); self.showDifficultySelection(); } }); }; // Entrance animation self.alpha = 0; self.scaleX = 0.8; self.scaleY = 0.8; tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeOut }); // Title pulse 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() { // Restart pulse animation self.titlePulse(); } }); } }); self.showDeckView = function () { // Create and show deck view var deckView = new DeckView(); game.addChild(deckView); }; self.showWikiView = function () { // Create and show wiki view var wikiView = new WikiView(); game.addChild(wikiView); }; self.showDifficultySelection = function () { // Create and show difficulty selection var difficultySelection = new DifficultySelection(); game.addChild(difficultySelection); }; self.titlePulse = function () { 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() { self.titlePulse(); } }); } }); }; self.startTrainingMode = function () { // Fade out menu tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove menu and start training game.removeChild(self); self.showTrainingMode(); } }); }; self.showTrainingMode = function () { // Create and show training mode var trainingMode = new TrainingMode(); game.addChild(trainingMode); }; self.showTrainingModeSelection = function () { // Create overlay for training mode selection var trainingOverlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.8 }); // Training mode title var trainingTitle = new Text2("OYUN MODU SEÇİN", { size: 80, fill: 0xf39c12 }); trainingTitle.anchor.set(0.5, 0.5); trainingTitle.x = 1024; trainingTitle.y = 800; self.addChild(trainingTitle); // Training mode button var trainingBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1100, tint: 0x27ae60 }); var trainingBtnText = new Text2("ANTRENMAN", { size: 48, fill: 0xffffff }); trainingBtnText.anchor.set(0.5, 0.5); trainingBtnText.x = 1024; trainingBtnText.y = 1100; self.addChild(trainingBtnText); // Play game button var playGameBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1350, tint: 0x3498db }); var playGameBtnText = new Text2("OYUNA BAŞLA", { size: 48, fill: 0xffffff }); playGameBtnText.anchor.set(0.5, 0.5); playGameBtnText.x = 1024; playGameBtnText.y = 1350; self.addChild(playGameBtnText); // Back button var backBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1600, scaleX: 0.8, scaleY: 0.8, tint: 0x95a5a6 }); var backBtnText = new Text2("GERİ", { size: 40, fill: 0xffffff }); backBtnText.anchor.set(0.5, 0.5); backBtnText.x = 1024; backBtnText.y = 1600; self.addChild(backBtnText); // Button hover tracking var trainingBtnHover = false; var playGameBtnHover = false; var backBtnHover = false; // Override down handler for training mode selection var originalDown = self.down; self.down = function (x, y, obj) { // Check if training button was clicked if (x >= 824 && x <= 1224 && y >= 1040 && y <= 1160) { // Button press effect tween(trainingBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0x2ecc71 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(trainingBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x27ae60 }, { duration: 100, easing: tween.easeOut }); } }); // Start training mode LK.setTimeout(function () { self.removeTrainingOverlay(); self.startTrainingMode(); }, 200); } // Check if play game button was clicked else if (x >= 824 && x <= 1224 && y >= 1290 && y <= 1410) { // Button press effect tween(playGameBtn, { scaleX: 0.95, scaleY: 0.95, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playGameBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Start game LK.setTimeout(function () { self.removeTrainingOverlay(); self.startGame(); }, 200); } // Check if back button was clicked else if (x >= 904 && x <= 1144 && y >= 1560 && y <= 1640) { // Button press effect tween(backBtn, { scaleX: 0.75, scaleY: 0.75, tint: 0x7f8c8d }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(backBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x95a5a6 }, { duration: 100, easing: tween.easeOut }); } }); // Go back to main menu LK.setTimeout(function () { self.removeTrainingOverlay(); }, 200); } }; // Override move handler for training mode selection var originalMove = self.move; self.move = function (x, y, obj) { // Check if mouse is over training button var isOverTrainingButton = x >= 824 && x <= 1224 && y >= 1040 && y <= 1160; if (isOverTrainingButton && !trainingBtnHover) { trainingBtnHover = true; tween(trainingBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0x2ecc71 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverTrainingButton && trainingBtnHover) { trainingBtnHover = false; tween(trainingBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x27ae60 }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over play game button var isOverPlayGameButton = x >= 824 && x <= 1224 && y >= 1290 && y <= 1410; if (isOverPlayGameButton && !playGameBtnHover) { playGameBtnHover = true; tween(playGameBtn, { scaleX: 1.1, scaleY: 1.1, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverPlayGameButton && playGameBtnHover) { playGameBtnHover = false; tween(playGameBtn, { scaleX: 1.0, scaleY: 1.0, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } // Check if mouse is over back button var isOverBackButton = x >= 904 && x <= 1144 && y >= 1560 && y <= 1640; if (isOverBackButton && !backBtnHover) { backBtnHover = true; tween(backBtn, { scaleX: 0.9, scaleY: 0.9, tint: 0xbdc3c7 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverBackButton && backBtnHover) { backBtnHover = false; tween(backBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x95a5a6 }, { duration: 200, easing: tween.easeOut }); } }; // Store references for cleanup self.trainingModeOverlay = { overlay: trainingOverlay, title: trainingTitle, trainingBtn: trainingBtn, trainingBtnText: trainingBtnText, playGameBtn: playGameBtn, playGameBtnText: playGameBtnText, backBtn: backBtn, backBtnText: backBtnText, originalDown: originalDown, originalMove: originalMove }; }; self.removeTrainingOverlay = function () { if (self.trainingModeOverlay) { // Restore original event handlers self.down = self.trainingModeOverlay.originalDown; self.move = self.trainingModeOverlay.originalMove; // Remove overlay elements self.removeChild(self.trainingModeOverlay.overlay); self.removeChild(self.trainingModeOverlay.title); self.removeChild(self.trainingModeOverlay.trainingBtn); self.removeChild(self.trainingModeOverlay.trainingBtnText); self.removeChild(self.trainingModeOverlay.playGameBtn); self.removeChild(self.trainingModeOverlay.playGameBtnText); self.removeChild(self.trainingModeOverlay.backBtn); self.removeChild(self.trainingModeOverlay.backBtnText); self.trainingModeOverlay = null; } }; self.showMedalDetails = function () { // Get win counts for each difficulty var easyWins = storage.easyWins || 0; var mediumWins = storage.mediumWins || 0; var hardWins = storage.hardWins || 0; // Create medal details view var medalView = new MedalDetailsView(easyWins, mediumWins, hardWins); game.addChild(medalView); }; return self; }); var MedalDetailsView = Container.expand(function (easyWins, mediumWins, hardWins) { var self = Container.call(this); // Dark overlay background var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.9 }); // Title var titleText = new Text2("MADALYA İSTATİSTİKLERİ", { size: 80, fill: 0xf39c12 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; self.addChild(titleText); // Easy difficulty stats var easyText = new Text2("KOLAY: " + easyWins + " galibiyet", { size: 56, fill: 0x27ae60 }); easyText.anchor.set(0.5, 0.5); easyText.x = 1024; easyText.y = 1000; self.addChild(easyText); // Medium difficulty stats var mediumText = new Text2("ORTA: " + mediumWins + " galibiyet", { size: 56, fill: 0xf39c12 }); mediumText.anchor.set(0.5, 0.5); mediumText.x = 1024; mediumText.y = 1200; self.addChild(mediumText); // Hard difficulty stats var hardText = new Text2("ZOR: " + hardWins + " galibiyet", { size: 56, fill: 0xe74c3c }); hardText.anchor.set(0.5, 0.5); hardText.x = 1024; hardText.y = 1400; self.addChild(hardText); // Total wins var totalWins = easyWins + mediumWins + hardWins; var totalText = new Text2("TOPLAM: " + totalWins + " galibiyet", { size: 64, fill: 0xecf0f1 }); totalText.anchor.set(0.5, 0.5); totalText.x = 1024; totalText.y = 1650; self.addChild(totalText); // Close button var closeBtn = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2000, scaleX: 0.8, scaleY: 0.8 }); var closeBtnText = new Text2("KAPAT", { size: 48, fill: 0xffffff }); closeBtnText.anchor.set(0.5, 0.5); closeBtnText.x = 1024; closeBtnText.y = 2000; self.addChild(closeBtnText); self.closeButtonHover = false; self.down = function (x, y, obj) { // Check if close button was clicked if (x >= 824 && x <= 1224 && y >= 1960 && y <= 2040) { // Button press effect tween(closeBtn, { scaleX: 0.75, scaleY: 0.75, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(closeBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Close medal details view after animation LK.setTimeout(function () { self.closeMedalView(); }, 200); } }; self.move = function (x, y, obj) { // Check if mouse is over close button var isOverCloseButton = x >= 824 && x <= 1224 && y >= 1960 && y <= 2040; if (isOverCloseButton && !self.closeButtonHover) { self.closeButtonHover = true; tween(closeBtn, { scaleX: 0.9, scaleY: 0.9, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverCloseButton && self.closeButtonHover) { self.closeButtonHover = false; tween(closeBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } }; self.closeMedalView = function () { // Fade out medal view tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove medal view game.removeChild(self); } }); }; // Entrance animation self.alpha = 0; self.scaleX = 0.8; self.scaleY = 0.8; tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeOut }); return self; }); var OpeningScreen = Container.expand(function () { var self = Container.call(this); // Dark background var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.95 }); // "inspired by Waldo" text var inspiredText = new Text2("inspired by Waldo", { size: 80, fill: 0x3498db }); inspiredText.anchor.set(0.5, 0.5); inspiredText.x = 1024; inspiredText.y = 1366; inspiredText.alpha = 0; self.addChild(inspiredText); // Fade in animation self.alpha = 0; tween(self, { alpha: 1.0 }, { duration: 800, easing: tween.easeOut }); // Fade in the text tween(inspiredText, { alpha: 1.0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Hold for 2 seconds, then fade out LK.setTimeout(function () { tween(self, { alpha: 0 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { // Remove opening screen and show main menu game.removeChild(self); showMainMenu(); } }); }, 2000); } }); // Allow clicking to skip self.down = function (x, y, obj) { // Skip opening and go to main menu tween(self, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { game.removeChild(self); showMainMenu(); } }); }; return self; }); var Player = Container.expand(function (isHuman) { var self = Container.call(this); self.isHuman = isHuman || false; // Set health based on difficulty and player type if (gameDifficulty === "easy") { self.health = isHuman ? 20 : 15; // Player: 20, AI: 15 on easy } else if (gameDifficulty === "medium") { self.health = 20; // Both players have 20 health on medium } else if (gameDifficulty === "hard") { self.health = isHuman ? 20 : 25; // Player: 20, AI: 25 on hard } else { self.health = 20; // Default fallback } self.maxMana = 12; self.currentMana = isHuman ? 3 : 0; self.hand = []; self.battlefield = []; self.deck = []; self.spells = []; // Initialize with Fire Ball spell var fireBallSpell = new Spell({ name: "Fire Ball", cost: 2, damage: 2, target: "enemy", description: "Deals 2 damage to target" }); self.spells.push(fireBallSpell); // Add heal spell var healSpell = new Spell({ name: "Şifa", cost: 2, damage: -2, // Negative damage for healing target: "ally", description: "Heals target for 2 health" }); self.spells.push(healSpell); // Add freeze spell var freezeSpell = new Spell({ name: "Freeze", cost: 2, damage: 0, target: "enemy", description: "Freezes target enemy for 1 turn" }); self.spells.push(freezeSpell); // AI player also gets spells if not human if (!isHuman) { var aiFireBallSpell = new Spell({ name: "Fire Ball", cost: 2, damage: 2, target: "enemy", description: "Deals 2 damage to target" }); self.spells.push(aiFireBallSpell); } // Initialize deck with basic cards var cardTypes = [{ name: "Fire Imp", cost: 3, attack: 2, health: 5, description: "A small fire creature" }, { name: "Water Spirit", cost: 2, attack: 2, health: 4, description: "A defensive water creature" }, { name: "Earth Golem", cost: 3, attack: 1, health: 10, description: "A powerful earth creature" }, { name: "Air Wisp", cost: 1, attack: 1, health: 3, description: "A quick air creature" }, { name: "Lightning Bolt", cost: 2, attack: 1, health: 5, description: "A shocking creature" }, { name: "Lucifer", cost: 4, attack: 3, health: 6, description: "A mystical water spirit with high endurance" }, { name: "Shadow Drake", cost: 3, attack: 3, health: 4, description: "A powerful shadow dragon" }, { name: "Michael Demiurgos", cost: 4, attack: 2, health: 7, description: "An archangel with divine power" }, { name: "Frost Wolf", cost: 3, attack: 2, health: 6, description: "A fierce ice wolf with freezing attacks", passive: "frost" }, { name: "Phoenix", cost: 4, attack: 3, health: 4, description: "A legendary fire bird that can rise from ashes", passive: "rebirth" }, { name: "Void Stalker", cost: 3, attack: 2, health: 5, description: "A shadowy creature from the void with teleportation abilities", passive: "void" }, { name: "Crystal Guardian", cost: 4, attack: 1, health: 8, description: "A mystical crystal protector that shields nearby allies", passive: "crystal_shield" }]; // 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(); // Trigger played passive card.triggerPassive("played", { player: self }); // Check for class synergy activation var cardClass = getCardClass(card.cardData.name); var sameClassCount = 0; for (var i = 0; i < self.battlefield.length; i++) { if (getCardClass(self.battlefield[i].cardData.name) === cardClass) { sameClassCount++; } } // Show synergy effect if 2 or more cards of same class if (sameClassCount >= 2) { // Create synergy activation text var synergyText = new Text2("SINERJI AKTIF: " + cardClass.toUpperCase(), { size: 40, fill: 0xFFD700 }); synergyText.anchor.set(0.5, 0.5); synergyText.x = 1024; synergyText.y = self.isHuman ? 1300 : 500; synergyText.alpha = 0; game.addChild(synergyText); // Animate synergy text tween(synergyText, { alpha: 1.0, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(synergyText, { alpha: 0, y: synergyText.y - 50 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { game.removeChild(synergyText); } }); } }); // Flash all cards of same class for (var i = 0; i < self.battlefield.length; i++) { if (getCardClass(self.battlefield[i].cardData.name) === cardClass) { LK.effects.flashObject(self.battlefield[i], 0xFFD700, 800); } } } 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 () { // Dynamic mana gain based on turn number var displayTurn = Math.floor(turnCounter / 2) + 1; // Calculate actual turn number var manaGain = 1; // Default base mana gain var bonusMana = 0; // Bonus mana every 3rd turn var isThirdTurn = displayTurn % 3 === 0; if (displayTurn > 20) { // After turn 20: 3 mana per turn, 4 mana every 3rd turn manaGain = 3; bonusMana = isThirdTurn ? 1 : 0; // +1 bonus every 3rd turn (total 4) } else if (displayTurn > 10) { // After turn 10: 2 mana per turn, 3 mana every 3rd turn manaGain = 2; bonusMana = isThirdTurn ? 1 : 0; // +1 bonus every 3rd turn (total 3) } else { // First 10 turns: 1 mana per turn, 2 mana every 3rd turn manaGain = 1; bonusMana = isThirdTurn ? 1 : 0; // +1 bonus every 3rd turn (total 2) } var totalManaGain = manaGain + bonusMana; self.currentMana = Math.min(self.maxMana, self.currentMana + totalManaGain); // Max mana is always 12, no need to increment // Reset battlefield cards and trigger turn start passives for (var i = 0; i < self.battlefield.length; i++) { self.battlefield[i].resetForNewTurn(); // Tank synergy now provides static health bonus instead of regeneration self.battlefield[i].triggerPassive("turn_start", { player: self }); // Handle stealth countdown if (self.battlefield[i].stealthTurns > 0) { self.battlefield[i].stealthTurns--; if (self.battlefield[i].stealthTurns <= 0) { self.battlefield[i].alpha = 1.0; // Return to normal visibility } } } // 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: 2, target: "enemy", // "enemy", "ally", "self" description: "Deals 2 damage to target" }; self.isUsable = false; // Create spell graphics var spellBg = self.attachAsset('spellSlot', { anchorX: 0.5, anchorY: 0.5 }); // Choose appropriate spell icon based on spell name var spellAssetName = 'fireballSpell'; // default if (self.spellData.name === "Şifa") { spellAssetName = 'healSpell'; } else if (self.spellData.name === "Freeze") { spellAssetName = 'freezeSpell'; } var spellIcon = self.attachAsset(spellAssetName, { 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; // Play appropriate sound based on spell type if (self.spellData.name === "Şifa") { LK.getSound('healSound').play(); } else { 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 projectileAsset = 'fireballSpell'; // default if (self.spellData.name === "Şifa") { projectileAsset = 'healSpell'; } else if (self.spellData.name === "Freeze") { projectileAsset = 'manaOrb'; // Use mana orb for snow effect } var projectile = game.addChild(LK.getAsset(projectileAsset, { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, tint: self.spellData.name === "Freeze" ? 0x87CEEB : 0xFFFFFF // Light blue tint for freeze })); var targetX = target ? target.x : 1024 + (Math.random() - 0.5) * 200; var targetY = target ? target.y : aiPlayer.battlefield.length > 0 ? 650 : 300; // Create snow particle trail for freeze spell if (self.spellData.name === "Freeze") { for (var snowFlake = 0; snowFlake < 6; snowFlake++) { var snow = game.addChild(LK.getAsset('manaOrb', { anchorX: 0.5, anchorY: 0.5, x: self.x + (Math.random() - 0.5) * 100, y: self.y + (Math.random() - 0.5) * 100, scaleX: 0.2, scaleY: 0.2, alpha: 0.8, tint: 0xFFFFFF // White snow })); // Animate snow particles following the projectile tween(snow, { x: targetX + (Math.random() - 0.5) * 120, y: targetY + (Math.random() - 0.5) * 120, scaleX: 0.4, scaleY: 0.4, alpha: 0, rotation: Math.PI * (Math.random() - 0.5) }, { duration: 500 + snowFlake * 100, easing: tween.easeOut, onFinish: function onFinish() { if (game.children.includes(snow)) { game.removeChild(snow); } } }); } } // 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 damage, healing, and freeze spells if (target && target.takeDamage && target.isOnBattlefield) { if (self.spellData.name === "Freeze") { // Freeze spell target.frozenTurns = 3; // Play freeze sound effect LK.getSound('freezeSound').play(); // Create ice crystal effects around the target for (var crystal = 0; crystal < 8; crystal++) { var iceEffect = game.addChild(LK.getAsset('manaOrb', { anchorX: 0.5, anchorY: 0.5, x: target.x + Math.cos(crystal * Math.PI / 4) * 80, y: target.y + Math.sin(crystal * Math.PI / 4) * 80, scaleX: 0.4, scaleY: 0.4, alpha: 0.9, tint: 0x87CEEB })); // Animate ice crystals converging to target tween(iceEffect, { x: target.x, y: target.y, scaleX: 0.1, scaleY: 0.1, alpha: 0 }, { duration: 600 + crystal * 50, easing: tween.easeIn, onFinish: function onFinish() { if (game.children.includes(iceEffect)) { game.removeChild(iceEffect); } } }); } // Create freeze burst effect at target var freezeBurst = game.addChild(LK.getAsset('manaOrb', { anchorX: 0.5, anchorY: 0.5, x: target.x, y: target.y, scaleX: 0.5, scaleY: 0.5, alpha: 1.0, tint: 0x00BFFF })); // Animate freeze burst expanding and fading tween(freezeBurst, { scaleX: 3.0, scaleY: 3.0, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(freezeBurst); } }); // Apply visual freeze effect to target with blue tint target.alpha = 0.7; // Slightly transparent tween(target, { tint: 0x87CEEB }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Pulsing freeze effect var _freezePulse = function freezePulse() { if (target.frozenTurns > 0) { tween(target, { alpha: 0.5, tint: 0x00BFFF }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(target, { alpha: 0.7, tint: 0x87CEEB }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { if (target.frozenTurns > 0) { _freezePulse(); } } }); } }); } }; _freezePulse(); } }); // Create freeze visual effect text var freezeText = new Text2("DONDU!", { size: 45, fill: 0x00ffff }); freezeText.anchor.set(0.5, 0.5); freezeText.x = target.x + (Math.random() - 0.5) * 60; freezeText.y = target.y - 50; freezeText.alpha = 1.0; game.addChild(freezeText); // Animate freeze text with ice effect tween(freezeText, { y: freezeText.y - 100, alpha: 0, scaleX: 2.0, scaleY: 2.0, rotation: Math.PI * 0.1 }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(freezeText); } }); // Screen flash with icy blue color LK.effects.flashScreen(0x00BFFF, 400); } else 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; }); var TrainingMode = Container.expand(function () { var self = Container.call(this); // Training mode state var currentStep = 0; var maxSteps = 10; var tutorialCards = []; var tutorialSpells = []; var tutorialPlayer = null; var tutorialAI = null; var highlightOverlay = null; var instructionText = null; var skipButton = null; var nextButton = null; var isWaitingForAction = false; // Dark overlay background var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.7 }); // Title var titleText = new Text2("ANTRENMAN MODU", { size: 80, fill: 0x27ae60 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 200; self.addChild(titleText); // Progress indicator var progressText = new Text2("Adım 1 / " + maxSteps, { size: 48, fill: 0xf39c12 }); progressText.anchor.set(0.5, 0.5); progressText.x = 1024; progressText.y = 300; self.addChild(progressText); // Instruction text instructionText = new Text2("Antrenman moduna hoş geldiniz!", { size: 44, fill: 0xecf0f1 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 1366; self.addChild(instructionText); // Skip button skipButton = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 150, scaleX: 0.6, scaleY: 0.6, tint: 0x95a5a6 }); var skipBtnText = new Text2("ATLA", { size: 32, fill: 0xffffff }); skipBtnText.anchor.set(0.5, 0.5); skipBtnText.x = 200; skipBtnText.y = 150; self.addChild(skipBtnText); // Next button nextButton = self.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2400, scaleX: 0.8, scaleY: 0.8, tint: 0x27ae60 }); var nextBtnText = new Text2("DEVAM", { size: 40, fill: 0xffffff }); nextBtnText.anchor.set(0.5, 0.5); nextBtnText.x = 1024; nextBtnText.y = 2400; self.addChild(nextBtnText); // Initialize tutorial self.initializeTutorial = function () { // Create simplified tutorial player tutorialPlayer = new Player(true); tutorialPlayer.health = 20; tutorialPlayer.currentMana = 5; tutorialPlayer.maxMana = 12; // Create simplified tutorial AI tutorialAI = new Player(false); tutorialAI.health = 15; tutorialAI.currentMana = 3; tutorialAI.maxMana = 12; // Create tutorial cards var fireImp = new Card({ name: "Fire Imp", cost: 3, attack: 2, health: 5, description: "Eğitim için basit bir ateş yaratığı", passive: "burn" }); var waterSpirit = new Card({ name: "Water Spirit", cost: 2, attack: 2, health: 4, description: "Eğitim için basit bir su ruhu", passive: "heal" }); tutorialCards = [fireImp, waterSpirit]; tutorialPlayer.hand = tutorialCards.slice(); // Create tutorial spells var fireBall = new Spell({ name: "Fire Ball", cost: 2, damage: 2, target: "enemy", description: "Eğitim için basit bir ateş büyüsü" }); tutorialSpells = [fireBall]; tutorialPlayer.spells = tutorialSpells.slice(); // Create end turn button for training mode var endTurnBtn = self.attachAsset('endTurnButton', { anchorX: 0.5, anchorY: 0.5, x: 1800, y: 1950 }); var endTurnText = new Text2("TURU GEÇER", { size: 28, fill: 0x2C3E50 }); endTurnText.anchor.set(0.5, 0.5); endTurnText.x = 1800; endTurnText.y = 1950; self.addChild(endTurnText); // Store references for cleanup self.endTurnBtn = endTurnBtn; self.endTurnText = endTurnText; // Start first step self.showStep(0); }; self.showStep = function (step) { currentStep = step; progressText.setText("Adım " + (step + 1) + " / " + maxSteps); isWaitingForAction = false; // Clear previous highlights self.clearHighlights(); switch (step) { case 0: instructionText.setText("Hoş geldiniz! Bu oyunun temel kurallarını öğrenelim."); break; case 1: instructionText.setText("Bu ekranın alt kısmında elinizde bulunan kartlar vardır."); self.highlightArea(0, 2200, 2048, 532); break; case 2: instructionText.setText("Kartların üzerindeki mor sayı MANA maliyetini gösterir."); self.highlightCard(tutorialCards[0]); break; case 3: instructionText.setText("Kırmızı sayı SALDIRI gücünü, yeşil sayı CAN miktarını gösterir."); self.highlightCard(tutorialCards[0]); break; case 4: instructionText.setText("Kartları oyun alanına sürükleyerek oynayabilirsiniz."); self.showPlayArea(); isWaitingForAction = true; break; case 5: instructionText.setText("Sol taraftaki mor slotlar büyülerinizi gösterir."); self.highlightArea(50, 2000, 200, 400); break; case 6: instructionText.setText("Büyüleri düşman kartlarına sürükleyerek kullanabilirsiniz."); break; case 7: instructionText.setText("Aynı sınıftan 2 kart oynadığınızda sinerji bonusu alırsınız."); break; case 8: instructionText.setText("Sağ alttaki 'End Turn' butonu ile turu geçebilirsiniz."); self.highlightArea(1700, 1910, 200, 80); break; case 9: instructionText.setText("Tebrikler! Artık oyuna hazırsınız. Ana menüye dönelim."); nextBtnText.setText("TAMAMLA"); break; } // Show/hide next button based on step if (step < maxSteps - 1) { nextButton.alpha = isWaitingForAction ? 0.5 : 1.0; } else { nextButton.alpha = 1.0; } }; self.highlightArea = function (x, y, width, height) { self.clearHighlights(); highlightOverlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: x, y: y, alpha: 0.3, tint: 0xFFD700 }); highlightOverlay.width = width; highlightOverlay.height = height; }; self.highlightCard = function (card) { if (card && game.children.includes(card)) { LK.effects.flashObject(card, 0xFFD700, 2000); } }; self.showPlayArea = function () { // Show lane areas self.highlightArea(380, 700, 1288, 650); }; self.clearHighlights = function () { if (highlightOverlay) { self.removeChild(highlightOverlay); highlightOverlay = null; } }; self.down = function (x, y, obj) { // Check if skip button was clicked if (x >= 140 && x <= 260 && y >= 120 && y <= 180) { self.completeTutorial(); return; } // Check if next button was clicked if (x >= 824 && x <= 1224 && y >= 2360 && y <= 2440) { if (currentStep < maxSteps - 1) { self.showStep(currentStep + 1); } else { self.completeTutorial(); } return; } // Check if end turn button was clicked if (x >= 1700 && x <= 1900 && y >= 1910 && y <= 1990) { // Show tutorial message about end turn instructionText.setText("Turu geçtiniz! Bu butonu kullanarak rakibin sırasına geçebilirsiniz."); // Advance to next step if this was part of tutorial if (currentStep < maxSteps - 1) { LK.setTimeout(function () { self.showStep(currentStep + 1); }, 1500); } return; } // Handle tutorial interactions if (isWaitingForAction && currentStep === 4) { // Check if user tried to drag a card to play area for (var i = 0; i < tutorialCards.length; i++) { var card = tutorialCards[i]; if (x >= card.x - 90 && x <= card.x + 90 && y >= card.y - 125 && y <= card.y + 125) { instructionText.setText("Harika! Kartı oyun alanına sürüklemeyi deneyin."); isWaitingForAction = false; nextButton.alpha = 1.0; return; } } } }; self.completeTutorial = function () { // Mark tutorial as completed storage.tutorialCompleted = true; // Fade out training mode tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove training mode and return to menu game.removeChild(self); showMainMenu(); } }); }; // Initialize tutorial on creation self.initializeTutorial(); // Entrance animation self.alpha = 0; self.scaleX = 0.8; self.scaleY = 0.8; tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeOut }); return self; }); var WikiView = Container.expand(function () { var self = Container.call(this); // Dark overlay background var overlay = self.attachAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.9 }); // Title var titleText = new Text2("OYUN REHBERİ", { size: 80, fill: 0xf39c12 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 200; self.addChild(titleText); // Game rules section var rulesTitle = new Text2("OYUN KURALLARI", { size: 60, fill: 0x3498db }); rulesTitle.anchor.set(0.5, 0.5); rulesTitle.x = 1024; rulesTitle.y = 350; self.addChild(rulesTitle); // Rules text var rulesText = new Text2("• Her oyuncu 3 lane'de kart oynayabilir\n• Kartları sürükleyerek lane'lere yerleştirin\n• Büyüleri düşman/müttefik kartlara hedefleyin\n• Mana her tur otomatik olarak yenilenir\n• Rakibin canını 0'a düşürün\n• Karakterlerin üstündeki yeşil sayı CAN, kırmızı HASAR, mor MANA", { size: 36, fill: 0xbdc3c7 }); rulesText.anchor.set(0.5, 0.5); rulesText.x = 1024; rulesText.y = 550; self.addChild(rulesText); // Class synergy section var synergyTitle = new Text2("SINIF SİNERJİLERİ", { size: 60, fill: 0x9b59b6 }); synergyTitle.anchor.set(0.5, 0.5); synergyTitle.x = 1024; synergyTitle.y = 800; self.addChild(synergyTitle); // Synergy explanation var synergyText = new Text2("2 veya daha fazla aynı sınıf kartı ile sinerji bonusları:\n\n• TANK: +1 Can (Her Tank kartı için)\n• MAGE: %25 şans ile 2x hasar\n• ROGUE: %20 Dodge şansı\n• WARRIOR: Air Wisp %60 kaçınma", { size: 36, fill: 0xbdc3c7 }); synergyText.anchor.set(0.5, 0.5); synergyText.x = 1024; synergyText.y = 1100; self.addChild(synergyText); // Spell section var spellTitle = new Text2("BÜYÜLER", { size: 60, fill: 0xe74c3c }); spellTitle.anchor.set(0.5, 0.5); spellTitle.x = 1024; spellTitle.y = 1400; self.addChild(spellTitle); // Spell explanation var spellText = new Text2("• Fire Ball: 2 hasar (Düşman kartlara)\n• Şifa: 2 iyileştirme (Müttefik kartlara)\n• Freeze: 2 mana, 3 tur dondurma (Düşman kartlara)", { size: 36, fill: 0xbdc3c7 }); spellText.anchor.set(0.5, 0.5); spellText.x = 1024; spellText.y = 1600; self.addChild(spellText); // Tips section var tipsTitle = new Text2("İPUÇLARI", { size: 60, fill: 0x27ae60 }); tipsTitle.anchor.set(0.5, 0.5); tipsTitle.x = 1024; tipsTitle.y = 1850; self.addChild(tipsTitle); // Tips text var tipsText = new Text2("• Sinerji bonusları için aynı sınıf kartları kullanın\n• Pasif yetenekleri stratejinize dahil edin\n• Büyüleri doğru zamanda kullanın\n• Kartları desteye geri döndürmek için aşağı sürükleyin", { size: 36, fill: 0xbdc3c7 }); tipsText.anchor.set(0.5, 0.5); tipsText.x = 1024; tipsText.y = 2050; self.addChild(tipsText); // Add wiki icon at top var wikiIcon = self.attachAsset('wikiIcon', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 120, scaleX: 1.5, scaleY: 1.5 }); // Add game rules icon var gameRulesIcon = self.attachAsset('gameRulesIcon', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 350, scaleX: 1.2, scaleY: 1.2 }); // Add synergy icon var synergyIcon = self.attachAsset('synergyIcon', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 800, scaleX: 1.2, scaleY: 1.2 }); // Add spell icon var spellIconAsset = self.attachAsset('spellIcon', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 1400, scaleX: 1.2, scaleY: 1.2 }); // Add tips icon var tipsIcon = self.attachAsset('tipsIcon', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 1850, scaleX: 1.2, scaleY: 1.2 }); // Close button var closeBtn = self.attachAsset('wikiButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2450, scaleX: 0.8, scaleY: 0.8 }); var closeBtnText = new Text2("KAPAT", { size: 48, fill: 0xffffff }); closeBtnText.anchor.set(0.5, 0.5); closeBtnText.x = 1024; closeBtnText.y = 2450; self.addChild(closeBtnText); self.closeButtonHover = false; self.down = function (x, y, obj) { // Check if close button was clicked if (x >= 824 && x <= 1224 && y >= 2410 && y <= 2490) { // Button press effect tween(closeBtn, { scaleX: 0.75, scaleY: 0.75, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(closeBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Close wiki view after animation LK.setTimeout(function () { self.closeWikiView(); }, 200); } }; self.move = function (x, y, obj) { // Check if mouse is over close button var isOverCloseButton = x >= 824 && x <= 1224 && y >= 2410 && y <= 2490; if (isOverCloseButton && !self.closeButtonHover) { self.closeButtonHover = true; tween(closeBtn, { scaleX: 0.9, scaleY: 0.9, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverCloseButton && self.closeButtonHover) { self.closeButtonHover = false; tween(closeBtn, { scaleX: 0.8, scaleY: 0.8, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } }; self.closeWikiView = function () { // Fade out wiki view tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Remove wiki view and return to menu game.removeChild(self); } }); }; // Entrance animation self.alpha = 0; self.scaleX = 0.8; self.scaleY = 0.8; tween(self, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeOut }); 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 gameState = "menu"; // "menu", "playing", "gameOver" var gameDifficulty = "easy"; // "easy", "medium", "hard" - will be set by difficulty selection var currentPlayer = 0; // 0 = human, 1 = AI var gamePhase = "playing"; // "playing", "gameOver" var mainMenu = null; var selectedCard = null; var draggedCard = null; var turnCounter = 0; // Track total turns taken var combatPhase = false; // Track if we're in combat phase var cardsLockedIn = false; // Track if cards are locked in for the turn // Create players var humanPlayer = new Player(true); var aiPlayer = new Player(false); // Set AI player's starting mana to 2 aiPlayer.currentMana = 2; 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: 20", { size: 48, fill: 0xECF0F1 }); playerHealthText.anchor.set(0, 0.5); playerHealthText.x = 50; playerHealthText.y = 1950; game.addChild(playerHealthText); // Synergy indicator display var synergyDisplays = { Tank: null, Mage: null, Rogue: null, Warrior: null }; var synergyIcons = { Tank: null, Mage: null, Rogue: null, Warrior: null }; // Store class feature info var classFeatures = { Tank: { name: "TANK", feature: "Savunma Odaklı", synergy: "+1 Can (Her Tank kartı için)", description: "Tank kartları yüksek can değerleriyle düşman saldırılarını absorbe eder. 2 veya daha fazla Tank kartı aynı anda savaş alanında olduğunda, her Tank kartı sinerji bonusu olarak +1 can kazanır." }, Mage: { name: "MAGE", feature: "Öfkelenme", synergy: "%25 şans ile 2x hasar (Her Mage kartı için)", description: "Mage kartları öfkelenme yetisi ile saldırır. 2 veya daha fazla Mage kartı aynı anda savaş alanında olduğunda, her Mage kartı sinerji bonusu olarak %25 şans ile 2x hasar verir." }, Rogue: { name: "ROGUE", feature: "Hızlı ve Çevik", synergy: "%20 Dodge şansı (Her Rogue kartı için)", description: "Rogue kartları hız ve çeviklikle saldırılardan kaçınabilir. 2 veya daha fazla Rogue kartı aynı anda savaş alanında olduğunda, her Rogue kartı sinerji bonusu olarak %20 şans ile saldırıları dodge atar." }, Warrior: { name: "WARRIOR", feature: "Savaş Ustası", synergy: "Air Wisp %60 kaçınma şansı", description: "Warrior kartları güçlü saldırılarıyla bilinir. 2 veya daha fazla Warrior kartı aynı anda savaş alanında olduğunda, Air Wisp kartının kaçınma şansı %25'ten %60'a çıkar." }, Vampire: { name: "VAMPIRE", feature: "Vampirizm", synergy: "Verilen hasar kadar can yenileme (Her Vampire kartı için)", description: "Vampire kartları verdiği hasar kadar can kazanır. 2 veya daha fazla Vampire kartı aynı anda savaş alanında olduğunda, her Vampire kartı hasar verdiğinde verdiği hasar kadar can yeniler." } }; // Class feature display variables var classFeatureDisplay = null; var isShowingClassFeature = false; // Create synergy displays var synergyStartY = 800; var synergySpacing = 200; var classNames = ["Tank", "Mage", "Rogue", "Warrior"]; var classAssets = ["tankClass", "mageClass", "rogueClass", "warriorClass"]; for (var i = 0; i < classNames.length; i++) { var className = classNames[i]; var assetName = classAssets[i]; var yPos = synergyStartY + i * synergySpacing; // Create class icon var icon = game.addChild(LK.getAsset(assetName, { anchorX: 0.5, anchorY: 0.5, x: 100, y: yPos, scaleX: 1.5, scaleY: 1.5, alpha: 0.3 })); synergyIcons[className] = icon; // Create synergy text var synergyText = new Text2("", { size: 36, fill: 0x95a5a6 }); synergyText.anchor.set(0, 0.5); synergyText.x = 150; synergyText.y = yPos; synergyText.alpha = 0.3; game.addChild(synergyText); synergyDisplays[className] = synergyText; } var opponentHealthText = new Text2("Enemy: 15", { size: 48, fill: 0xECF0F1 }); opponentHealthText.anchor.set(0.5, 0.5); opponentHealthText.x = 1024; opponentHealthText.y = 150; game.addChild(opponentHealthText); var manaText = new Text2("Mana: 3/12", { 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/12", { size: 36, fill: 0x9B59B6 }); aiManaText.anchor.set(0.5, 0.5); aiManaText.x = 1024; aiManaText.y = 200; game.addChild(aiManaText); var nextTurnManaText = new Text2("Next Turn: +1 Mana", { size: 36, fill: 0x9B59B6 }); nextTurnManaText.anchor.set(1, 0.5); nextTurnManaText.x = 1950; nextTurnManaText.y = 2100; game.addChild(nextTurnManaText); 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); // Turn counter display on right middle side var turnCounterText = new Text2("Turn: 1", { size: 38, fill: 0xECF0F1 }); turnCounterText.anchor.set(0.5, 0.5); turnCounterText.x = 1800; turnCounterText.y = 1366; game.addChild(turnCounterText); // 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); // Main menu button var mainMenuBtn = game.addChild(LK.getAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 1600, y: 150, scaleX: 0.6, scaleY: 0.6 })); var mainMenuBtnText = new Text2("ANA MENÜ", { size: 20, fill: 0xffffff }); mainMenuBtnText.anchor.set(0.5, 0.5); mainMenuBtnText.x = 1600; mainMenuBtnText.y = 150; game.addChild(mainMenuBtnText); 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"; } // Update next turn mana display var nextDisplayTurn = Math.floor((turnCounter + 1) / 2) + 1; var nextManaGain = 1; var nextBonusMana = 0; var nextIsThirdTurn = nextDisplayTurn % 3 === 0; if (nextDisplayTurn > 20) { // After turn 20: 3 mana per turn, 4 mana every 3rd turn nextManaGain = 3; nextBonusMana = nextIsThirdTurn ? 1 : 0; } else if (nextDisplayTurn > 10) { // After turn 10: 2 mana per turn, 3 mana every 3rd turn nextManaGain = 2; nextBonusMana = nextIsThirdTurn ? 1 : 0; } else { // First 10 turns: 1 mana per turn, 2 mana every 3rd turn nextManaGain = 1; nextBonusMana = nextIsThirdTurn ? 1 : 0; } var totalNextManaGain = nextManaGain + nextBonusMana; nextTurnManaText.setText("Gelecek Tur: +" + totalNextManaGain + " Mana"); // Update turn counter display var displayTurn = Math.floor(turnCounter / 2) + 1; turnCounterText.setText("Turn: " + displayTurn); } 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 getCardClass(cardName) { // Determine card class based on name if (cardName === "Earth Golem" || cardName === "Lightning Bolt") { return "Tank"; } else if (cardName === "Fire Imp" || cardName === "Water Spirit") { return "Mage"; } else if (cardName === "Shadow Drake" || cardName === "Michael Demiurgos") { return "Rogue"; } else if (cardName === "Lucifer" || cardName === "Air Wisp" || cardName === "Frost Wolf") { return "Warrior"; } else if (cardName === "Phoenix") { return "Mage"; } else if (cardName === "Void Stalker") { return "Rogue"; } else if (cardName === "Crystal Guardian") { return "Tank"; } else if (cardName === "Vampire Lord" || cardName === "Blood Drake") { return "Vampire"; } return "None"; } function calculateClassSynergy(player) { // Count cards by class on battlefield var classCounts = { "Tank": 0, "Mage": 0, "Rogue": 0, "Warrior": 0, "Vampire": 0 }; for (var i = 0; i < player.battlefield.length; i++) { var cardClass = getCardClass(player.battlefield[i].cardData.name); if (classCounts[cardClass] !== undefined) { classCounts[cardClass]++; } } // Update synergy display only for human player if (player.isHuman) { for (var className in synergyDisplays) { var count = classCounts[className]; var icon = synergyIcons[className]; var display = synergyDisplays[className]; if (count >= 2) { // Synergy is active icon.alpha = 1.0; icon.tint = 0xFFD700; // Gold color for active display.alpha = 1.0; display.fill = 0xFFD700; // Show synergy bonus text var bonusText = ""; if (className === "Tank") { bonusText = "+" + count + " Can"; } else if (className === "Mage") { bonusText = "%25 2x hasar"; } else if (className === "Rogue") { bonusText = "%20 Dodge şansı"; } else if (className === "Warrior") { bonusText = "Air Wisp %60 kaçınma"; } else if (className === "Vampire") { bonusText = "Vampirizm: Hasar=Can"; } display.setText(className.toUpperCase() + ": " + bonusText); } else if (count === 1) { // One card, not active yet icon.alpha = 0.7; icon.tint = 0xFFFFFF; display.alpha = 0.7; display.fill = 0xbdc3c7; display.setText(className.toUpperCase() + ": 1/2"); } else { // No cards icon.alpha = 0.3; icon.tint = 0xFFFFFF; display.alpha = 0.3; display.fill = 0x95a5a6; display.setText(className.toUpperCase() + ": 0/2"); } } } // Apply synergy bonuses for (var i = 0; i < player.battlefield.length; i++) { var card = player.battlefield[i]; var cardClass = getCardClass(card.cardData.name); var classCount = classCounts[cardClass]; // Reset to base values first card.synergyAttackBonus = 0; card.synergyHealthBonus = 0; card.synergyRage = false; // Reset rage mechanic // Apply synergy bonuses based on class count if (classCount >= 2) { if (cardClass === "Tank") { // Tank synergy: +1 health gain per Tank card card.synergyHealthBonus = classCount; // Tank cards gain health card.synergyHealthRegen = 0; // No regeneration } else if (cardClass === "Mage") { // Mage synergy: 50% chance for 2x damage (rage mechanic) card.synergyRage = true; // Enable rage for Mage cards with synergy } else if (cardClass === "Rogue") { // Rogue synergy: 20% chance to dodge attacks (handled in passive system) // No stat bonuses for Rogue synergy } else if (cardClass === "Warrior") { // Warrior synergy: Air Wisp passive evasion chance increases from 25% to 60% // No stat bonuses for Warrior synergy - handled in passive system } } } } function arrangeBattlefield() { // Calculate synergies for both players calculateClassSynergy(humanPlayer); calculateClassSynergy(aiPlayer); // 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) { // Check if either card has taunt - taunt forces combat var humanDamage = humanCard.cardData.attack + (humanCard.synergyAttackBonus || 0); var aiDamage = aiCard.cardData.attack + (aiCard.synergyAttackBonus || 0); // Check if cards are frozen - frozen cards cannot deal damage if (humanCard.frozenTurns && humanCard.frozenTurns > 0) { humanDamage = 0; // Frozen cards deal no damage } if (aiCard.frozenTurns && aiCard.frozenTurns > 0) { aiDamage = 0; // Frozen cards deal no damage } // Apply Mage rage if applicable (only if not frozen) if (humanCard.synergyRage && Math.random() < 0.25 && humanDamage > 0) { humanDamage *= 2; } if (aiCard.synergyRage && Math.random() < 0.25 && aiDamage > 0) { aiDamage *= 2; } // 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 - check if frozen first if (humanCard.frozenTurns && humanCard.frozenTurns > 0) { // Frozen card cannot attack tower, skip this lane LK.setTimeout(onComplete, 100); } else { // 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 - check if frozen first if (aiCard.frozenTurns && aiCard.frozenTurns > 0) { // Frozen card cannot attack tower, skip this lane LK.setTimeout(onComplete, 100); } else { // 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 but check if card is frozen var actualDamage = 0; if (!card.frozenTurns || card.frozenTurns <= 0) { actualDamage = card.cardData.attack; } // Flash the tower area only if damage will be dealt if (actualDamage > 0) { 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(); // Reset game after showing game over LK.setTimeout(function () { resetGame(); }, 3000); return true; } else if (aiPlayer.health <= 0) { gamePhase = "gameOver"; // Increment medal count when player wins var currentMedals = storage.gamesWon || 0; storage.gamesWon = currentMedals + 1; // Track wins by difficulty if (gameDifficulty === "easy") { var easyWins = storage.easyWins || 0; storage.easyWins = easyWins + 1; } else if (gameDifficulty === "medium") { var mediumWins = storage.mediumWins || 0; storage.mediumWins = mediumWins + 1; } else if (gameDifficulty === "hard") { var hardWins = storage.hardWins || 0; storage.hardWins = hardWins + 1; } LK.showYouWin(); // Reset game after showing you win LK.setTimeout(function () { resetGame(); }, 3000); return true; } return false; } function resetGame() { // Reset game state gameState = "menu"; gamePhase = "playing"; currentPlayer = 0; turnCounter = 0; combatPhase = false; // Remove all cards from display before resetting arrays var allCards = humanPlayer.hand.concat(humanPlayer.battlefield).concat(aiPlayer.hand).concat(aiPlayer.battlefield); for (var i = 0; i < allCards.length; i++) { if (game.children.includes(allCards[i])) { game.removeChild(allCards[i]); } } // Remove all spells from display for (var i = 0; i < humanPlayer.spells.length; i++) { if (game.children.includes(humanPlayer.spells[i])) { game.removeChild(humanPlayer.spells[i]); } } for (var i = 0; i < aiPlayer.spells.length; i++) { if (game.children.includes(aiPlayer.spells[i])) { game.removeChild(aiPlayer.spells[i]); } } // Reset players with difficulty-based health if (gameDifficulty === "easy") { humanPlayer.health = 20; aiPlayer.health = 15; } else if (gameDifficulty === "medium") { humanPlayer.health = 20; aiPlayer.health = 20; } else if (gameDifficulty === "hard") { humanPlayer.health = 20; aiPlayer.health = 25; } else { humanPlayer.health = 20; aiPlayer.health = 20; } // Reset turn counter display turnCounterText.setText("Turn: 1"); humanPlayer.currentMana = 3; humanPlayer.maxMana = 12; humanPlayer.hand = []; humanPlayer.battlefield = []; humanPlayer.deck = []; aiPlayer.currentMana = 0; aiPlayer.maxMana = 12; aiPlayer.hand = []; aiPlayer.battlefield = []; aiPlayer.deck = []; // Initialize deck with basic cards var cardTypes = [{ name: "Fire Imp", cost: 3, attack: 2, health: 5, description: "A small fire creature", passive: "burn" // Burns enemy for 1 damage at end of turn }, { name: "Water Spirit", cost: 2, attack: 2, health: 4, description: "A defensive water creature", passive: "heal" // Heals 1 health at start of turn }, { name: "Earth Golem", cost: 3, attack: 1, health: 10, description: "A powerful earth creature", passive: "taunt" // Forces enemies to attack this card first }, { name: "Air Wisp", cost: 1, attack: 1, health: 3, description: "A quick air creature", passive: "evasion" // 25% chance to dodge attacks }, { name: "Lightning Bolt", cost: 2, attack: 1, health: 5, description: "A shocking creature", passive: "shock" // Deals 3 damage to all enemies when played }, { name: "Lucifer", cost: 4, attack: 3, health: 6, description: "A mystical water spirit with high endurance", passive: "lifesteal" // Already implemented: heals when dealing damage }, { name: "Shadow Drake", cost: 3, attack: 3, health: 4, description: "A powerful shadow dragon", passive: "stealth" }, { name: "Michael Demiurgos", cost: 4, attack: 2, health: 7, description: "An archangel with divine power", passive: "divine_shield" // Ignores first damage taken }, { name: "Frost Wolf", cost: 3, attack: 2, health: 6, description: "A fierce ice wolf with freezing attacks", passive: "frost" // Slows enemy cards when attacking }, { name: "Phoenix", cost: 4, attack: 3, health: 4, description: "A legendary fire bird that can rise from ashes", passive: "rebirth" // Revives once when destroyed }, { name: "Void Stalker", cost: 3, attack: 2, health: 5, description: "A shadowy creature from the void with teleportation abilities", passive: "void" // Teleports to different lane when taking damage }, { name: "Crystal Guardian", cost: 4, attack: 1, health: 8, description: "A mystical crystal protector that shields nearby allies", passive: "crystal_shield" // Reduces damage taken by all friendly cards by 1 }]; // Recreate decks for both players for (var p = 0; p < 2; p++) { var player = p === 0 ? humanPlayer : aiPlayer; for (var i = 0; i < cardTypes.length; i++) { var newCard = new Card(cardTypes[i]); newCard.validateStats(); player.deck.push(newCard); } // Shuffle deck for (var i = player.deck.length - 1; i > 0; i--) { var randomIndex = Math.floor(Math.random() * (i + 1)); var temp = player.deck[i]; player.deck[i] = player.deck[randomIndex]; player.deck[randomIndex] = temp; } } // Clear any remaining display elements selectedCard = null; draggedCard = null; // Show main menu showMainMenu(); } function endTurn() { // Lock in cards for current turn - no more returns to deck allowed cardsLockedIn = true; // 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; // Reset cards locked in flag for new turn cardsLockedIn = false; // New turn system: Each player gets one full turn, then combat // Human starts (currentPlayer 0), then AI (currentPlayer 1), then combat if (turnCounter % 2 === 0) { // After both players have taken a turn, enter combat phase combatPhase = true; turnText.setText("Combat Phase"); turnText.fill = "#e67e22"; // Resolve combat after both players complete their turns LK.setTimeout(function () { resolveCombat(); combatPhase = false; // Start next round with human player currentPlayer = 0; // Always start new round with human player players[currentPlayer].startTurn(); if (!checkGameOver()) { updateUI(); arrangeHand(); arrangeBattlefield(); } }, 1000); } else { // Switch to the other player for their turn players[currentPlayer].startTurn(); if (currentPlayer === 1) { // AI turn LK.setTimeout(function () { performAITurn(); }, 1000); } if (!checkGameOver()) { updateUI(); arrangeHand(); arrangeBattlefield(); } } } function performAITurn() { // Enhanced AI with strategic decision-making and adaptive difficulty console.log("AI Turn - Difficulty:", gameDifficulty, "Health:", aiPlayer.health, "vs", humanPlayer.health); console.log("AI Hand size:", aiPlayer.hand.length, "Battlefield:", aiPlayer.battlefield.length, "Mana:", aiPlayer.currentMana); // Calculate board state and threat assessment var boardState = evaluateBoardState(); var threatLevel = calculateThreatLevel(); var aiStrategy = determineStrategy(boardState, threatLevel); console.log("AI Strategy:", aiStrategy, "Threat Level:", threatLevel); // Always try to play cards first - this is the main issue var playableCards = aiPlayer.hand.filter(function (card) { return aiPlayer.canPlayCard(card); }); console.log("Playable cards:", playableCards.length); // Force AI to play at least one card if possible var cardsPlayed = 0; var maxCardsToPlay = Math.min(3 - aiPlayer.battlefield.length, 2); // Play up to 2 cards per turn while (cardsPlayed < maxCardsToPlay && playableCards.length > 0 && aiPlayer.battlefield.length < 3) { var cardDecision = makeCardDecision(playableCards, boardState, threatLevel, aiStrategy); if (cardDecision.card && cardDecision.lane !== -1) { console.log("AI playing card:", cardDecision.card.cardData.name, "in lane", cardDecision.lane); if (aiPlayer.playCard(cardDecision.card)) { cardDecision.card.laneIndex = cardDecision.lane; cardDecision.card.targetLane = cardDecision.lane; cardsPlayed++; // Remove played card from playable list var cardIndex = playableCards.indexOf(cardDecision.card); if (cardIndex >= 0) { playableCards.splice(cardIndex, 1); } updateUI(); arrangeHand(); arrangeBattlefield(); } else { break; // Failed to play card, stop trying } } else { break; // No valid card decision, stop trying } } // Spell casting after playing cards var usableSpells = aiPlayer.spells.filter(function (spell) { return aiPlayer.canCastSpell(spell); }); if (usableSpells.length > 0) { var spellDecision = makeSpellDecision(usableSpells, boardState, threatLevel); if (spellDecision.spell && spellDecision.target) { console.log("AI casting spell:", spellDecision.spell.spellData.name, "on", spellDecision.target.cardData.name); if (aiPlayer.castSpell(spellDecision.spell, spellDecision.target)) { updateUI(); arrangeHand(); arrangeBattlefield(); } } } // Dynamic turn timing based on complexity and difficulty var turnDelay = calculateTurnDelay(boardState, threatLevel); LK.setTimeout(function () { if (!checkGameOver()) { endTurn(); } }, turnDelay); // AI helper functions for strategic decision making function evaluateBoardState() { var state = { aiCards: aiPlayer.battlefield.length, humanCards: humanPlayer.battlefield.length, aiTotalPower: 0, humanTotalPower: 0, aiSynergies: calculateAISynergies(), humanSynergies: calculateHumanSynergies(), availableLanes: getAvailableLanes(), manaEfficiency: aiPlayer.currentMana / aiPlayer.maxMana }; // Calculate total power on board for (var i = 0; i < aiPlayer.battlefield.length; i++) { var card = aiPlayer.battlefield[i]; state.aiTotalPower += card.cardData.attack + card.currentHealth; } for (var i = 0; i < humanPlayer.battlefield.length; i++) { var card = humanPlayer.battlefield[i]; state.humanTotalPower += card.cardData.attack + card.currentHealth; } return state; } function calculateThreatLevel() { var threat = 0; // Player health threat if (humanPlayer.health <= 15) threat += 30;else if (humanPlayer.health <= 25) threat += 15; // AI health threat if (aiPlayer.health <= 20) threat += 40;else if (aiPlayer.health <= 35) threat += 20; // Board control threat var powerDifference = 0; for (var i = 0; i < humanPlayer.battlefield.length; i++) { powerDifference += humanPlayer.battlefield[i].cardData.attack; } for (var i = 0; i < aiPlayer.battlefield.length; i++) { powerDifference -= aiPlayer.battlefield[i].cardData.attack; } if (powerDifference > 5) threat += 25;else if (powerDifference > 0) threat += 10; return Math.min(100, threat); } function determineStrategy(boardState, threatLevel) { if (threatLevel > 60) return "defensive"; if (aiPlayer.health > humanPlayer.health * 1.5) return "aggressive"; if (boardState.manaEfficiency > 0.8) return "tempo"; if (boardState.aiSynergies.count >= 2) return "synergy"; return "balanced"; } function makeSpellDecision(usableSpells, boardState, threatLevel) { var bestSpell = null; var bestTarget = null; var bestValue = -1; for (var s = 0; s < usableSpells.length; s++) { var spell = usableSpells[s]; var targets = []; if (spell.spellData.target === "enemy") { targets = humanPlayer.battlefield.slice(); } else if (spell.spellData.target === "ally") { targets = aiPlayer.battlefield.slice(); } for (var t = 0; t < targets.length; t++) { var target = targets[t]; var value = evaluateSpellValue(spell, target, boardState, threatLevel); if (value > bestValue) { bestValue = value; bestSpell = spell; bestTarget = target; } } } // Difficulty-based casting probability - made more aggressive var castProbability = 0.7; // Increased base probability if (gameDifficulty === "medium") castProbability = 0.8;else if (gameDifficulty === "hard") castProbability = 0.95;else if (gameDifficulty === "easy") castProbability = 0.6; // Increase probability based on threat level castProbability += threatLevel * 0.005; // Always cast if spell can kill an enemy or has very high value if (bestValue > 80) castProbability = 1.0; if (Math.random() < castProbability && bestSpell && bestTarget) { return { spell: bestSpell, target: bestTarget }; } return { spell: null, target: null }; } function evaluateSpellValue(spell, target, boardState, threatLevel) { var value = 0; if (spell.spellData.target === "enemy") { // Damage spells on enemies if (spell.spellData.name === "Fire Ball") { // Prioritize killing high-value targets if (target.currentHealth <= spell.spellData.damage) { value = 100 + target.cardData.cost * 15 + target.cardData.attack * 10; // Extra value for removing synergy threats var targetClass = getCardClass(target.cardData.name); var humanClassCount = countClassCards(humanPlayer.battlefield, targetClass); if (humanClassCount >= 2) value += 50; // Extra value for removing taunt if (target.cardData.passive === "taunt") value += 30; } else { value = spell.spellData.damage * 5; } } else if (spell.spellData.name === "Freeze") { // Freeze high-attack threats var attackValue = target.cardData.attack + (target.synergyAttackBonus || 0); value = attackValue * 15; // Extra value for freezing synergy engines var targetClass = getCardClass(target.cardData.name); var humanClassCount = countClassCards(humanPlayer.battlefield, targetClass); if (humanClassCount >= 2) value += 40; } } else if (spell.spellData.target === "ally") { // Heal spells on allies if (spell.spellData.name === "Şifa") { var missingHealth = target.maxHealth - target.currentHealth; if (missingHealth > 0) { value = Math.min(missingHealth, Math.abs(spell.spellData.damage)) * 8; value += target.cardData.cost * 5; // Value keeping expensive cards alive // Extra value for healing synergy cards var targetClass = getCardClass(target.cardData.name); var aiClassCount = countClassCards(aiPlayer.battlefield, targetClass); if (aiClassCount >= 2) value += 25; } } } // Adjust value based on difficulty if (gameDifficulty === "easy") value *= 0.7;else if (gameDifficulty === "hard") value *= 1.3; return value; } function makeCardDecision(playableCards, boardState, threatLevel, strategy) { if (playableCards.length === 0) { return { card: null, lane: -1 }; } var bestCard = null; var bestLane = -1; var bestValue = -999; //{DE} // Start with very low value var availableLanes = getAvailableLanes(); // If no lanes available, return null if (availableLanes.length === 0) { return { card: null, lane: -1 }; } for (var c = 0; c < playableCards.length; c++) { var card = playableCards[c]; for (var l = 0; l < availableLanes.length; l++) { var lane = availableLanes[l]; var value = evaluateCardPlacement(card, lane, boardState, threatLevel, strategy); if (value > bestValue) { bestValue = value; bestCard = card; bestLane = lane; } } } // Fallback: if no good placement found, pick first available card and lane if (bestCard === null && playableCards.length > 0 && availableLanes.length > 0) { bestCard = playableCards[0]; bestLane = availableLanes[0]; console.log("AI fallback: playing", bestCard.cardData.name, "in lane", bestLane); } return { card: bestCard, lane: bestLane }; } function evaluateCardPlacement(card, lane, boardState, threatLevel, strategy) { var value = 50; // Start with base positive value to ensure AI plays cards // Base card value var costEfficiency = card.cardData.cost > 0 ? (card.cardData.attack + card.cardData.health / 2) / card.cardData.cost : card.cardData.attack + card.cardData.health; value += costEfficiency * 15; // Synergy bonus evaluation var cardClass = getCardClass(card.cardData.name); var currentClassCount = countClassCards(aiPlayer.battlefield, cardClass); if (currentClassCount >= 1) { // Will create or strengthen synergy var synergyValue = calculateSynergyValue(cardClass, currentClassCount + 1); value += synergyValue; } // Lane-specific evaluation var humanCardInLane = findHumanCardInLane(lane); if (humanCardInLane) { // Can we win this matchup? var ourAttack = card.cardData.attack; var theirHealth = humanCardInLane.currentHealth; var ourHealth = card.cardData.health; var theirAttack = humanCardInLane.cardData.attack; if (ourAttack >= theirHealth && theirAttack < ourHealth) { value += 60; // Great trade } else if (ourAttack >= theirHealth) { value += 30; // We kill them but might die } else if (theirAttack < ourHealth) { value += 20; // We survive their attack } else { value -= 20; // Bad matchup } // Avoid Lucifer conflicts if (card.cardData.name === "Lucifer" && humanCardInLane.cardData.name === "Lucifer") { value -= 200; } } else { // Empty lane - good for pressure value += 25; if (lane === 1) value += 10; // Center lane preference } // Strategy adjustments if (strategy === "aggressive") { value += card.cardData.attack * 10; } else if (strategy === "defensive") { value += card.cardData.health * 8; if (card.cardData.passive === "taunt") value += 40; } else if (strategy === "synergy") { if (currentClassCount >= 1) value += 50; } // Passive ability values if (card.cardData.passive) { value += evaluatePassiveValue(card.cardData.passive, boardState, threatLevel); } // Difficulty scaling if (gameDifficulty === "easy") { value *= 0.6 + Math.random() * 0.4; // Add randomness for easy } else if (gameDifficulty === "hard") { value *= 1.2; // Better evaluation for hard } return value; } function calculateSynergyValue(cardClass, newCount) { if (newCount < 2) return 0; var value = 0; switch (cardClass) { case "Tank": value = newCount * 25; break; // Health regen case "Mage": value = newCount * 35; break; // Rage damage case "Rogue": value = newCount * 30; break; // Attack/health boost case "Warrior": value = newCount * 40; break; // Attack boost case "Vampire": value = newCount * 30; break; // Lifesteal } return value; } function evaluatePassiveValue(passive, boardState, threatLevel) { switch (passive) { case "burn": return 25 + humanPlayer.battlefield.length * 10; case "heal": return 20; case "taunt": return threatLevel > 40 ? 35 : 15; case "evasion": return 20; case "shock": return humanPlayer.battlefield.length * 15; case "lifesteal": return 25; case "stealth": return 15; case "divine_shield": return 30; default: return 0; } } function calculateAISynergies() { var synergies = { count: 0, types: [] }; var classCounts = {}; for (var i = 0; i < aiPlayer.battlefield.length; i++) { var cardClass = getCardClass(aiPlayer.battlefield[i].cardData.name); classCounts[cardClass] = (classCounts[cardClass] || 0) + 1; } for (var cardClass in classCounts) { if (classCounts[cardClass] >= 2) { synergies.count++; synergies.types.push(cardClass); } } return synergies; } function calculateHumanSynergies() { var synergies = { count: 0, types: [] }; var classCounts = {}; for (var i = 0; i < humanPlayer.battlefield.length; i++) { var cardClass = getCardClass(humanPlayer.battlefield[i].cardData.name); classCounts[cardClass] = (classCounts[cardClass] || 0) + 1; } for (var cardClass in classCounts) { if (classCounts[cardClass] >= 2) { synergies.count++; synergies.types.push(cardClass); } } return synergies; } function countClassCards(battlefield, cardClass) { var count = 0; for (var i = 0; i < battlefield.length; i++) { if (getCardClass(battlefield[i].cardData.name) === cardClass) { count++; } } return count; } function getAvailableLanes() { 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); } } return availableLanes; } function findHumanCardInLane(lane) { for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (humanPlayer.battlefield[i].laneIndex === lane) { return humanPlayer.battlefield[i]; } } return null; } function calculateTurnDelay(boardState, threatLevel) { var baseDelay = 1500; if (gameDifficulty === "easy") { baseDelay = 2200; // Slower for easy } else if (gameDifficulty === "hard") { baseDelay = 1000; // Faster for hard } // Faster decisions under high threat if (threatLevel > 70) baseDelay *= 0.8; // Add some variation baseDelay += (Math.random() - 0.5) * 400; return Math.max(800, baseDelay); } } // 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 // Button hover tracking var mainMenuButtonHover = false; // 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) { switch (passiveType) { case "burn": return "Burns all enemies for 1 damage at end of turn"; case "heal": return "Heals 1 health at start of turn"; case "taunt": return "Forces enemies to attack this card first"; case "evasion": return "25% chance to dodge attacks"; case "shock": return "Deals 3 damage to all enemies when played"; case "lifesteal": return "Heals 1 when dealing damage to other cards"; case "stealth": return "Cannot be targeted by spells for first turn"; case "divine_shield": return "Ignores the first damage taken"; case "frost": return "Slows enemy cards when attacking them"; case "rebirth": return "Revives once when destroyed with half health"; case "void": return "30% chance to teleport to different lane when taking damage"; case "crystal_shield": return "Reduces damage taken by all friendly cards by 1"; case "stone_skin": return "Reduces all damage taken by 1 (minimum 1 damage)"; case "shadow": return "Becomes invisible for 2 turns when played, harder to target"; default: return "No passive ability"; } } function createClassFeatureDisplay(className) { if (isShowingClassFeature) { destroyClassFeatureDisplay(); } var classInfo = classFeatures[className]; if (!classInfo) return; // Create dark overlay background var overlay = game.addChild(LK.getAsset('menuOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.85 })); // Class name title var titleText = new Text2(classInfo.name + " SINIFI", { size: 60, fill: 0xf39c12 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; game.addChild(titleText); // Class feature var featureText = new Text2("Özellik: " + classInfo.feature, { size: 48, fill: 0x3498db }); featureText.anchor.set(0.5, 0.5); featureText.x = 1024; featureText.y = 900; game.addChild(featureText); // Synergy bonus var synergyText = new Text2("Sinerji Bonusu: " + classInfo.synergy, { size: 44, fill: 0xFFD700 }); synergyText.anchor.set(0.5, 0.5); synergyText.x = 1024; synergyText.y = 1000; game.addChild(synergyText); // Description (split into multiple lines for better readability) var descLines = classInfo.description.split('. '); for (var i = 0; i < descLines.length; i++) { var lineText = new Text2(descLines[i] + (i < descLines.length - 1 ? '.' : ''), { size: 36, fill: 0xecf0f1 }); lineText.anchor.set(0.5, 0.5); lineText.x = 1024; lineText.y = 1150 + i * 60; game.addChild(lineText); } // Close instruction var closeText = new Text2("Kapatmak için herhangi bir yere tıklayın", { size: 32, fill: 0x7f8c8d }); closeText.anchor.set(0.5, 0.5); closeText.x = 1024; closeText.y = 1600; game.addChild(closeText); // Store references for cleanup classFeatureDisplay = { overlay: overlay, titleText: titleText, featureText: featureText, synergyText: synergyText, descLines: [], closeText: closeText }; // Add description lines to cleanup list for (var i = 0; i < descLines.length; i++) { classFeatureDisplay.descLines.push(game.children[game.children.length - 2 - i]); } isShowingClassFeature = true; // Auto-hide after 5 seconds LK.setTimeout(function () { destroyClassFeatureDisplay(); }, 5000); } function destroyClassFeatureDisplay() { if (!isShowingClassFeature || !classFeatureDisplay) return; if (classFeatureDisplay.overlay) { game.removeChild(classFeatureDisplay.overlay); } if (classFeatureDisplay.titleText) { game.removeChild(classFeatureDisplay.titleText); } if (classFeatureDisplay.featureText) { game.removeChild(classFeatureDisplay.featureText); } if (classFeatureDisplay.synergyText) { game.removeChild(classFeatureDisplay.synergyText); } for (var i = 0; i < classFeatureDisplay.descLines.length; i++) { if (classFeatureDisplay.descLines[i]) { game.removeChild(classFeatureDisplay.descLines[i]); } } if (classFeatureDisplay.closeText) { game.removeChild(classFeatureDisplay.closeText); } classFeatureDisplay = null; isShowingClassFeature = false; } 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(); } // Close class feature display if showing if (isShowingClassFeature) { destroyClassFeatureDisplay(); return; } // Check if a synergy class icon was clicked var classNames = ["Tank", "Mage", "Rogue", "Warrior"]; var synergyStartY = 800; var synergySpacing = 200; for (var i = 0; i < classNames.length; i++) { var className = classNames[i]; var yPos = synergyStartY + i * synergySpacing; var iconBounds = { left: 50, right: 150, top: yPos - 40, bottom: yPos + 40 }; if (x >= iconBounds.left && x <= iconBounds.right && y >= iconBounds.top && y <= iconBounds.bottom) { createClassFeatureDisplay(className); return; } } // Check if end turn button was clicked if (x >= 1700 && x <= 1900 && y >= 1910 && y <= 1990) { endTurn(); return; } // Check if main menu button was clicked if (x >= 1480 && x <= 1720 && y >= 110 && y <= 190) { // Button press effect tween(mainMenuBtn, { scaleX: 0.55, scaleY: 0.55, tint: 0x2980b9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(mainMenuBtn, { scaleX: 0.6, scaleY: 0.6, tint: 0x3498db }, { duration: 100, easing: tween.easeOut }); } }); // Return to main menu and reset game LK.setTimeout(function () { resetGame(); }, 200); 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]; // Ensure card is properly displayed in game if (!game.children.includes(card)) { continue; } 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 && humanPlayer.canPlayCard(card)) { selectedCard = card; draggedCard = card; // Start long press timer for zoom preview if (zoomPreviewTimeout) { LK.clearTimeout(zoomPreviewTimeout); } zoomPreviewTimeout = LK.setTimeout(function () { if (selectedCard === card && game.children.includes(card)) { createZoomPreview(card); draggedCard = null; // Cancel drag when showing zoom } }, 800); // 800ms long press } return; } } // Check battlefield cards for zoom preview and drag (human player cards only) for (var i = 0; i < humanPlayer.battlefield.length; i++) { var card = humanPlayer.battlefield[i]; // Ensure card is properly displayed in game if (!game.children.includes(card)) { continue; } 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; // Allow dragging battlefield cards if not locked in if (!cardsLockedIn && card.isOnBattlefield) { draggedCard = card; selectedCard = card; } // Start long press timer for battlefield card zoom if (zoomPreviewTimeout) { LK.clearTimeout(zoomPreviewTimeout); } zoomPreviewTimeout = LK.setTimeout(function () { if (!draggedCard && game.children.includes(card)) { // Only show zoom if not dragging createZoomPreview(card); } }, 800); return; } } // Check AI battlefield cards for zoom preview only (no dragging) for (var i = 0; i < aiPlayer.battlefield.length; i++) { var card = aiPlayer.battlefield[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 AI 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 AI 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; } // Check if mouse is over main menu button var isOverMainMenuButton = x >= 1480 && x <= 1720 && y >= 110 && y <= 190; if (isOverMainMenuButton && !mainMenuButtonHover) { mainMenuButtonHover = true; tween(mainMenuBtn, { scaleX: 0.7, scaleY: 0.7, tint: 0x5dade2 }, { duration: 200, easing: tween.easeOut }); } else if (!isOverMainMenuButton && mainMenuButtonHover) { mainMenuButtonHover = false; tween(mainMenuBtn, { scaleX: 0.6, scaleY: 0.6, tint: 0x3498db }, { duration: 200, easing: tween.easeOut }); } // Handle card dragging if (draggedCard && game.children.includes(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++) { if (game.children.includes(aiPlayer.battlefield[i])) { aiPlayer.battlefield[i].alpha = 1.0; } } for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (game.children.includes(humanPlayer.battlefield[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]; if (game.children.includes(card)) { var distance = Math.sqrt((card.x - x) * (card.x - x) + (card.y - y) * (card.y - y)); if (distance < 150) { card.alpha = 0.7; } } } } } else { // Reset dragged card if it's not in the game anymore draggedCard = null; selectedCard = null; } }; 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(); } } } // Check if card is being dragged from battlefield back to hand area (return to deck functionality) else if (draggedCard && y > 1900 && draggedCard.isOnBattlefield && !cardsLockedIn) { // Find the card on battlefield and return it to deck var battlefieldIndex = humanPlayer.battlefield.indexOf(draggedCard); if (battlefieldIndex >= 0) { // Store original card data before removing var originalCardData = { name: draggedCard.cardData.name, cost: draggedCard.cardData.cost, attack: draggedCard.cardData.attack, health: draggedCard.cardData.health, description: draggedCard.cardData.description, passive: draggedCard.cardData.passive }; // Return mana to player humanPlayer.currentMana = Math.min(humanPlayer.maxMana, humanPlayer.currentMana + draggedCard.cardData.cost); // Remove from battlefield humanPlayer.battlefield.splice(battlefieldIndex, 1); // Clear lane assignment draggedCard.laneIndex = undefined; draggedCard.isOnBattlefield = false; // Remove from game display game.removeChild(draggedCard); // Create a completely fresh new card instance with the original data var newCard = new Card(originalCardData); newCard.validateStats(); // Ensure stats are correct // Add new card instance to deck humanPlayer.deck.push(newCard); // Visual feedback for successful return var returnText = new Text2("KARTA DESTEYE DÖNDÜ!", { size: 40, fill: 0x27ae60 }); returnText.anchor.set(0.5, 0.5); returnText.x = 1024; returnText.y = 1500; returnText.alpha = 1.0; game.addChild(returnText); // Animate feedback text tween(returnText, { y: returnText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(returnText); } }); draggedCard = null; selectedCard = null; updateUI(); arrangeHand(); arrangeBattlefield(); } } // Check if card from hand is being dragged onto an occupied lane (card replacement) else if (draggedCard && !draggedCard.isOnBattlefield && 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 occupied by player's card var existingCardInLane = null; for (var i = 0; i < humanPlayer.battlefield.length; i++) { if (humanPlayer.battlefield[i].laneIndex === targetLane) { existingCardInLane = humanPlayer.battlefield[i]; break; } } // If lane is occupied and we can play the new card, replace it if (targetLane >= 0 && existingCardInLane && humanPlayer.canPlayCard(draggedCard)) { // 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 (!luciferBlocked) { // Store the existing card data var existingCardData = { name: existingCardInLane.cardData.name, cost: existingCardInLane.cardData.cost, attack: existingCardInLane.cardData.attack, health: existingCardInLane.cardData.health, description: existingCardInLane.cardData.description, passive: existingCardInLane.cardData.passive }; // Remove existing card from battlefield var existingIndex = humanPlayer.battlefield.indexOf(existingCardInLane); humanPlayer.battlefield.splice(existingIndex, 1); existingCardInLane.laneIndex = undefined; existingCardInLane.isOnBattlefield = false; game.removeChild(existingCardInLane); // Create new card instance for the replaced card and add to deck var replacedCard = new Card(existingCardData); replacedCard.validateStats(); humanPlayer.deck.push(replacedCard); // Play the new card in the same lane if (humanPlayer.playCard(draggedCard)) { draggedCard.laneIndex = targetLane; draggedCard.targetLane = targetLane; // Visual feedback for successful replacement var replaceText = new Text2("KART YER DEĞİŞTİRDİ!", { size: 40, fill: 0xf39c12 }); replaceText.anchor.set(0.5, 0.5); replaceText.x = 1024; replaceText.y = 1500; replaceText.alpha = 1.0; game.addChild(replaceText); // Animate feedback text tween(replaceText, { y: replaceText.y - 80, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(replaceText); } }); 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(); } }; function initializeGameplay() { // Initialize starting hands for (var i = 0; i < 4; i++) { humanPlayer.drawCard(); aiPlayer.drawCard(); } // Play background music LK.playMusic('Darksouls'); // Initial setup updateUI(); arrangeHand(); arrangeBattlefield(); arrangeSpells(); } function showMainMenu() { if (mainMenu) { game.removeChild(mainMenu); } mainMenu = new MainMenu(); game.addChild(mainMenu); } function showOpeningScreen() { var opening = new OpeningScreen(); game.addChild(opening); } // Initialize with opening screen if (gameState === "menu") { showOpeningScreen(); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.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
};
// 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;
}
// Initialize passive abilities based on card name if not already set
if (!self.cardData.passive) {
switch (self.cardData.name) {
case "Fire Imp":
self.cardData.passive = "burn";
break;
case "Water Spirit":
self.cardData.passive = "heal";
break;
case "Earth Golem":
self.cardData.passive = "stone_skin";
break;
case "Air Wisp":
self.cardData.passive = "evasion";
break;
case "Lightning Bolt":
self.cardData.passive = "shock";
break;
case "Lucifer":
self.cardData.passive = "lifesteal";
break;
case "Shadow Drake":
self.cardData.passive = "shadow";
break;
case "Michael Demiurgos":
self.cardData.passive = "divine_shield";
break;
case "Frost Wolf":
self.cardData.passive = "frost";
break;
case "Phoenix":
self.cardData.passive = "rebirth";
break;
case "Void Stalker":
self.cardData.passive = "void";
break;
case "Crystal Guardian":
self.cardData.passive = "crystal_shield";
break;
}
}
self.maxHealth = self.cardData.health;
self.currentHealth = self.cardData.health;
self.synergyAttackBonus = 0; // Track synergy bonuses
self.synergyHealthBonus = 0;
self.synergyHealthRegen = 0; // Track health regeneration per turn
self.synergyRage = false; // Track rage mechanic for Mage cards
self.frozenTurns = 0; // Track frozen state duration
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;
case "Frost Wolf":
cardAssetName = 'frostWolfBg';
symbolAssetName = 'frostWolfSymbol';
break;
case "Phoenix":
cardAssetName = 'phoenixBg';
symbolAssetName = 'phoenixSymbol';
break;
case "Void Stalker":
cardAssetName = 'voidStalkerBg';
symbolAssetName = 'voidStalkerSymbol';
break;
case "Crystal Guardian":
cardAssetName = 'crystalGuardianBg';
symbolAssetName = 'crystalGuardianSymbol';
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
}
// Add class indicators for cards
var classAsset = null;
if (self.cardData.name === "Earth Golem" || self.cardData.name === "Lightning Bolt") {
classAsset = self.attachAsset('tankClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Fire Imp" || self.cardData.name === "Water Spirit") {
classAsset = self.attachAsset('mageClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Shadow Drake" || self.cardData.name === "Michael Demiurgos") {
classAsset = self.attachAsset('rogueClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Air Wisp") {
classAsset = self.attachAsset('warriorClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Lucifer") {
classAsset = self.attachAsset('warriorClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Frost Wolf") {
classAsset = self.attachAsset('warriorClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Phoenix") {
classAsset = self.attachAsset('mageClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Void Stalker") {
classAsset = self.attachAsset('rogueClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
} else if (self.cardData.name === "Crystal Guardian") {
classAsset = self.attachAsset('tankClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = 80; // Top right corner
classAsset.y = -100;
}
// Card text elements - name removed
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 () {
// Calculate health with synergy bonus (Tank cards now get health bonus display)
var cardClass = getCardClass(self.cardData.name);
var healthBonus = self.synergyHealthBonus || 0;
var synergyMaxHealth = self.cardData.health + healthBonus;
var adjustedCurrentHealth = self.currentHealth + healthBonus;
var displayHealth = isNaN(adjustedCurrentHealth) ? 0 : Math.max(0, adjustedCurrentHealth);
// 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 with synergy bonus
if (self.healthText) {
self.healthText.setText(displayHealth.toString());
// Change color if synergy bonus is active (including Tank cards)
var cardClass = getCardClass(self.cardData.name);
if (healthBonus > 0) {
self.healthText.fill = 0x00ff00; // Green for boosted health
} else {
self.healthText.fill = 0x27AE60; // Normal green
}
} else if (healthText) {
healthText.setText(displayHealth.toString());
}
// Update attack text with synergy bonus
if (self.attackText && self.cardData.attack !== undefined) {
var displayAttack = self.cardData.attack + (self.synergyAttackBonus || 0);
self.attackText.setText(displayAttack.toString());
// Change color if synergy bonus is active (but not for Mage rage)
var cardClass = getCardClass(self.cardData.name);
if (self.synergyAttackBonus > 0) {
self.attackText.fill = 0x00ff00; // Green for boosted attack
} else if (self.synergyRage && cardClass === "Mage") {
self.attackText.fill = 0xFF4444; // Red glow for rage-enabled Mage cards
} else {
self.attackText.fill = 0xE74C3C; // Normal red
}
}
// 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;
}
// Check for damage prevention passives
var damageContext = {
attacker: attacker,
damage: damage
};
var passiveResult = self.triggerPassive("before_damage", damageContext);
if (passiveResult === -1) {
// Damage was negated by passive ability
return;
}
// Update damage if it was modified by passive (like stone_skin)
if (damageContext.damage !== undefined) {
damage = damageContext.damage;
}
// Check for Rogue synergy dodge
var cardClass = getCardClass(self.cardData.name);
if (cardClass === "Rogue" && self.isOnBattlefield) {
// Find which player owns this card
var ownerPlayer = null;
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;
}
}
}
if (ownerPlayer) {
// Count Rogue cards on battlefield
var rogueCount = 0;
for (var i = 0; i < ownerPlayer.battlefield.length; i++) {
if (getCardClass(ownerPlayer.battlefield[i].cardData.name) === "Rogue") {
rogueCount++;
}
}
// Rogue synergy triggers with 2 or more Rogue cards
if (rogueCount >= 2 && Math.random() < 0.2) {
// 20% chance to dodge
var dodgeText = new Text2("ROGUE DODGE!", {
size: 35,
fill: 0x8e44ad
});
dodgeText.anchor.set(0.5, 0.5);
dodgeText.x = self.x;
dodgeText.y = self.y - 50;
dodgeText.alpha = 1.0;
game.addChild(dodgeText);
tween(dodgeText, {
y: dodgeText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(dodgeText);
}
});
LK.effects.flashObject(self, 0x8e44ad, 300);
return; // Damage was dodged
}
}
}
// Check for Crystal Guardian damage reduction
var ownerPlayer = null;
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;
}
}
}
// Apply Crystal Guardian damage reduction
if (ownerPlayer) {
for (var i = 0; i < ownerPlayer.battlefield.length; i++) {
if (ownerPlayer.battlefield[i].cardData.name === "Crystal Guardian" && ownerPlayer.battlefield[i].currentHealth > 0) {
damage = Math.max(0, damage - 1);
// Show crystal shield effect
var shieldText = new Text2("CRYSTAL SHIELD!", {
size: 35,
fill: 0x00FFFF
});
shieldText.anchor.set(0.5, 0.5);
shieldText.x = self.x;
shieldText.y = self.y - 50;
shieldText.alpha = 1.0;
game.addChild(shieldText);
tween(shieldText, {
y: shieldText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(shieldText);
}
});
LK.effects.flashObject(self, 0x00FFFF, 300);
break;
}
}
}
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 1 health when dealing damage to other cards
if (attacker && attacker.cardData.name === "Lucifer" && self.isOnBattlefield) {
// Heal Lucifer by 1 health (not exceeding max health)
var healAmount = 1;
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);
}
// Vampire passive: heal equal to damage dealt
if (attacker && attacker.isOnBattlefield && getCardClass(attacker.cardData.name) === "Vampire") {
// Check if vampire synergy is active (2 or more vampire cards)
var attackerPlayer = null;
// Find which player owns the attacker
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
if (humanPlayer.battlefield[i] === attacker) {
attackerPlayer = humanPlayer;
break;
}
}
if (!attackerPlayer) {
for (var i = 0; i < aiPlayer.battlefield.length; i++) {
if (aiPlayer.battlefield[i] === attacker) {
attackerPlayer = aiPlayer;
break;
}
}
}
if (attackerPlayer) {
// Count vampire cards on battlefield
var vampireCount = 0;
for (var i = 0; i < attackerPlayer.battlefield.length; i++) {
if (getCardClass(attackerPlayer.battlefield[i].cardData.name) === "Vampire") {
vampireCount++;
}
}
// Vampire synergy triggers with 2 or more vampire cards
if (vampireCount >= 2) {
var healAmount = finalDamage; // Heal equal to damage dealt
var oldHealth = attacker.currentHealth;
attacker.currentHealth = Math.min(attacker.maxHealth, attacker.currentHealth + healAmount);
// Only show effect if health was actually restored
if (attacker.currentHealth > oldHealth) {
var actualHeal = attacker.currentHealth - oldHealth;
attacker.updateHealthDisplay();
// Create vampire healing visual effect
var vampireHealText = new Text2("+" + actualHeal.toString(), {
size: 38,
fill: 0x8B0000 // Dark red for vampire heal
});
vampireHealText.anchor.set(0.5, 0.5);
vampireHealText.x = attacker.x + (Math.random() - 0.5) * 60;
vampireHealText.y = attacker.y - 60;
vampireHealText.alpha = 1.0;
game.addChild(vampireHealText);
// Animate vampire healing with blood-like effect
tween(vampireHealText, {
y: vampireHealText.y - 90,
alpha: 0,
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 900,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(vampireHealText);
}
});
// Dark red flash on vampire card
LK.effects.flashObject(attacker, 0x8B0000, 400);
}
}
}
}
// 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.frozenTurns || self.frozenTurns <= 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 base attack value plus synergy bonus
var totalDamage = self.cardData.attack + (self.synergyAttackBonus || 0);
// Apply Mage rage mechanic if enabled
var isCriticalHit = false;
if (self.synergyRage && Math.random() < 0.25) {
totalDamage *= 2; // Double damage on rage proc
isCriticalHit = true;
// Critical hit screen flash
LK.effects.flashScreen(0xFFD700, 400);
// Show critical hit effect
var critText = new Text2("KRİTİK VURUŞ!", {
size: 50,
fill: 0xFFD700
});
critText.anchor.set(0.5, 0.5);
critText.x = self.x + (Math.random() - 0.5) * 60;
critText.y = self.y - 80;
critText.alpha = 1.0;
game.addChild(critText);
// Create sparkle effects around the attacking card
for (var sparkle = 0; sparkle < 6; sparkle++) {
var spark = game.addChild(LK.getAsset('manaOrb', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + (Math.random() - 0.5) * 120,
y: self.y + (Math.random() - 0.5) * 120,
scaleX: 0.3,
scaleY: 0.3,
alpha: 1.0,
tint: 0xFFD700
}));
// Animate sparkles
tween(spark, {
scaleX: 0.8,
scaleY: 0.8,
alpha: 0,
x: spark.x + (Math.random() - 0.5) * 200,
y: spark.y + (Math.random() - 0.5) * 200
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
if (game.children.includes(spark)) {
game.removeChild(spark);
}
}
});
}
// Animate critical text with glow effect
tween(critText, {
y: critText.y - 80,
alpha: 0,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(critText);
}
});
// Enhanced card flash for critical hit
tween(self, {
tint: 0xFFD700,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
// 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;
// Handle frozen state
if (self.frozenTurns > 0) {
self.frozenTurns--;
if (self.frozenTurns <= 0) {
// Return to normal state when freeze ends
self.alpha = 1.0;
self.tint = 0xFFFFFF; // Remove blue tint
}
}
if (self.currentHealth > 0) {
cardBg.alpha = 1.0;
}
};
// Passive ability system
self.triggerPassive = function (trigger, context) {
if (!self.hasPassive()) return 0;
var passiveType = self.cardData.passive;
var effect = 0;
switch (passiveType) {
case "burn":
if (trigger === "end_turn" && self.isOnBattlefield) {
// Fire Imp: Burns all enemy cards for 1 damage at end of turn
var enemyPlayer = context.player.isHuman ? aiPlayer : humanPlayer;
for (var i = 0; i < enemyPlayer.battlefield.length; i++) {
var enemyCard = enemyPlayer.battlefield[i];
if (enemyCard.currentHealth > 0) {
enemyCard.takeDamage(1, self);
// Create burn visual effect
var burnEffect = game.addChild(LK.getAsset('burnEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: enemyCard.x + (Math.random() - 0.5) * 40,
y: enemyCard.y - 30,
alpha: 0.8,
tint: 0xff4400
}));
tween(burnEffect, {
y: burnEffect.y - 60,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(burnEffect);
}
});
}
}
effect = 1;
}
break;
case "heal":
if (trigger === "turn_start" && self.isOnBattlefield) {
// Water Spirit: Heals 1 health at start of turn
var oldHealth = self.currentHealth;
self.currentHealth = Math.min(self.maxHealth, self.currentHealth + 1);
if (self.currentHealth > oldHealth) {
self.updateHealthDisplay();
// Create healing visual effect
var healText = new Text2("+1", {
size: 30,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = self.x + (Math.random() - 0.5) * 40;
healText.y = self.y - 30;
healText.alpha = 1.0;
game.addChild(healText);
tween(healText, {
y: healText.y - 60,
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(healText);
}
});
LK.effects.flashObject(self, 0x00ff00, 200);
effect = 1;
}
}
break;
case "shock":
if (trigger === "played") {
// Lightning Bolt: Deals 3 damage to all enemies when played
var enemyPlayer = context.player.isHuman ? aiPlayer : humanPlayer;
for (var i = 0; i < enemyPlayer.battlefield.length; i++) {
var enemyCard = enemyPlayer.battlefield[i];
if (enemyCard.currentHealth > 0) {
enemyCard.takeDamage(3, self);
}
}
// Screen flash for shock effect
LK.effects.flashScreen(0xffff00, 300);
effect = 1;
}
break;
case "evasion":
// Check if Warrior synergy is active for Air Wisp
var evasionChance = 0.25; // Default 25% chance
if (self.cardData.name === "Air Wisp" && self.isOnBattlefield) {
// Find which player owns this card
var ownerPlayer = null;
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;
}
}
}
if (ownerPlayer) {
// Count Warrior cards on battlefield
var warriorCount = 0;
for (var i = 0; i < ownerPlayer.battlefield.length; i++) {
if (getCardClass(ownerPlayer.battlefield[i].cardData.name) === "Warrior") {
warriorCount++;
}
}
// Warrior synergy triggers with 2 or more Warrior cards
if (warriorCount >= 2) {
evasionChance = 0.60; // Increase to 60% with synergy
}
}
}
if (trigger === "before_damage" && Math.random() < evasionChance) {
// Air Wisp: evasion chance (25% base, 60% with Warrior synergy)
var dodgeText = new Text2("DODGE!", {
size: 35,
fill: 0x00ffff
});
dodgeText.anchor.set(0.5, 0.5);
dodgeText.x = self.x;
dodgeText.y = self.y - 50;
dodgeText.alpha = 1.0;
game.addChild(dodgeText);
tween(dodgeText, {
y: dodgeText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(dodgeText);
}
});
LK.effects.flashObject(self, 0x00ffff, 300);
return -1; // Negative return indicates damage should be negated
}
break;
case "divine_shield":
if (trigger === "played" && !self.shieldUsed) {
// Initialize divine shield when card is played
self.shieldUsed = false;
self.alpha = 0.9; // Slight transparency to indicate shield
}
if (trigger === "before_damage" && !self.shieldUsed) {
// Michael Demiurgos: Ignores first damage taken
self.shieldUsed = true;
self.alpha = 1.0; // Return to normal transparency
var shieldText = new Text2("DIVINE SHIELD!", {
size: 35,
fill: 0xffd700
});
shieldText.anchor.set(0.5, 0.5);
shieldText.x = self.x;
shieldText.y = self.y - 50;
shieldText.alpha = 1.0;
game.addChild(shieldText);
tween(shieldText, {
y: shieldText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(shieldText);
}
});
LK.effects.flashObject(self, 0xffd700, 400);
return -1; // Negative return indicates damage should be negated
}
if (trigger === "before_damage" && self.shieldUsed && turnCounter > 1 && Math.random() < 0.1) {
// Michael Demiurgos: 10% chance to avoid damage after first turn
var dodgeText = new Text2("DIVINE PROTECTION!", {
size: 35,
fill: 0xffd700
});
dodgeText.anchor.set(0.5, 0.5);
dodgeText.x = self.x;
dodgeText.y = self.y - 50;
dodgeText.alpha = 1.0;
game.addChild(dodgeText);
tween(dodgeText, {
y: dodgeText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(dodgeText);
}
});
LK.effects.flashObject(self, 0xffd700, 300);
return -1; // Negative return indicates damage should be negated
}
break;
case "stealth":
if (trigger === "played") {
// Shadow Drake: Cannot be targeted by spells for first turn
self.stealthTurns = 1;
var stealthText = new Text2("STEALTH", {
size: 30,
fill: 0x8b008b
});
stealthText.anchor.set(0.5, 0.5);
stealthText.x = self.x;
stealthText.y = self.y - 50;
stealthText.alpha = 1.0;
game.addChild(stealthText);
tween(stealthText, {
y: stealthText.y - 60,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(stealthText);
}
});
self.alpha = 0.7; // Visual indicator of stealth
effect = 1;
} else if (trigger === "turn_start" && self.stealthTurns > 0) {
self.stealthTurns--;
if (self.stealthTurns <= 0) {
self.alpha = 1.0; // Return to normal visibility
}
}
break;
case "taunt":
// Earth Golem: Forces enemies to attack this card first
// This is handled in AI targeting logic and combat resolution
break;
case "frost":
// Frost Wolf: Slows enemy cards when attacking them
if (trigger === "attack_dealt" && context.target && context.target.isOnBattlefield) {
// Add slow effect - reduce attack by 1 for 2 turns
context.target.frostSlowTurns = 2;
context.target.frostSlowAmount = 1;
var frostText = new Text2("FROST SLOW!", {
size: 35,
fill: 0x87CEEB
});
frostText.anchor.set(0.5, 0.5);
frostText.x = context.target.x;
frostText.y = context.target.y - 50;
frostText.alpha = 1.0;
game.addChild(frostText);
tween(frostText, {
y: frostText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(frostText);
}
});
LK.effects.flashObject(context.target, 0x87CEEB, 400);
effect = 1;
}
break;
case "rebirth":
if (trigger === "death" && !self.hasRebirthed && self.isOnBattlefield) {
// Phoenix: Revives once when destroyed with half health
self.hasRebirthed = true;
self.currentHealth = Math.ceil(self.maxHealth / 2);
self.updateHealthDisplay();
// Create rebirth visual effect
var rebirthText = new Text2("REBIRTH!", {
size: 45,
fill: 0xFF6B00
});
rebirthText.anchor.set(0.5, 0.5);
rebirthText.x = self.x;
rebirthText.y = self.y - 50;
rebirthText.alpha = 1.0;
game.addChild(rebirthText);
// Create fire effect around Phoenix
for (var flame = 0; flame < 8; flame++) {
var fireEffect = game.addChild(LK.getAsset('burnEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + Math.cos(flame * Math.PI / 4) * 60,
y: self.y + Math.sin(flame * Math.PI / 4) * 60,
scaleX: 0.8,
scaleY: 0.8,
alpha: 0.9,
tint: 0xFF4500
}));
tween(fireEffect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
if (game.children.includes(fireEffect)) {
game.removeChild(fireEffect);
}
}
});
}
// Animate rebirth text
tween(rebirthText, {
y: rebirthText.y - 80,
alpha: 0,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(rebirthText);
}
});
// Flash Phoenix with fire colors
LK.effects.flashObject(self, 0xFF6B00, 600);
effect = 1;
}
break;
case "void":
if (trigger === "before_damage" && self.isOnBattlefield && Math.random() < 0.3) {
// Void Stalker: 30% chance to teleport to different lane when taking damage
var ownerPlayer = null;
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;
}
}
}
if (ownerPlayer) {
// Find available lanes
var availableLanes = [0, 1, 2];
var currentLane = self.laneIndex;
// Remove current lane and occupied lanes
for (var i = 0; i < ownerPlayer.battlefield.length; i++) {
var occupiedLane = ownerPlayer.battlefield[i].laneIndex;
if (occupiedLane !== undefined) {
var laneIdx = availableLanes.indexOf(occupiedLane);
if (laneIdx >= 0) availableLanes.splice(laneIdx, 1);
}
}
// If there are available lanes, teleport
if (availableLanes.length > 0) {
var newLane = availableLanes[Math.floor(Math.random() * availableLanes.length)];
self.laneIndex = newLane;
var lanePositions = [600, 1024, 1448];
// Teleport animation
var voidText = new Text2("VOID TELEPORT!", {
size: 35,
fill: 0x8B008B
});
voidText.anchor.set(0.5, 0.5);
voidText.x = self.x;
voidText.y = self.y - 50;
voidText.alpha = 1.0;
game.addChild(voidText);
// Fade out at current position
tween(self, {
alpha: 0.2,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Move to new lane
self.x = lanePositions[newLane];
// Fade back in at new position
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
});
tween(voidText, {
y: voidText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(voidText);
}
});
LK.effects.flashObject(self, 0x8B008B, 400);
effect = 1;
return -1; // Negative return indicates damage should be negated
}
}
}
break;
case "crystal_shield":
// Crystal Guardian: Reduces damage taken by all friendly cards by 1
// This is implemented in the damage calculation of other cards
break;
case "stone_skin":
if (trigger === "before_damage" && self.isOnBattlefield) {
// Earth Golem: Reduces all damage taken by 1 (minimum 1 damage)
if (context.damage && context.damage > 1) {
context.damage = Math.max(1, context.damage - 1);
var stoneText = new Text2("STONE SKIN!", {
size: 35,
fill: 0x8B4513
});
stoneText.anchor.set(0.5, 0.5);
stoneText.x = self.x;
stoneText.y = self.y - 50;
stoneText.alpha = 1.0;
game.addChild(stoneText);
tween(stoneText, {
y: stoneText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(stoneText);
}
});
LK.effects.flashObject(self, 0x8B4513, 400);
effect = 1;
}
}
break;
case "shadow":
if (trigger === "played") {
// Shadow Drake: Becomes invisible for 2 turns, cannot be targeted by spells or direct attacks
self.shadowTurns = 2;
self.alpha = 0.5; // Visual indicator of shadow state
var shadowText = new Text2("SHADOW CLOAK!", {
size: 35,
fill: 0x8B008B
});
shadowText.anchor.set(0.5, 0.5);
shadowText.x = self.x;
shadowText.y = self.y - 50;
shadowText.alpha = 1.0;
game.addChild(shadowText);
tween(shadowText, {
y: shadowText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(shadowText);
}
});
LK.effects.flashObject(self, 0x8B008B, 600);
effect = 1;
} else if (trigger === "turn_start" && self.shadowTurns > 0) {
// Reduce shadow duration
self.shadowTurns--;
if (self.shadowTurns <= 0) {
self.alpha = 1.0; // Return to normal visibility
var unshadowText = new Text2("SHADOW FADES", {
size: 30,
fill: 0x8B008B
});
unshadowText.anchor.set(0.5, 0.5);
unshadowText.x = self.x;
unshadowText.y = self.y - 50;
unshadowText.alpha = 1.0;
game.addChild(unshadowText);
tween(unshadowText, {
y: unshadowText.y - 60,
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(unshadowText);
}
});
}
}
break;
}
return effect;
};
self.hasPassive = function () {
return self.cardData.passive !== null && self.cardData.passive !== undefined;
};
// 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 DeckView = Container.expand(function () {
var self = Container.call(this);
// Dark overlay background
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.9
});
// Title
var titleText = new Text2("KART VE BÜYÜ KOLEKSİYONU", {
size: 80,
fill: 0xf39c12
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
self.addChild(titleText);
// Cards section title
var cardsTitle = new Text2("KARTLAR", {
size: 60,
fill: 0x3498db
});
cardsTitle.anchor.set(0.5, 0.5);
cardsTitle.x = 1024;
cardsTitle.y = 350;
self.addChild(cardsTitle);
// Spells section title
var spellsTitle = new Text2("BÜYÜLER", {
size: 60,
fill: 0x9b59b6
});
spellsTitle.anchor.set(0.5, 0.5);
spellsTitle.x = 1024;
spellsTitle.y = 1800;
self.addChild(spellsTitle);
// Close button
var closeBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2400,
scaleX: 0.8,
scaleY: 0.8
});
// Create sample cards for display
var cardTypes = [{
name: "Fire Imp",
cost: 3,
attack: 2,
health: 5,
description: "A small fire creature",
passive: "burn"
}, {
name: "Water Spirit",
cost: 2,
attack: 2,
health: 4,
description: "A defensive water creature",
passive: "heal"
}, {
name: "Earth Golem",
cost: 3,
attack: 1,
health: 10,
description: "A powerful earth creature",
passive: "taunt"
}, {
name: "Air Wisp",
cost: 1,
attack: 1,
health: 3,
description: "A quick air creature",
passive: "evasion"
}, {
name: "Lightning Bolt",
cost: 2,
attack: 1,
health: 5,
description: "A shocking creature",
passive: "shock"
}, {
name: "Lucifer",
cost: 4,
attack: 3,
health: 6,
description: "A mystical water spirit with high endurance",
passive: "lifesteal"
}, {
name: "Shadow Drake",
cost: 3,
attack: 3,
health: 4,
description: "A powerful shadow dragon",
passive: "stealth" // Cannot be targeted by spells for first turn
}, {
name: "Michael Demiurgos",
cost: 4,
attack: 2,
health: 7,
description: "An archangel with divine power",
passive: "divine_shield"
}, {
name: "Frost Wolf",
cost: 3,
attack: 2,
health: 6,
description: "A fierce ice wolf with freezing attacks",
passive: "frost"
}, {
name: "Phoenix",
cost: 4,
attack: 3,
health: 4,
description: "A legendary fire bird that can rise from ashes",
passive: "rebirth"
}, {
name: "Void Stalker",
cost: 3,
attack: 2,
health: 5,
description: "A shadowy creature from the void with teleportation abilities",
passive: "void"
}, {
name: "Crystal Guardian",
cost: 4,
attack: 1,
health: 8,
description: "A mystical crystal protector that shields nearby allies",
passive: "crystal_shield"
}];
// Display cards in a grid (4 cards per row)
self.displayCards = [];
for (var i = 0; i < cardTypes.length; i++) {
var displayCard = new Card(cardTypes[i]);
var row = Math.floor(i / 4);
var col = i % 4;
var startX = 1024 - 3 * 100; // Center 4 cards
displayCard.x = startX + col * 200;
displayCard.y = 500 + row * 300;
displayCard.scaleX = 0.6;
displayCard.scaleY = 0.6;
self.addChild(displayCard);
self.displayCards.push(displayCard);
// Add class logos to cards in deck view
var classAsset = null;
if (cardTypes[i].name === "Earth Golem" || cardTypes[i].name === "Lightning Bolt") {
classAsset = self.attachAsset('tankClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Fire Imp" || cardTypes[i].name === "Water Spirit") {
classAsset = self.attachAsset('mageClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Shadow Drake" || cardTypes[i].name === "Michael Demiurgos") {
classAsset = self.attachAsset('rogueClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Air Wisp") {
classAsset = self.attachAsset('warriorClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Lucifer") {
classAsset = self.attachAsset('warriorClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Frost Wolf") {
classAsset = self.attachAsset('warriorClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Phoenix") {
classAsset = self.attachAsset('mageClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Void Stalker") {
classAsset = self.attachAsset('rogueClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
} else if (cardTypes[i].name === "Crystal Guardian") {
classAsset = self.attachAsset('tankClass', {
anchorX: 1,
anchorY: 0
});
classAsset.x = displayCard.x + 48; // Adjusted for scaled card
classAsset.y = displayCard.y - 60;
classAsset.scaleX = 0.6;
classAsset.scaleY = 0.6;
}
}
// Create sample spells for display
var spellTypes = [{
name: "Fire Ball",
cost: 2,
damage: 2,
target: "enemy",
description: "Deals 2 damage to target"
}, {
name: "Şifa",
cost: 2,
damage: -2,
target: "ally",
description: "Heals target for 2 health"
}, {
name: "Freeze",
cost: 2,
damage: 0,
target: "enemy",
description: "Freezes target enemy for 1 turn"
}];
// Display spells
self.displaySpells = [];
for (var i = 0; i < spellTypes.length; i++) {
var displaySpell = new Spell(spellTypes[i]);
displaySpell.x = 1024 - 100 + i * 200;
displaySpell.y = 1950;
displaySpell.scaleX = 0.8;
displaySpell.scaleY = 0.8;
self.addChild(displaySpell);
self.displaySpells.push(displaySpell);
}
self.closeButtonHover = false;
self.down = function (x, y, obj) {
// If showing zoom, hide it first
if (self.isShowingZoom) {
self.hideCardZoom();
return;
}
// Check if close button was clicked
if (x >= 824 && x <= 1224 && y >= 2360 && y <= 2440) {
// Button press effect
tween(closeBtn, {
scaleX: 0.75,
scaleY: 0.75,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(closeBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Close deck view after animation
LK.setTimeout(function () {
self.closeDeckView();
}, 200);
return;
}
// Check if any card was clicked for zoom preview
for (var i = 0; i < self.displayCards.length; i++) {
var card = self.displayCards[i];
var cardBounds = {
left: card.x - 54,
// card.scaleX is 0.6, so bounds are 90*0.6 = 54
right: card.x + 54,
top: card.y - 75,
// card.scaleY is 0.6, so bounds are 125*0.6 = 75
bottom: card.y + 75
};
if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) {
self.showCardZoom(card);
return;
}
}
// Check if any spell was clicked for zoom preview
for (var i = 0; i < self.displaySpells.length; i++) {
var spell = self.displaySpells[i];
var spellBounds = {
left: spell.x - 48,
// spell.scaleX is 0.8, so bounds are 60*0.8 = 48
right: spell.x + 48,
top: spell.y - 48,
// spell.scaleY is 0.8, so bounds are 60*0.8 = 48
bottom: spell.y + 48
};
if (x >= spellBounds.left && x <= spellBounds.right && y >= spellBounds.top && y <= spellBounds.bottom) {
self.showSpellZoom(spell);
return;
}
}
};
self.move = function (x, y, obj) {
// Check if mouse is over close button
var isOverCloseButton = x >= 824 && x <= 1224 && y >= 2360 && y <= 2440;
if (isOverCloseButton && !self.closeButtonHover) {
self.closeButtonHover = true;
tween(closeBtn, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverCloseButton && self.closeButtonHover) {
self.closeButtonHover = false;
tween(closeBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.closeDeckView = function () {
// Fade out deck view
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove deck view and return to menu
game.removeChild(self);
}
});
};
// Entrance animation
self.alpha = 0;
self.scaleX = 0.8;
self.scaleY = 0.8;
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeOut
});
// Card zoom preview variables for deck view
self.zoomCard = null;
self.zoomBg = null;
self.zoomTexts = [];
self.isShowingZoom = false;
self.showCardZoom = function (card) {
if (self.isShowingZoom) {
self.hideCardZoom();
}
// Create dark overlay
self.zoomBg = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.95
});
// Create zoomed card
self.zoomCard = new Card(card.cardData);
self.zoomCard.x = 1024;
self.zoomCard.y = 1200;
self.zoomCard.scaleX = 3.0;
self.zoomCard.scaleY = 3.0;
self.addChild(self.zoomCard);
// Card name
var nameText = new Text2(card.cardData.name, {
size: 80,
fill: 0xf39c12
});
nameText.anchor.set(0.5, 0.5);
nameText.x = 1024;
nameText.y = 800;
self.addChild(nameText);
self.zoomTexts.push(nameText);
// Card stats
var statsText = new Text2("Mana: " + card.cardData.cost + " | Saldırı: " + card.cardData.attack + " | Can: " + card.cardData.health, {
size: 48,
fill: 0x3498db
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 1024;
statsText.y = 900;
self.addChild(statsText);
self.zoomTexts.push(statsText);
// Card description
var descText = new Text2(card.cardData.description, {
size: 40,
fill: 0xecf0f1
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1600;
self.addChild(descText);
self.zoomTexts.push(descText);
// Passive abilities
var passiveDesc = card.hasPassive() ? getPassiveDescription(card.cardData.passive) : "Yok";
var passiveText = new Text2("Pasif Yetenek: " + passiveDesc, {
size: 36,
fill: card.hasPassive() ? 0xf39c12 : 0x95a5a6
});
passiveText.anchor.set(0.5, 0.5);
passiveText.x = 1024;
passiveText.y = 1700;
self.addChild(passiveText);
self.zoomTexts.push(passiveText);
// Close instruction
var closeText = new Text2("Kapatmak için herhangi bir yere tıklayın", {
size: 32,
fill: 0x7f8c8d
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 1024;
closeText.y = 2000;
self.addChild(closeText);
self.zoomTexts.push(closeText);
// Animate zoom in
self.zoomCard.alpha = 0;
self.zoomCard.scaleX = 1.0;
self.zoomCard.scaleY = 1.0;
tween(self.zoomCard, {
alpha: 1.0,
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 400,
easing: tween.easeOut
});
for (var i = 0; i < self.zoomTexts.length; i++) {
self.zoomTexts[i].alpha = 0;
tween(self.zoomTexts[i], {
alpha: 1.0
}, {
duration: 400,
easing: tween.easeOut
});
}
self.isShowingZoom = true;
};
self.showSpellZoom = function (spell) {
if (self.isShowingZoom) {
self.hideCardZoom();
}
// Create dark overlay
self.zoomBg = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.95
});
// Create zoomed spell
self.zoomCard = new Spell(spell.spellData);
self.zoomCard.x = 1024;
self.zoomCard.y = 1200;
self.zoomCard.scaleX = 4.0;
self.zoomCard.scaleY = 4.0;
self.addChild(self.zoomCard);
// Spell name
var nameText = new Text2(spell.spellData.name, {
size: 80,
fill: 0x9b59b6
});
nameText.anchor.set(0.5, 0.5);
nameText.x = 1024;
nameText.y = 800;
self.addChild(nameText);
self.zoomTexts.push(nameText);
// Spell stats
var effectText = spell.spellData.damage >= 0 ? "Hasar: " + spell.spellData.damage : "İyileştirme: " + Math.abs(spell.spellData.damage);
var statsText = new Text2("Mana: " + spell.spellData.cost + " | " + effectText + " | Hedef: " + (spell.spellData.target === "enemy" ? "Düşman" : "Müttefik"), {
size: 48,
fill: 0x3498db
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 1024;
statsText.y = 900;
self.addChild(statsText);
self.zoomTexts.push(statsText);
// Spell description
var descText = new Text2(spell.spellData.description, {
size: 40,
fill: 0xecf0f1
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1600;
self.addChild(descText);
self.zoomTexts.push(descText);
// Close instruction
var closeText = new Text2("Kapatmak için herhangi bir yere tıklayın", {
size: 32,
fill: 0x7f8c8d
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 1024;
closeText.y = 2000;
self.addChild(closeText);
self.zoomTexts.push(closeText);
// Animate zoom in
self.zoomCard.alpha = 0;
self.zoomCard.scaleX = 1.0;
self.zoomCard.scaleY = 1.0;
tween(self.zoomCard, {
alpha: 1.0,
scaleX: 4.0,
scaleY: 4.0
}, {
duration: 400,
easing: tween.easeOut
});
for (var i = 0; i < self.zoomTexts.length; i++) {
self.zoomTexts[i].alpha = 0;
tween(self.zoomTexts[i], {
alpha: 1.0
}, {
duration: 400,
easing: tween.easeOut
});
}
self.isShowingZoom = true;
};
self.hideCardZoom = function () {
if (!self.isShowingZoom) return;
// Animate zoom out
if (self.zoomCard) {
tween(self.zoomCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.removeChild(self.zoomCard);
self.zoomCard = null;
}
});
}
// Animate text fade out
for (var i = 0; i < self.zoomTexts.length; i++) {
var text = self.zoomTexts[i];
tween(text, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.removeChild(text);
}
});
}
// Remove background
if (self.zoomBg) {
tween(self.zoomBg, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.removeChild(self.zoomBg);
self.zoomBg = null;
}
});
}
self.zoomTexts = [];
self.isShowingZoom = false;
};
return self;
});
var DifficultySelection = Container.expand(function () {
var self = Container.call(this);
// Dark overlay background
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.9
});
// Title
var titleText = new Text2("ZORLUK SEÇİN", {
size: 100,
fill: 0xf39c12
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
self.addChild(titleText);
// Easy button
var easyBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1000,
tint: 0x27ae60
});
var easyBtnText = new Text2("KOLAY", {
size: 56,
fill: 0xffffff
});
easyBtnText.anchor.set(0.5, 0.5);
easyBtnText.x = 1024;
easyBtnText.y = 1080;
self.addChild(easyBtnText);
// Medium button
var mediumBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1300,
tint: 0xf39c12
});
var mediumBtnText = new Text2("ORTA", {
size: 56,
fill: 0xffffff
});
mediumBtnText.anchor.set(0.5, 0.5);
mediumBtnText.x = 1024;
mediumBtnText.y = 1380;
self.addChild(mediumBtnText);
// Hard button
var hardBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1600,
tint: 0xe74c3c
});
var hardBtnText = new Text2("ZOR", {
size: 56,
fill: 0xffffff
});
hardBtnText.anchor.set(0.5, 0.5);
hardBtnText.x = 1024;
hardBtnText.y = 1680;
self.addChild(hardBtnText);
// Back button
var backBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1850,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x95a5a6
});
// Button hover tracking
self.easyButtonHover = false;
self.mediumButtonHover = false;
self.hardButtonHover = false;
self.backButtonHover = false;
self.down = function (x, y, obj) {
// Check if easy button was clicked
if (x >= 824 && x <= 1224 && y >= 940 && y <= 1060) {
// Button press effect
tween(easyBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x2ecc71
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(easyBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x27ae60
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Start game with easy difficulty
LK.setTimeout(function () {
self.startGameWithDifficulty("easy");
}, 200);
}
// Check if medium button was clicked
else if (x >= 824 && x <= 1224 && y >= 1240 && y <= 1360) {
// Button press effect
tween(mediumBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0xe67e22
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(mediumBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xf39c12
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Start game with medium difficulty
LK.setTimeout(function () {
self.startGameWithDifficulty("medium");
}, 200);
}
// Check if hard button was clicked
else if (x >= 824 && x <= 1224 && y >= 1540 && y <= 1660) {
// Button press effect
tween(hardBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0xc0392b
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(hardBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xe74c3c
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Start game with hard difficulty
LK.setTimeout(function () {
self.startGameWithDifficulty("hard");
}, 200);
}
// Check if back button was clicked
else if (x >= 904 && x <= 1144 && y >= 1810 && y <= 1890) {
// Button press effect
tween(backBtn, {
scaleX: 0.75,
scaleY: 0.75,
tint: 0x7f8c8d
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(backBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x95a5a6
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Go back to main menu
LK.setTimeout(function () {
self.goBackToMenu();
}, 200);
}
};
self.move = function (x, y, obj) {
// Check if mouse is over easy button
var isOverEasyButton = x >= 824 && x <= 1224 && y >= 940 && y <= 1060;
if (isOverEasyButton && !self.easyButtonHover) {
self.easyButtonHover = true;
tween(easyBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0x2ecc71
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverEasyButton && self.easyButtonHover) {
self.easyButtonHover = false;
tween(easyBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x27ae60
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over medium button
var isOverMediumButton = x >= 824 && x <= 1224 && y >= 1240 && y <= 1360;
if (isOverMediumButton && !self.mediumButtonHover) {
self.mediumButtonHover = true;
tween(mediumBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xe67e22
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverMediumButton && self.mediumButtonHover) {
self.mediumButtonHover = false;
tween(mediumBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xf39c12
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over hard button
var isOverHardButton = x >= 824 && x <= 1224 && y >= 1540 && y <= 1660;
if (isOverHardButton && !self.hardButtonHover) {
self.hardButtonHover = true;
tween(hardBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xc0392b
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverHardButton && self.hardButtonHover) {
self.hardButtonHover = false;
tween(hardBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xe74c3c
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over back button
var isOverBackButton = x >= 904 && x <= 1144 && y >= 1810 && y <= 1890;
if (isOverBackButton && !self.backButtonHover) {
self.backButtonHover = true;
tween(backBtn, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0xbdc3c7
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverBackButton && self.backButtonHover) {
self.backButtonHover = false;
tween(backBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x95a5a6
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.startGameWithDifficulty = function (difficulty) {
// Store difficulty for later use
gameDifficulty = difficulty;
// Update player health based on selected difficulty
if (gameDifficulty === "easy") {
humanPlayer.health = 20;
aiPlayer.health = 15;
} else if (gameDifficulty === "medium") {
humanPlayer.health = 20;
aiPlayer.health = 20;
} else if (gameDifficulty === "hard") {
humanPlayer.health = 20;
aiPlayer.health = 25;
}
// Fade out difficulty selection
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove difficulty selection and start game
game.removeChild(self);
gameState = "playing";
initializeGameplay();
}
});
};
self.goBackToMenu = function () {
// Fade out difficulty selection
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove difficulty selection and return to menu
game.removeChild(self);
showMainMenu();
}
});
};
// Entrance animation
self.alpha = 0;
self.scaleX = 0.8;
self.scaleY = 0.8;
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeOut
});
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Menu background
var menuBg = self.attachAsset('menuBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.8
});
// Dark overlay for better text visibility
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.6
});
// Game title
var titleText = new Text2("Arsenic", {
size: 120,
fill: 0xf39c12
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
self.addChild(titleText);
// Subtitle
var subtitleText = new Text2("Rakibini Yenmek İçin Kartlarını Kullan", {
size: 48,
fill: 0xecf0f1
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 950;
self.addChild(subtitleText);
// Play button
var playBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1250
});
// Deck button
var deckBtn = self.attachAsset('deckButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1500
});
// Wiki button at bottom
var wikiBtn = self.attachAsset('wikiButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2000
});
// Wiki icon removed
// Wiki button text removed
// Medal display
var medalCount = storage.gamesWon || 0;
var medalText = new Text2("🏆 Kazanılan Oyunlar: " + medalCount, {
size: 48,
fill: 0xf39c12
});
medalText.anchor.set(0.5, 0.5);
medalText.x = 1024;
medalText.y = 1650;
self.addChild(medalText);
// Instructions
var instructionText = new Text2("• Kartları sürükleyerek oynat\n• Büyüleri rakip kartlara hedefle\n• Rakibin canını 0'a düşür", {
size: 36,
fill: 0xbdc3c7
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1880;
self.addChild(instructionText);
// Early Access text
var earlyAccessText = new Text2("Early Access", {
size: 36,
fill: 0xe74c3c
});
earlyAccessText.anchor.set(0.5, 0.5);
earlyAccessText.x = 1024;
earlyAccessText.y = 2150;
self.addChild(earlyAccessText);
// Waldo credit text
var waldoText = new Text2("Waldo tarafından yapıldı", {
size: 32,
fill: 0x3498db
});
waldoText.anchor.set(0.5, 0.5);
waldoText.x = 1024;
waldoText.y = 2220;
self.addChild(waldoText);
// Credits
var creditsText = new Text2("FRVR Tarafından Yapıldı", {
size: 28,
fill: 0x95a5a6
});
creditsText.anchor.set(0.5, 0.5);
creditsText.x = 1024;
creditsText.y = 2280;
self.addChild(creditsText);
// Button hover effect
self.playButtonHover = false;
self.deckButtonHover = false;
self.wikiButtonHover = false;
self.down = function (x, y, obj) {
// Check if play button was clicked
if (x >= 824 && x <= 1224 && y >= 1190 && y <= 1310) {
// Button press effect
tween(playBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Show training mode selection overlay
LK.setTimeout(function () {
self.showTrainingModeSelection();
}, 200);
}
// Check if deck button was clicked
else if (x >= 824 && x <= 1224 && y >= 1440 && y <= 1560) {
// Button press effect
tween(deckBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(deckBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Show deck view after animation
LK.setTimeout(function () {
self.showDeckView();
}, 200);
}
// Check if wiki button was clicked
else if (x >= 824 && x <= 1224 && y >= 1960 && y <= 2040) {
// Button press effect
tween(wikiBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(wikiBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Show wiki view after animation
LK.setTimeout(function () {
self.showWikiView();
}, 200);
}
// Check if medal was clicked
else if (x >= 824 && x <= 1224 && y >= 1610 && y <= 1690) {
self.showMedalDetails();
}
};
self.move = function (x, y, obj) {
var isOverPlayButton = x >= 824 && x <= 1224 && y >= 1190 && y <= 1310;
if (isOverPlayButton && !self.playButtonHover) {
self.playButtonHover = true;
tween(playBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverPlayButton && self.playButtonHover) {
self.playButtonHover = false;
tween(playBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over deck button
var isOverDeckButton = x >= 824 && x <= 1224 && y >= 1440 && y <= 1560;
if (isOverDeckButton && !self.deckButtonHover) {
self.deckButtonHover = true;
tween(deckBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverDeckButton && self.deckButtonHover) {
self.deckButtonHover = false;
tween(deckBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over wiki button
var isOverWikiButton = x >= 824 && x <= 1224 && y >= 1960 && y <= 2040;
if (isOverWikiButton && !self.wikiButtonHover) {
self.wikiButtonHover = true;
tween(wikiBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverWikiButton && self.wikiButtonHover) {
self.wikiButtonHover = false;
tween(wikiBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.startGame = function () {
// Fade out menu
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove menu and show difficulty selection
game.removeChild(self);
self.showDifficultySelection();
}
});
};
// Entrance animation
self.alpha = 0;
self.scaleX = 0.8;
self.scaleY = 0.8;
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeOut
});
// Title pulse 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() {
// Restart pulse animation
self.titlePulse();
}
});
}
});
self.showDeckView = function () {
// Create and show deck view
var deckView = new DeckView();
game.addChild(deckView);
};
self.showWikiView = function () {
// Create and show wiki view
var wikiView = new WikiView();
game.addChild(wikiView);
};
self.showDifficultySelection = function () {
// Create and show difficulty selection
var difficultySelection = new DifficultySelection();
game.addChild(difficultySelection);
};
self.titlePulse = function () {
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() {
self.titlePulse();
}
});
}
});
};
self.startTrainingMode = function () {
// Fade out menu
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove menu and start training
game.removeChild(self);
self.showTrainingMode();
}
});
};
self.showTrainingMode = function () {
// Create and show training mode
var trainingMode = new TrainingMode();
game.addChild(trainingMode);
};
self.showTrainingModeSelection = function () {
// Create overlay for training mode selection
var trainingOverlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.8
});
// Training mode title
var trainingTitle = new Text2("OYUN MODU SEÇİN", {
size: 80,
fill: 0xf39c12
});
trainingTitle.anchor.set(0.5, 0.5);
trainingTitle.x = 1024;
trainingTitle.y = 800;
self.addChild(trainingTitle);
// Training mode button
var trainingBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1100,
tint: 0x27ae60
});
var trainingBtnText = new Text2("ANTRENMAN", {
size: 48,
fill: 0xffffff
});
trainingBtnText.anchor.set(0.5, 0.5);
trainingBtnText.x = 1024;
trainingBtnText.y = 1100;
self.addChild(trainingBtnText);
// Play game button
var playGameBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1350,
tint: 0x3498db
});
var playGameBtnText = new Text2("OYUNA BAŞLA", {
size: 48,
fill: 0xffffff
});
playGameBtnText.anchor.set(0.5, 0.5);
playGameBtnText.x = 1024;
playGameBtnText.y = 1350;
self.addChild(playGameBtnText);
// Back button
var backBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1600,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x95a5a6
});
var backBtnText = new Text2("GERİ", {
size: 40,
fill: 0xffffff
});
backBtnText.anchor.set(0.5, 0.5);
backBtnText.x = 1024;
backBtnText.y = 1600;
self.addChild(backBtnText);
// Button hover tracking
var trainingBtnHover = false;
var playGameBtnHover = false;
var backBtnHover = false;
// Override down handler for training mode selection
var originalDown = self.down;
self.down = function (x, y, obj) {
// Check if training button was clicked
if (x >= 824 && x <= 1224 && y >= 1040 && y <= 1160) {
// Button press effect
tween(trainingBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x2ecc71
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(trainingBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x27ae60
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Start training mode
LK.setTimeout(function () {
self.removeTrainingOverlay();
self.startTrainingMode();
}, 200);
}
// Check if play game button was clicked
else if (x >= 824 && x <= 1224 && y >= 1290 && y <= 1410) {
// Button press effect
tween(playGameBtn, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playGameBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Start game
LK.setTimeout(function () {
self.removeTrainingOverlay();
self.startGame();
}, 200);
}
// Check if back button was clicked
else if (x >= 904 && x <= 1144 && y >= 1560 && y <= 1640) {
// Button press effect
tween(backBtn, {
scaleX: 0.75,
scaleY: 0.75,
tint: 0x7f8c8d
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(backBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x95a5a6
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Go back to main menu
LK.setTimeout(function () {
self.removeTrainingOverlay();
}, 200);
}
};
// Override move handler for training mode selection
var originalMove = self.move;
self.move = function (x, y, obj) {
// Check if mouse is over training button
var isOverTrainingButton = x >= 824 && x <= 1224 && y >= 1040 && y <= 1160;
if (isOverTrainingButton && !trainingBtnHover) {
trainingBtnHover = true;
tween(trainingBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0x2ecc71
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverTrainingButton && trainingBtnHover) {
trainingBtnHover = false;
tween(trainingBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x27ae60
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over play game button
var isOverPlayGameButton = x >= 824 && x <= 1224 && y >= 1290 && y <= 1410;
if (isOverPlayGameButton && !playGameBtnHover) {
playGameBtnHover = true;
tween(playGameBtn, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverPlayGameButton && playGameBtnHover) {
playGameBtnHover = false;
tween(playGameBtn, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
// Check if mouse is over back button
var isOverBackButton = x >= 904 && x <= 1144 && y >= 1560 && y <= 1640;
if (isOverBackButton && !backBtnHover) {
backBtnHover = true;
tween(backBtn, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0xbdc3c7
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverBackButton && backBtnHover) {
backBtnHover = false;
tween(backBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x95a5a6
}, {
duration: 200,
easing: tween.easeOut
});
}
};
// Store references for cleanup
self.trainingModeOverlay = {
overlay: trainingOverlay,
title: trainingTitle,
trainingBtn: trainingBtn,
trainingBtnText: trainingBtnText,
playGameBtn: playGameBtn,
playGameBtnText: playGameBtnText,
backBtn: backBtn,
backBtnText: backBtnText,
originalDown: originalDown,
originalMove: originalMove
};
};
self.removeTrainingOverlay = function () {
if (self.trainingModeOverlay) {
// Restore original event handlers
self.down = self.trainingModeOverlay.originalDown;
self.move = self.trainingModeOverlay.originalMove;
// Remove overlay elements
self.removeChild(self.trainingModeOverlay.overlay);
self.removeChild(self.trainingModeOverlay.title);
self.removeChild(self.trainingModeOverlay.trainingBtn);
self.removeChild(self.trainingModeOverlay.trainingBtnText);
self.removeChild(self.trainingModeOverlay.playGameBtn);
self.removeChild(self.trainingModeOverlay.playGameBtnText);
self.removeChild(self.trainingModeOverlay.backBtn);
self.removeChild(self.trainingModeOverlay.backBtnText);
self.trainingModeOverlay = null;
}
};
self.showMedalDetails = function () {
// Get win counts for each difficulty
var easyWins = storage.easyWins || 0;
var mediumWins = storage.mediumWins || 0;
var hardWins = storage.hardWins || 0;
// Create medal details view
var medalView = new MedalDetailsView(easyWins, mediumWins, hardWins);
game.addChild(medalView);
};
return self;
});
var MedalDetailsView = Container.expand(function (easyWins, mediumWins, hardWins) {
var self = Container.call(this);
// Dark overlay background
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.9
});
// Title
var titleText = new Text2("MADALYA İSTATİSTİKLERİ", {
size: 80,
fill: 0xf39c12
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
self.addChild(titleText);
// Easy difficulty stats
var easyText = new Text2("KOLAY: " + easyWins + " galibiyet", {
size: 56,
fill: 0x27ae60
});
easyText.anchor.set(0.5, 0.5);
easyText.x = 1024;
easyText.y = 1000;
self.addChild(easyText);
// Medium difficulty stats
var mediumText = new Text2("ORTA: " + mediumWins + " galibiyet", {
size: 56,
fill: 0xf39c12
});
mediumText.anchor.set(0.5, 0.5);
mediumText.x = 1024;
mediumText.y = 1200;
self.addChild(mediumText);
// Hard difficulty stats
var hardText = new Text2("ZOR: " + hardWins + " galibiyet", {
size: 56,
fill: 0xe74c3c
});
hardText.anchor.set(0.5, 0.5);
hardText.x = 1024;
hardText.y = 1400;
self.addChild(hardText);
// Total wins
var totalWins = easyWins + mediumWins + hardWins;
var totalText = new Text2("TOPLAM: " + totalWins + " galibiyet", {
size: 64,
fill: 0xecf0f1
});
totalText.anchor.set(0.5, 0.5);
totalText.x = 1024;
totalText.y = 1650;
self.addChild(totalText);
// Close button
var closeBtn = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2000,
scaleX: 0.8,
scaleY: 0.8
});
var closeBtnText = new Text2("KAPAT", {
size: 48,
fill: 0xffffff
});
closeBtnText.anchor.set(0.5, 0.5);
closeBtnText.x = 1024;
closeBtnText.y = 2000;
self.addChild(closeBtnText);
self.closeButtonHover = false;
self.down = function (x, y, obj) {
// Check if close button was clicked
if (x >= 824 && x <= 1224 && y >= 1960 && y <= 2040) {
// Button press effect
tween(closeBtn, {
scaleX: 0.75,
scaleY: 0.75,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(closeBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Close medal details view after animation
LK.setTimeout(function () {
self.closeMedalView();
}, 200);
}
};
self.move = function (x, y, obj) {
// Check if mouse is over close button
var isOverCloseButton = x >= 824 && x <= 1224 && y >= 1960 && y <= 2040;
if (isOverCloseButton && !self.closeButtonHover) {
self.closeButtonHover = true;
tween(closeBtn, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverCloseButton && self.closeButtonHover) {
self.closeButtonHover = false;
tween(closeBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.closeMedalView = function () {
// Fade out medal view
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove medal view
game.removeChild(self);
}
});
};
// Entrance animation
self.alpha = 0;
self.scaleX = 0.8;
self.scaleY = 0.8;
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeOut
});
return self;
});
var OpeningScreen = Container.expand(function () {
var self = Container.call(this);
// Dark background
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.95
});
// "inspired by Waldo" text
var inspiredText = new Text2("inspired by Waldo", {
size: 80,
fill: 0x3498db
});
inspiredText.anchor.set(0.5, 0.5);
inspiredText.x = 1024;
inspiredText.y = 1366;
inspiredText.alpha = 0;
self.addChild(inspiredText);
// Fade in animation
self.alpha = 0;
tween(self, {
alpha: 1.0
}, {
duration: 800,
easing: tween.easeOut
});
// Fade in the text
tween(inspiredText, {
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hold for 2 seconds, then fade out
LK.setTimeout(function () {
tween(self, {
alpha: 0
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove opening screen and show main menu
game.removeChild(self);
showMainMenu();
}
});
}, 2000);
}
});
// Allow clicking to skip
self.down = function (x, y, obj) {
// Skip opening and go to main menu
tween(self, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
game.removeChild(self);
showMainMenu();
}
});
};
return self;
});
var Player = Container.expand(function (isHuman) {
var self = Container.call(this);
self.isHuman = isHuman || false;
// Set health based on difficulty and player type
if (gameDifficulty === "easy") {
self.health = isHuman ? 20 : 15; // Player: 20, AI: 15 on easy
} else if (gameDifficulty === "medium") {
self.health = 20; // Both players have 20 health on medium
} else if (gameDifficulty === "hard") {
self.health = isHuman ? 20 : 25; // Player: 20, AI: 25 on hard
} else {
self.health = 20; // Default fallback
}
self.maxMana = 12;
self.currentMana = isHuman ? 3 : 0;
self.hand = [];
self.battlefield = [];
self.deck = [];
self.spells = [];
// Initialize with Fire Ball spell
var fireBallSpell = new Spell({
name: "Fire Ball",
cost: 2,
damage: 2,
target: "enemy",
description: "Deals 2 damage to target"
});
self.spells.push(fireBallSpell);
// Add heal spell
var healSpell = new Spell({
name: "Şifa",
cost: 2,
damage: -2,
// Negative damage for healing
target: "ally",
description: "Heals target for 2 health"
});
self.spells.push(healSpell);
// Add freeze spell
var freezeSpell = new Spell({
name: "Freeze",
cost: 2,
damage: 0,
target: "enemy",
description: "Freezes target enemy for 1 turn"
});
self.spells.push(freezeSpell);
// AI player also gets spells if not human
if (!isHuman) {
var aiFireBallSpell = new Spell({
name: "Fire Ball",
cost: 2,
damage: 2,
target: "enemy",
description: "Deals 2 damage to target"
});
self.spells.push(aiFireBallSpell);
}
// Initialize deck with basic cards
var cardTypes = [{
name: "Fire Imp",
cost: 3,
attack: 2,
health: 5,
description: "A small fire creature"
}, {
name: "Water Spirit",
cost: 2,
attack: 2,
health: 4,
description: "A defensive water creature"
}, {
name: "Earth Golem",
cost: 3,
attack: 1,
health: 10,
description: "A powerful earth creature"
}, {
name: "Air Wisp",
cost: 1,
attack: 1,
health: 3,
description: "A quick air creature"
}, {
name: "Lightning Bolt",
cost: 2,
attack: 1,
health: 5,
description: "A shocking creature"
}, {
name: "Lucifer",
cost: 4,
attack: 3,
health: 6,
description: "A mystical water spirit with high endurance"
}, {
name: "Shadow Drake",
cost: 3,
attack: 3,
health: 4,
description: "A powerful shadow dragon"
}, {
name: "Michael Demiurgos",
cost: 4,
attack: 2,
health: 7,
description: "An archangel with divine power"
}, {
name: "Frost Wolf",
cost: 3,
attack: 2,
health: 6,
description: "A fierce ice wolf with freezing attacks",
passive: "frost"
}, {
name: "Phoenix",
cost: 4,
attack: 3,
health: 4,
description: "A legendary fire bird that can rise from ashes",
passive: "rebirth"
}, {
name: "Void Stalker",
cost: 3,
attack: 2,
health: 5,
description: "A shadowy creature from the void with teleportation abilities",
passive: "void"
}, {
name: "Crystal Guardian",
cost: 4,
attack: 1,
health: 8,
description: "A mystical crystal protector that shields nearby allies",
passive: "crystal_shield"
}];
// 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();
// Trigger played passive
card.triggerPassive("played", {
player: self
});
// Check for class synergy activation
var cardClass = getCardClass(card.cardData.name);
var sameClassCount = 0;
for (var i = 0; i < self.battlefield.length; i++) {
if (getCardClass(self.battlefield[i].cardData.name) === cardClass) {
sameClassCount++;
}
}
// Show synergy effect if 2 or more cards of same class
if (sameClassCount >= 2) {
// Create synergy activation text
var synergyText = new Text2("SINERJI AKTIF: " + cardClass.toUpperCase(), {
size: 40,
fill: 0xFFD700
});
synergyText.anchor.set(0.5, 0.5);
synergyText.x = 1024;
synergyText.y = self.isHuman ? 1300 : 500;
synergyText.alpha = 0;
game.addChild(synergyText);
// Animate synergy text
tween(synergyText, {
alpha: 1.0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(synergyText, {
alpha: 0,
y: synergyText.y - 50
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
game.removeChild(synergyText);
}
});
}
});
// Flash all cards of same class
for (var i = 0; i < self.battlefield.length; i++) {
if (getCardClass(self.battlefield[i].cardData.name) === cardClass) {
LK.effects.flashObject(self.battlefield[i], 0xFFD700, 800);
}
}
}
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 () {
// Dynamic mana gain based on turn number
var displayTurn = Math.floor(turnCounter / 2) + 1; // Calculate actual turn number
var manaGain = 1; // Default base mana gain
var bonusMana = 0; // Bonus mana every 3rd turn
var isThirdTurn = displayTurn % 3 === 0;
if (displayTurn > 20) {
// After turn 20: 3 mana per turn, 4 mana every 3rd turn
manaGain = 3;
bonusMana = isThirdTurn ? 1 : 0; // +1 bonus every 3rd turn (total 4)
} else if (displayTurn > 10) {
// After turn 10: 2 mana per turn, 3 mana every 3rd turn
manaGain = 2;
bonusMana = isThirdTurn ? 1 : 0; // +1 bonus every 3rd turn (total 3)
} else {
// First 10 turns: 1 mana per turn, 2 mana every 3rd turn
manaGain = 1;
bonusMana = isThirdTurn ? 1 : 0; // +1 bonus every 3rd turn (total 2)
}
var totalManaGain = manaGain + bonusMana;
self.currentMana = Math.min(self.maxMana, self.currentMana + totalManaGain);
// Max mana is always 12, no need to increment
// Reset battlefield cards and trigger turn start passives
for (var i = 0; i < self.battlefield.length; i++) {
self.battlefield[i].resetForNewTurn();
// Tank synergy now provides static health bonus instead of regeneration
self.battlefield[i].triggerPassive("turn_start", {
player: self
});
// Handle stealth countdown
if (self.battlefield[i].stealthTurns > 0) {
self.battlefield[i].stealthTurns--;
if (self.battlefield[i].stealthTurns <= 0) {
self.battlefield[i].alpha = 1.0; // Return to normal visibility
}
}
}
// 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: 2,
target: "enemy",
// "enemy", "ally", "self"
description: "Deals 2 damage to target"
};
self.isUsable = false;
// Create spell graphics
var spellBg = self.attachAsset('spellSlot', {
anchorX: 0.5,
anchorY: 0.5
});
// Choose appropriate spell icon based on spell name
var spellAssetName = 'fireballSpell'; // default
if (self.spellData.name === "Şifa") {
spellAssetName = 'healSpell';
} else if (self.spellData.name === "Freeze") {
spellAssetName = 'freezeSpell';
}
var spellIcon = self.attachAsset(spellAssetName, {
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;
// Play appropriate sound based on spell type
if (self.spellData.name === "Şifa") {
LK.getSound('healSound').play();
} else {
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 projectileAsset = 'fireballSpell'; // default
if (self.spellData.name === "Şifa") {
projectileAsset = 'healSpell';
} else if (self.spellData.name === "Freeze") {
projectileAsset = 'manaOrb'; // Use mana orb for snow effect
}
var projectile = game.addChild(LK.getAsset(projectileAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
tint: self.spellData.name === "Freeze" ? 0x87CEEB : 0xFFFFFF // Light blue tint for freeze
}));
var targetX = target ? target.x : 1024 + (Math.random() - 0.5) * 200;
var targetY = target ? target.y : aiPlayer.battlefield.length > 0 ? 650 : 300;
// Create snow particle trail for freeze spell
if (self.spellData.name === "Freeze") {
for (var snowFlake = 0; snowFlake < 6; snowFlake++) {
var snow = game.addChild(LK.getAsset('manaOrb', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + (Math.random() - 0.5) * 100,
y: self.y + (Math.random() - 0.5) * 100,
scaleX: 0.2,
scaleY: 0.2,
alpha: 0.8,
tint: 0xFFFFFF // White snow
}));
// Animate snow particles following the projectile
tween(snow, {
x: targetX + (Math.random() - 0.5) * 120,
y: targetY + (Math.random() - 0.5) * 120,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0,
rotation: Math.PI * (Math.random() - 0.5)
}, {
duration: 500 + snowFlake * 100,
easing: tween.easeOut,
onFinish: function onFinish() {
if (game.children.includes(snow)) {
game.removeChild(snow);
}
}
});
}
}
// 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 damage, healing, and freeze spells
if (target && target.takeDamage && target.isOnBattlefield) {
if (self.spellData.name === "Freeze") {
// Freeze spell
target.frozenTurns = 3;
// Play freeze sound effect
LK.getSound('freezeSound').play();
// Create ice crystal effects around the target
for (var crystal = 0; crystal < 8; crystal++) {
var iceEffect = game.addChild(LK.getAsset('manaOrb', {
anchorX: 0.5,
anchorY: 0.5,
x: target.x + Math.cos(crystal * Math.PI / 4) * 80,
y: target.y + Math.sin(crystal * Math.PI / 4) * 80,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0.9,
tint: 0x87CEEB
}));
// Animate ice crystals converging to target
tween(iceEffect, {
x: target.x,
y: target.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 600 + crystal * 50,
easing: tween.easeIn,
onFinish: function onFinish() {
if (game.children.includes(iceEffect)) {
game.removeChild(iceEffect);
}
}
});
}
// Create freeze burst effect at target
var freezeBurst = game.addChild(LK.getAsset('manaOrb', {
anchorX: 0.5,
anchorY: 0.5,
x: target.x,
y: target.y,
scaleX: 0.5,
scaleY: 0.5,
alpha: 1.0,
tint: 0x00BFFF
}));
// Animate freeze burst expanding and fading
tween(freezeBurst, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(freezeBurst);
}
});
// Apply visual freeze effect to target with blue tint
target.alpha = 0.7; // Slightly transparent
tween(target, {
tint: 0x87CEEB
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Pulsing freeze effect
var _freezePulse = function freezePulse() {
if (target.frozenTurns > 0) {
tween(target, {
alpha: 0.5,
tint: 0x00BFFF
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(target, {
alpha: 0.7,
tint: 0x87CEEB
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (target.frozenTurns > 0) {
_freezePulse();
}
}
});
}
});
}
};
_freezePulse();
}
});
// Create freeze visual effect text
var freezeText = new Text2("DONDU!", {
size: 45,
fill: 0x00ffff
});
freezeText.anchor.set(0.5, 0.5);
freezeText.x = target.x + (Math.random() - 0.5) * 60;
freezeText.y = target.y - 50;
freezeText.alpha = 1.0;
game.addChild(freezeText);
// Animate freeze text with ice effect
tween(freezeText, {
y: freezeText.y - 100,
alpha: 0,
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI * 0.1
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(freezeText);
}
});
// Screen flash with icy blue color
LK.effects.flashScreen(0x00BFFF, 400);
} else 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;
});
var TrainingMode = Container.expand(function () {
var self = Container.call(this);
// Training mode state
var currentStep = 0;
var maxSteps = 10;
var tutorialCards = [];
var tutorialSpells = [];
var tutorialPlayer = null;
var tutorialAI = null;
var highlightOverlay = null;
var instructionText = null;
var skipButton = null;
var nextButton = null;
var isWaitingForAction = false;
// Dark overlay background
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.7
});
// Title
var titleText = new Text2("ANTRENMAN MODU", {
size: 80,
fill: 0x27ae60
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
self.addChild(titleText);
// Progress indicator
var progressText = new Text2("Adım 1 / " + maxSteps, {
size: 48,
fill: 0xf39c12
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 1024;
progressText.y = 300;
self.addChild(progressText);
// Instruction text
instructionText = new Text2("Antrenman moduna hoş geldiniz!", {
size: 44,
fill: 0xecf0f1
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1366;
self.addChild(instructionText);
// Skip button
skipButton = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 150,
scaleX: 0.6,
scaleY: 0.6,
tint: 0x95a5a6
});
var skipBtnText = new Text2("ATLA", {
size: 32,
fill: 0xffffff
});
skipBtnText.anchor.set(0.5, 0.5);
skipBtnText.x = 200;
skipBtnText.y = 150;
self.addChild(skipBtnText);
// Next button
nextButton = self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2400,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x27ae60
});
var nextBtnText = new Text2("DEVAM", {
size: 40,
fill: 0xffffff
});
nextBtnText.anchor.set(0.5, 0.5);
nextBtnText.x = 1024;
nextBtnText.y = 2400;
self.addChild(nextBtnText);
// Initialize tutorial
self.initializeTutorial = function () {
// Create simplified tutorial player
tutorialPlayer = new Player(true);
tutorialPlayer.health = 20;
tutorialPlayer.currentMana = 5;
tutorialPlayer.maxMana = 12;
// Create simplified tutorial AI
tutorialAI = new Player(false);
tutorialAI.health = 15;
tutorialAI.currentMana = 3;
tutorialAI.maxMana = 12;
// Create tutorial cards
var fireImp = new Card({
name: "Fire Imp",
cost: 3,
attack: 2,
health: 5,
description: "Eğitim için basit bir ateş yaratığı",
passive: "burn"
});
var waterSpirit = new Card({
name: "Water Spirit",
cost: 2,
attack: 2,
health: 4,
description: "Eğitim için basit bir su ruhu",
passive: "heal"
});
tutorialCards = [fireImp, waterSpirit];
tutorialPlayer.hand = tutorialCards.slice();
// Create tutorial spells
var fireBall = new Spell({
name: "Fire Ball",
cost: 2,
damage: 2,
target: "enemy",
description: "Eğitim için basit bir ateş büyüsü"
});
tutorialSpells = [fireBall];
tutorialPlayer.spells = tutorialSpells.slice();
// Create end turn button for training mode
var endTurnBtn = self.attachAsset('endTurnButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1800,
y: 1950
});
var endTurnText = new Text2("TURU GEÇER", {
size: 28,
fill: 0x2C3E50
});
endTurnText.anchor.set(0.5, 0.5);
endTurnText.x = 1800;
endTurnText.y = 1950;
self.addChild(endTurnText);
// Store references for cleanup
self.endTurnBtn = endTurnBtn;
self.endTurnText = endTurnText;
// Start first step
self.showStep(0);
};
self.showStep = function (step) {
currentStep = step;
progressText.setText("Adım " + (step + 1) + " / " + maxSteps);
isWaitingForAction = false;
// Clear previous highlights
self.clearHighlights();
switch (step) {
case 0:
instructionText.setText("Hoş geldiniz! Bu oyunun temel kurallarını öğrenelim.");
break;
case 1:
instructionText.setText("Bu ekranın alt kısmında elinizde bulunan kartlar vardır.");
self.highlightArea(0, 2200, 2048, 532);
break;
case 2:
instructionText.setText("Kartların üzerindeki mor sayı MANA maliyetini gösterir.");
self.highlightCard(tutorialCards[0]);
break;
case 3:
instructionText.setText("Kırmızı sayı SALDIRI gücünü, yeşil sayı CAN miktarını gösterir.");
self.highlightCard(tutorialCards[0]);
break;
case 4:
instructionText.setText("Kartları oyun alanına sürükleyerek oynayabilirsiniz.");
self.showPlayArea();
isWaitingForAction = true;
break;
case 5:
instructionText.setText("Sol taraftaki mor slotlar büyülerinizi gösterir.");
self.highlightArea(50, 2000, 200, 400);
break;
case 6:
instructionText.setText("Büyüleri düşman kartlarına sürükleyerek kullanabilirsiniz.");
break;
case 7:
instructionText.setText("Aynı sınıftan 2 kart oynadığınızda sinerji bonusu alırsınız.");
break;
case 8:
instructionText.setText("Sağ alttaki 'End Turn' butonu ile turu geçebilirsiniz.");
self.highlightArea(1700, 1910, 200, 80);
break;
case 9:
instructionText.setText("Tebrikler! Artık oyuna hazırsınız. Ana menüye dönelim.");
nextBtnText.setText("TAMAMLA");
break;
}
// Show/hide next button based on step
if (step < maxSteps - 1) {
nextButton.alpha = isWaitingForAction ? 0.5 : 1.0;
} else {
nextButton.alpha = 1.0;
}
};
self.highlightArea = function (x, y, width, height) {
self.clearHighlights();
highlightOverlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: x,
y: y,
alpha: 0.3,
tint: 0xFFD700
});
highlightOverlay.width = width;
highlightOverlay.height = height;
};
self.highlightCard = function (card) {
if (card && game.children.includes(card)) {
LK.effects.flashObject(card, 0xFFD700, 2000);
}
};
self.showPlayArea = function () {
// Show lane areas
self.highlightArea(380, 700, 1288, 650);
};
self.clearHighlights = function () {
if (highlightOverlay) {
self.removeChild(highlightOverlay);
highlightOverlay = null;
}
};
self.down = function (x, y, obj) {
// Check if skip button was clicked
if (x >= 140 && x <= 260 && y >= 120 && y <= 180) {
self.completeTutorial();
return;
}
// Check if next button was clicked
if (x >= 824 && x <= 1224 && y >= 2360 && y <= 2440) {
if (currentStep < maxSteps - 1) {
self.showStep(currentStep + 1);
} else {
self.completeTutorial();
}
return;
}
// Check if end turn button was clicked
if (x >= 1700 && x <= 1900 && y >= 1910 && y <= 1990) {
// Show tutorial message about end turn
instructionText.setText("Turu geçtiniz! Bu butonu kullanarak rakibin sırasına geçebilirsiniz.");
// Advance to next step if this was part of tutorial
if (currentStep < maxSteps - 1) {
LK.setTimeout(function () {
self.showStep(currentStep + 1);
}, 1500);
}
return;
}
// Handle tutorial interactions
if (isWaitingForAction && currentStep === 4) {
// Check if user tried to drag a card to play area
for (var i = 0; i < tutorialCards.length; i++) {
var card = tutorialCards[i];
if (x >= card.x - 90 && x <= card.x + 90 && y >= card.y - 125 && y <= card.y + 125) {
instructionText.setText("Harika! Kartı oyun alanına sürüklemeyi deneyin.");
isWaitingForAction = false;
nextButton.alpha = 1.0;
return;
}
}
}
};
self.completeTutorial = function () {
// Mark tutorial as completed
storage.tutorialCompleted = true;
// Fade out training mode
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove training mode and return to menu
game.removeChild(self);
showMainMenu();
}
});
};
// Initialize tutorial on creation
self.initializeTutorial();
// Entrance animation
self.alpha = 0;
self.scaleX = 0.8;
self.scaleY = 0.8;
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeOut
});
return self;
});
var WikiView = Container.expand(function () {
var self = Container.call(this);
// Dark overlay background
var overlay = self.attachAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.9
});
// Title
var titleText = new Text2("OYUN REHBERİ", {
size: 80,
fill: 0xf39c12
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
self.addChild(titleText);
// Game rules section
var rulesTitle = new Text2("OYUN KURALLARI", {
size: 60,
fill: 0x3498db
});
rulesTitle.anchor.set(0.5, 0.5);
rulesTitle.x = 1024;
rulesTitle.y = 350;
self.addChild(rulesTitle);
// Rules text
var rulesText = new Text2("• Her oyuncu 3 lane'de kart oynayabilir\n• Kartları sürükleyerek lane'lere yerleştirin\n• Büyüleri düşman/müttefik kartlara hedefleyin\n• Mana her tur otomatik olarak yenilenir\n• Rakibin canını 0'a düşürün\n• Karakterlerin üstündeki yeşil sayı CAN, kırmızı HASAR, mor MANA", {
size: 36,
fill: 0xbdc3c7
});
rulesText.anchor.set(0.5, 0.5);
rulesText.x = 1024;
rulesText.y = 550;
self.addChild(rulesText);
// Class synergy section
var synergyTitle = new Text2("SINIF SİNERJİLERİ", {
size: 60,
fill: 0x9b59b6
});
synergyTitle.anchor.set(0.5, 0.5);
synergyTitle.x = 1024;
synergyTitle.y = 800;
self.addChild(synergyTitle);
// Synergy explanation
var synergyText = new Text2("2 veya daha fazla aynı sınıf kartı ile sinerji bonusları:\n\n• TANK: +1 Can (Her Tank kartı için)\n• MAGE: %25 şans ile 2x hasar\n• ROGUE: %20 Dodge şansı\n• WARRIOR: Air Wisp %60 kaçınma", {
size: 36,
fill: 0xbdc3c7
});
synergyText.anchor.set(0.5, 0.5);
synergyText.x = 1024;
synergyText.y = 1100;
self.addChild(synergyText);
// Spell section
var spellTitle = new Text2("BÜYÜLER", {
size: 60,
fill: 0xe74c3c
});
spellTitle.anchor.set(0.5, 0.5);
spellTitle.x = 1024;
spellTitle.y = 1400;
self.addChild(spellTitle);
// Spell explanation
var spellText = new Text2("• Fire Ball: 2 hasar (Düşman kartlara)\n• Şifa: 2 iyileştirme (Müttefik kartlara)\n• Freeze: 2 mana, 3 tur dondurma (Düşman kartlara)", {
size: 36,
fill: 0xbdc3c7
});
spellText.anchor.set(0.5, 0.5);
spellText.x = 1024;
spellText.y = 1600;
self.addChild(spellText);
// Tips section
var tipsTitle = new Text2("İPUÇLARI", {
size: 60,
fill: 0x27ae60
});
tipsTitle.anchor.set(0.5, 0.5);
tipsTitle.x = 1024;
tipsTitle.y = 1850;
self.addChild(tipsTitle);
// Tips text
var tipsText = new Text2("• Sinerji bonusları için aynı sınıf kartları kullanın\n• Pasif yetenekleri stratejinize dahil edin\n• Büyüleri doğru zamanda kullanın\n• Kartları desteye geri döndürmek için aşağı sürükleyin", {
size: 36,
fill: 0xbdc3c7
});
tipsText.anchor.set(0.5, 0.5);
tipsText.x = 1024;
tipsText.y = 2050;
self.addChild(tipsText);
// Add wiki icon at top
var wikiIcon = self.attachAsset('wikiIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 120,
scaleX: 1.5,
scaleY: 1.5
});
// Add game rules icon
var gameRulesIcon = self.attachAsset('gameRulesIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 350,
scaleX: 1.2,
scaleY: 1.2
});
// Add synergy icon
var synergyIcon = self.attachAsset('synergyIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 800,
scaleX: 1.2,
scaleY: 1.2
});
// Add spell icon
var spellIconAsset = self.attachAsset('spellIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 1400,
scaleX: 1.2,
scaleY: 1.2
});
// Add tips icon
var tipsIcon = self.attachAsset('tipsIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 1850,
scaleX: 1.2,
scaleY: 1.2
});
// Close button
var closeBtn = self.attachAsset('wikiButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2450,
scaleX: 0.8,
scaleY: 0.8
});
var closeBtnText = new Text2("KAPAT", {
size: 48,
fill: 0xffffff
});
closeBtnText.anchor.set(0.5, 0.5);
closeBtnText.x = 1024;
closeBtnText.y = 2450;
self.addChild(closeBtnText);
self.closeButtonHover = false;
self.down = function (x, y, obj) {
// Check if close button was clicked
if (x >= 824 && x <= 1224 && y >= 2410 && y <= 2490) {
// Button press effect
tween(closeBtn, {
scaleX: 0.75,
scaleY: 0.75,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(closeBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Close wiki view after animation
LK.setTimeout(function () {
self.closeWikiView();
}, 200);
}
};
self.move = function (x, y, obj) {
// Check if mouse is over close button
var isOverCloseButton = x >= 824 && x <= 1224 && y >= 2410 && y <= 2490;
if (isOverCloseButton && !self.closeButtonHover) {
self.closeButtonHover = true;
tween(closeBtn, {
scaleX: 0.9,
scaleY: 0.9,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverCloseButton && self.closeButtonHover) {
self.closeButtonHover = false;
tween(closeBtn, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.closeWikiView = function () {
// Fade out wiki view
tween(self, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove wiki view and return to menu
game.removeChild(self);
}
});
};
// Entrance animation
self.alpha = 0;
self.scaleX = 0.8;
self.scaleY = 0.8;
tween(self, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeOut
});
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 gameState = "menu"; // "menu", "playing", "gameOver"
var gameDifficulty = "easy"; // "easy", "medium", "hard" - will be set by difficulty selection
var currentPlayer = 0; // 0 = human, 1 = AI
var gamePhase = "playing"; // "playing", "gameOver"
var mainMenu = null;
var selectedCard = null;
var draggedCard = null;
var turnCounter = 0; // Track total turns taken
var combatPhase = false; // Track if we're in combat phase
var cardsLockedIn = false; // Track if cards are locked in for the turn
// Create players
var humanPlayer = new Player(true);
var aiPlayer = new Player(false);
// Set AI player's starting mana to 2
aiPlayer.currentMana = 2;
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: 20", {
size: 48,
fill: 0xECF0F1
});
playerHealthText.anchor.set(0, 0.5);
playerHealthText.x = 50;
playerHealthText.y = 1950;
game.addChild(playerHealthText);
// Synergy indicator display
var synergyDisplays = {
Tank: null,
Mage: null,
Rogue: null,
Warrior: null
};
var synergyIcons = {
Tank: null,
Mage: null,
Rogue: null,
Warrior: null
};
// Store class feature info
var classFeatures = {
Tank: {
name: "TANK",
feature: "Savunma Odaklı",
synergy: "+1 Can (Her Tank kartı için)",
description: "Tank kartları yüksek can değerleriyle düşman saldırılarını absorbe eder. 2 veya daha fazla Tank kartı aynı anda savaş alanında olduğunda, her Tank kartı sinerji bonusu olarak +1 can kazanır."
},
Mage: {
name: "MAGE",
feature: "Öfkelenme",
synergy: "%25 şans ile 2x hasar (Her Mage kartı için)",
description: "Mage kartları öfkelenme yetisi ile saldırır. 2 veya daha fazla Mage kartı aynı anda savaş alanında olduğunda, her Mage kartı sinerji bonusu olarak %25 şans ile 2x hasar verir."
},
Rogue: {
name: "ROGUE",
feature: "Hızlı ve Çevik",
synergy: "%20 Dodge şansı (Her Rogue kartı için)",
description: "Rogue kartları hız ve çeviklikle saldırılardan kaçınabilir. 2 veya daha fazla Rogue kartı aynı anda savaş alanında olduğunda, her Rogue kartı sinerji bonusu olarak %20 şans ile saldırıları dodge atar."
},
Warrior: {
name: "WARRIOR",
feature: "Savaş Ustası",
synergy: "Air Wisp %60 kaçınma şansı",
description: "Warrior kartları güçlü saldırılarıyla bilinir. 2 veya daha fazla Warrior kartı aynı anda savaş alanında olduğunda, Air Wisp kartının kaçınma şansı %25'ten %60'a çıkar."
},
Vampire: {
name: "VAMPIRE",
feature: "Vampirizm",
synergy: "Verilen hasar kadar can yenileme (Her Vampire kartı için)",
description: "Vampire kartları verdiği hasar kadar can kazanır. 2 veya daha fazla Vampire kartı aynı anda savaş alanında olduğunda, her Vampire kartı hasar verdiğinde verdiği hasar kadar can yeniler."
}
};
// Class feature display variables
var classFeatureDisplay = null;
var isShowingClassFeature = false;
// Create synergy displays
var synergyStartY = 800;
var synergySpacing = 200;
var classNames = ["Tank", "Mage", "Rogue", "Warrior"];
var classAssets = ["tankClass", "mageClass", "rogueClass", "warriorClass"];
for (var i = 0; i < classNames.length; i++) {
var className = classNames[i];
var assetName = classAssets[i];
var yPos = synergyStartY + i * synergySpacing;
// Create class icon
var icon = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: yPos,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}));
synergyIcons[className] = icon;
// Create synergy text
var synergyText = new Text2("", {
size: 36,
fill: 0x95a5a6
});
synergyText.anchor.set(0, 0.5);
synergyText.x = 150;
synergyText.y = yPos;
synergyText.alpha = 0.3;
game.addChild(synergyText);
synergyDisplays[className] = synergyText;
}
var opponentHealthText = new Text2("Enemy: 15", {
size: 48,
fill: 0xECF0F1
});
opponentHealthText.anchor.set(0.5, 0.5);
opponentHealthText.x = 1024;
opponentHealthText.y = 150;
game.addChild(opponentHealthText);
var manaText = new Text2("Mana: 3/12", {
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/12", {
size: 36,
fill: 0x9B59B6
});
aiManaText.anchor.set(0.5, 0.5);
aiManaText.x = 1024;
aiManaText.y = 200;
game.addChild(aiManaText);
var nextTurnManaText = new Text2("Next Turn: +1 Mana", {
size: 36,
fill: 0x9B59B6
});
nextTurnManaText.anchor.set(1, 0.5);
nextTurnManaText.x = 1950;
nextTurnManaText.y = 2100;
game.addChild(nextTurnManaText);
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);
// Turn counter display on right middle side
var turnCounterText = new Text2("Turn: 1", {
size: 38,
fill: 0xECF0F1
});
turnCounterText.anchor.set(0.5, 0.5);
turnCounterText.x = 1800;
turnCounterText.y = 1366;
game.addChild(turnCounterText);
// 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);
// Main menu button
var mainMenuBtn = game.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1600,
y: 150,
scaleX: 0.6,
scaleY: 0.6
}));
var mainMenuBtnText = new Text2("ANA MENÜ", {
size: 20,
fill: 0xffffff
});
mainMenuBtnText.anchor.set(0.5, 0.5);
mainMenuBtnText.x = 1600;
mainMenuBtnText.y = 150;
game.addChild(mainMenuBtnText);
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";
}
// Update next turn mana display
var nextDisplayTurn = Math.floor((turnCounter + 1) / 2) + 1;
var nextManaGain = 1;
var nextBonusMana = 0;
var nextIsThirdTurn = nextDisplayTurn % 3 === 0;
if (nextDisplayTurn > 20) {
// After turn 20: 3 mana per turn, 4 mana every 3rd turn
nextManaGain = 3;
nextBonusMana = nextIsThirdTurn ? 1 : 0;
} else if (nextDisplayTurn > 10) {
// After turn 10: 2 mana per turn, 3 mana every 3rd turn
nextManaGain = 2;
nextBonusMana = nextIsThirdTurn ? 1 : 0;
} else {
// First 10 turns: 1 mana per turn, 2 mana every 3rd turn
nextManaGain = 1;
nextBonusMana = nextIsThirdTurn ? 1 : 0;
}
var totalNextManaGain = nextManaGain + nextBonusMana;
nextTurnManaText.setText("Gelecek Tur: +" + totalNextManaGain + " Mana");
// Update turn counter display
var displayTurn = Math.floor(turnCounter / 2) + 1;
turnCounterText.setText("Turn: " + displayTurn);
}
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 getCardClass(cardName) {
// Determine card class based on name
if (cardName === "Earth Golem" || cardName === "Lightning Bolt") {
return "Tank";
} else if (cardName === "Fire Imp" || cardName === "Water Spirit") {
return "Mage";
} else if (cardName === "Shadow Drake" || cardName === "Michael Demiurgos") {
return "Rogue";
} else if (cardName === "Lucifer" || cardName === "Air Wisp" || cardName === "Frost Wolf") {
return "Warrior";
} else if (cardName === "Phoenix") {
return "Mage";
} else if (cardName === "Void Stalker") {
return "Rogue";
} else if (cardName === "Crystal Guardian") {
return "Tank";
} else if (cardName === "Vampire Lord" || cardName === "Blood Drake") {
return "Vampire";
}
return "None";
}
function calculateClassSynergy(player) {
// Count cards by class on battlefield
var classCounts = {
"Tank": 0,
"Mage": 0,
"Rogue": 0,
"Warrior": 0,
"Vampire": 0
};
for (var i = 0; i < player.battlefield.length; i++) {
var cardClass = getCardClass(player.battlefield[i].cardData.name);
if (classCounts[cardClass] !== undefined) {
classCounts[cardClass]++;
}
}
// Update synergy display only for human player
if (player.isHuman) {
for (var className in synergyDisplays) {
var count = classCounts[className];
var icon = synergyIcons[className];
var display = synergyDisplays[className];
if (count >= 2) {
// Synergy is active
icon.alpha = 1.0;
icon.tint = 0xFFD700; // Gold color for active
display.alpha = 1.0;
display.fill = 0xFFD700;
// Show synergy bonus text
var bonusText = "";
if (className === "Tank") {
bonusText = "+" + count + " Can";
} else if (className === "Mage") {
bonusText = "%25 2x hasar";
} else if (className === "Rogue") {
bonusText = "%20 Dodge şansı";
} else if (className === "Warrior") {
bonusText = "Air Wisp %60 kaçınma";
} else if (className === "Vampire") {
bonusText = "Vampirizm: Hasar=Can";
}
display.setText(className.toUpperCase() + ": " + bonusText);
} else if (count === 1) {
// One card, not active yet
icon.alpha = 0.7;
icon.tint = 0xFFFFFF;
display.alpha = 0.7;
display.fill = 0xbdc3c7;
display.setText(className.toUpperCase() + ": 1/2");
} else {
// No cards
icon.alpha = 0.3;
icon.tint = 0xFFFFFF;
display.alpha = 0.3;
display.fill = 0x95a5a6;
display.setText(className.toUpperCase() + ": 0/2");
}
}
}
// Apply synergy bonuses
for (var i = 0; i < player.battlefield.length; i++) {
var card = player.battlefield[i];
var cardClass = getCardClass(card.cardData.name);
var classCount = classCounts[cardClass];
// Reset to base values first
card.synergyAttackBonus = 0;
card.synergyHealthBonus = 0;
card.synergyRage = false; // Reset rage mechanic
// Apply synergy bonuses based on class count
if (classCount >= 2) {
if (cardClass === "Tank") {
// Tank synergy: +1 health gain per Tank card
card.synergyHealthBonus = classCount; // Tank cards gain health
card.synergyHealthRegen = 0; // No regeneration
} else if (cardClass === "Mage") {
// Mage synergy: 50% chance for 2x damage (rage mechanic)
card.synergyRage = true; // Enable rage for Mage cards with synergy
} else if (cardClass === "Rogue") {
// Rogue synergy: 20% chance to dodge attacks (handled in passive system)
// No stat bonuses for Rogue synergy
} else if (cardClass === "Warrior") {
// Warrior synergy: Air Wisp passive evasion chance increases from 25% to 60%
// No stat bonuses for Warrior synergy - handled in passive system
}
}
}
}
function arrangeBattlefield() {
// Calculate synergies for both players
calculateClassSynergy(humanPlayer);
calculateClassSynergy(aiPlayer);
// 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) {
// Check if either card has taunt - taunt forces combat
var humanDamage = humanCard.cardData.attack + (humanCard.synergyAttackBonus || 0);
var aiDamage = aiCard.cardData.attack + (aiCard.synergyAttackBonus || 0);
// Check if cards are frozen - frozen cards cannot deal damage
if (humanCard.frozenTurns && humanCard.frozenTurns > 0) {
humanDamage = 0; // Frozen cards deal no damage
}
if (aiCard.frozenTurns && aiCard.frozenTurns > 0) {
aiDamage = 0; // Frozen cards deal no damage
}
// Apply Mage rage if applicable (only if not frozen)
if (humanCard.synergyRage && Math.random() < 0.25 && humanDamage > 0) {
humanDamage *= 2;
}
if (aiCard.synergyRage && Math.random() < 0.25 && aiDamage > 0) {
aiDamage *= 2;
}
// 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 - check if frozen first
if (humanCard.frozenTurns && humanCard.frozenTurns > 0) {
// Frozen card cannot attack tower, skip this lane
LK.setTimeout(onComplete, 100);
} else {
// 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 - check if frozen first
if (aiCard.frozenTurns && aiCard.frozenTurns > 0) {
// Frozen card cannot attack tower, skip this lane
LK.setTimeout(onComplete, 100);
} else {
// 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 but check if card is frozen
var actualDamage = 0;
if (!card.frozenTurns || card.frozenTurns <= 0) {
actualDamage = card.cardData.attack;
}
// Flash the tower area only if damage will be dealt
if (actualDamage > 0) {
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();
// Reset game after showing game over
LK.setTimeout(function () {
resetGame();
}, 3000);
return true;
} else if (aiPlayer.health <= 0) {
gamePhase = "gameOver";
// Increment medal count when player wins
var currentMedals = storage.gamesWon || 0;
storage.gamesWon = currentMedals + 1;
// Track wins by difficulty
if (gameDifficulty === "easy") {
var easyWins = storage.easyWins || 0;
storage.easyWins = easyWins + 1;
} else if (gameDifficulty === "medium") {
var mediumWins = storage.mediumWins || 0;
storage.mediumWins = mediumWins + 1;
} else if (gameDifficulty === "hard") {
var hardWins = storage.hardWins || 0;
storage.hardWins = hardWins + 1;
}
LK.showYouWin();
// Reset game after showing you win
LK.setTimeout(function () {
resetGame();
}, 3000);
return true;
}
return false;
}
function resetGame() {
// Reset game state
gameState = "menu";
gamePhase = "playing";
currentPlayer = 0;
turnCounter = 0;
combatPhase = false;
// Remove all cards from display before resetting arrays
var allCards = humanPlayer.hand.concat(humanPlayer.battlefield).concat(aiPlayer.hand).concat(aiPlayer.battlefield);
for (var i = 0; i < allCards.length; i++) {
if (game.children.includes(allCards[i])) {
game.removeChild(allCards[i]);
}
}
// Remove all spells from display
for (var i = 0; i < humanPlayer.spells.length; i++) {
if (game.children.includes(humanPlayer.spells[i])) {
game.removeChild(humanPlayer.spells[i]);
}
}
for (var i = 0; i < aiPlayer.spells.length; i++) {
if (game.children.includes(aiPlayer.spells[i])) {
game.removeChild(aiPlayer.spells[i]);
}
}
// Reset players with difficulty-based health
if (gameDifficulty === "easy") {
humanPlayer.health = 20;
aiPlayer.health = 15;
} else if (gameDifficulty === "medium") {
humanPlayer.health = 20;
aiPlayer.health = 20;
} else if (gameDifficulty === "hard") {
humanPlayer.health = 20;
aiPlayer.health = 25;
} else {
humanPlayer.health = 20;
aiPlayer.health = 20;
}
// Reset turn counter display
turnCounterText.setText("Turn: 1");
humanPlayer.currentMana = 3;
humanPlayer.maxMana = 12;
humanPlayer.hand = [];
humanPlayer.battlefield = [];
humanPlayer.deck = [];
aiPlayer.currentMana = 0;
aiPlayer.maxMana = 12;
aiPlayer.hand = [];
aiPlayer.battlefield = [];
aiPlayer.deck = [];
// Initialize deck with basic cards
var cardTypes = [{
name: "Fire Imp",
cost: 3,
attack: 2,
health: 5,
description: "A small fire creature",
passive: "burn" // Burns enemy for 1 damage at end of turn
}, {
name: "Water Spirit",
cost: 2,
attack: 2,
health: 4,
description: "A defensive water creature",
passive: "heal" // Heals 1 health at start of turn
}, {
name: "Earth Golem",
cost: 3,
attack: 1,
health: 10,
description: "A powerful earth creature",
passive: "taunt" // Forces enemies to attack this card first
}, {
name: "Air Wisp",
cost: 1,
attack: 1,
health: 3,
description: "A quick air creature",
passive: "evasion" // 25% chance to dodge attacks
}, {
name: "Lightning Bolt",
cost: 2,
attack: 1,
health: 5,
description: "A shocking creature",
passive: "shock" // Deals 3 damage to all enemies when played
}, {
name: "Lucifer",
cost: 4,
attack: 3,
health: 6,
description: "A mystical water spirit with high endurance",
passive: "lifesteal" // Already implemented: heals when dealing damage
}, {
name: "Shadow Drake",
cost: 3,
attack: 3,
health: 4,
description: "A powerful shadow dragon",
passive: "stealth"
}, {
name: "Michael Demiurgos",
cost: 4,
attack: 2,
health: 7,
description: "An archangel with divine power",
passive: "divine_shield" // Ignores first damage taken
}, {
name: "Frost Wolf",
cost: 3,
attack: 2,
health: 6,
description: "A fierce ice wolf with freezing attacks",
passive: "frost" // Slows enemy cards when attacking
}, {
name: "Phoenix",
cost: 4,
attack: 3,
health: 4,
description: "A legendary fire bird that can rise from ashes",
passive: "rebirth" // Revives once when destroyed
}, {
name: "Void Stalker",
cost: 3,
attack: 2,
health: 5,
description: "A shadowy creature from the void with teleportation abilities",
passive: "void" // Teleports to different lane when taking damage
}, {
name: "Crystal Guardian",
cost: 4,
attack: 1,
health: 8,
description: "A mystical crystal protector that shields nearby allies",
passive: "crystal_shield" // Reduces damage taken by all friendly cards by 1
}];
// Recreate decks for both players
for (var p = 0; p < 2; p++) {
var player = p === 0 ? humanPlayer : aiPlayer;
for (var i = 0; i < cardTypes.length; i++) {
var newCard = new Card(cardTypes[i]);
newCard.validateStats();
player.deck.push(newCard);
}
// Shuffle deck
for (var i = player.deck.length - 1; i > 0; i--) {
var randomIndex = Math.floor(Math.random() * (i + 1));
var temp = player.deck[i];
player.deck[i] = player.deck[randomIndex];
player.deck[randomIndex] = temp;
}
}
// Clear any remaining display elements
selectedCard = null;
draggedCard = null;
// Show main menu
showMainMenu();
}
function endTurn() {
// Lock in cards for current turn - no more returns to deck allowed
cardsLockedIn = true;
// 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;
// Reset cards locked in flag for new turn
cardsLockedIn = false;
// New turn system: Each player gets one full turn, then combat
// Human starts (currentPlayer 0), then AI (currentPlayer 1), then combat
if (turnCounter % 2 === 0) {
// After both players have taken a turn, enter combat phase
combatPhase = true;
turnText.setText("Combat Phase");
turnText.fill = "#e67e22";
// Resolve combat after both players complete their turns
LK.setTimeout(function () {
resolveCombat();
combatPhase = false;
// Start next round with human player
currentPlayer = 0; // Always start new round with human player
players[currentPlayer].startTurn();
if (!checkGameOver()) {
updateUI();
arrangeHand();
arrangeBattlefield();
}
}, 1000);
} else {
// Switch to the other player for their turn
players[currentPlayer].startTurn();
if (currentPlayer === 1) {
// AI turn
LK.setTimeout(function () {
performAITurn();
}, 1000);
}
if (!checkGameOver()) {
updateUI();
arrangeHand();
arrangeBattlefield();
}
}
}
function performAITurn() {
// Enhanced AI with strategic decision-making and adaptive difficulty
console.log("AI Turn - Difficulty:", gameDifficulty, "Health:", aiPlayer.health, "vs", humanPlayer.health);
console.log("AI Hand size:", aiPlayer.hand.length, "Battlefield:", aiPlayer.battlefield.length, "Mana:", aiPlayer.currentMana);
// Calculate board state and threat assessment
var boardState = evaluateBoardState();
var threatLevel = calculateThreatLevel();
var aiStrategy = determineStrategy(boardState, threatLevel);
console.log("AI Strategy:", aiStrategy, "Threat Level:", threatLevel);
// Always try to play cards first - this is the main issue
var playableCards = aiPlayer.hand.filter(function (card) {
return aiPlayer.canPlayCard(card);
});
console.log("Playable cards:", playableCards.length);
// Force AI to play at least one card if possible
var cardsPlayed = 0;
var maxCardsToPlay = Math.min(3 - aiPlayer.battlefield.length, 2); // Play up to 2 cards per turn
while (cardsPlayed < maxCardsToPlay && playableCards.length > 0 && aiPlayer.battlefield.length < 3) {
var cardDecision = makeCardDecision(playableCards, boardState, threatLevel, aiStrategy);
if (cardDecision.card && cardDecision.lane !== -1) {
console.log("AI playing card:", cardDecision.card.cardData.name, "in lane", cardDecision.lane);
if (aiPlayer.playCard(cardDecision.card)) {
cardDecision.card.laneIndex = cardDecision.lane;
cardDecision.card.targetLane = cardDecision.lane;
cardsPlayed++;
// Remove played card from playable list
var cardIndex = playableCards.indexOf(cardDecision.card);
if (cardIndex >= 0) {
playableCards.splice(cardIndex, 1);
}
updateUI();
arrangeHand();
arrangeBattlefield();
} else {
break; // Failed to play card, stop trying
}
} else {
break; // No valid card decision, stop trying
}
}
// Spell casting after playing cards
var usableSpells = aiPlayer.spells.filter(function (spell) {
return aiPlayer.canCastSpell(spell);
});
if (usableSpells.length > 0) {
var spellDecision = makeSpellDecision(usableSpells, boardState, threatLevel);
if (spellDecision.spell && spellDecision.target) {
console.log("AI casting spell:", spellDecision.spell.spellData.name, "on", spellDecision.target.cardData.name);
if (aiPlayer.castSpell(spellDecision.spell, spellDecision.target)) {
updateUI();
arrangeHand();
arrangeBattlefield();
}
}
}
// Dynamic turn timing based on complexity and difficulty
var turnDelay = calculateTurnDelay(boardState, threatLevel);
LK.setTimeout(function () {
if (!checkGameOver()) {
endTurn();
}
}, turnDelay);
// AI helper functions for strategic decision making
function evaluateBoardState() {
var state = {
aiCards: aiPlayer.battlefield.length,
humanCards: humanPlayer.battlefield.length,
aiTotalPower: 0,
humanTotalPower: 0,
aiSynergies: calculateAISynergies(),
humanSynergies: calculateHumanSynergies(),
availableLanes: getAvailableLanes(),
manaEfficiency: aiPlayer.currentMana / aiPlayer.maxMana
};
// Calculate total power on board
for (var i = 0; i < aiPlayer.battlefield.length; i++) {
var card = aiPlayer.battlefield[i];
state.aiTotalPower += card.cardData.attack + card.currentHealth;
}
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
var card = humanPlayer.battlefield[i];
state.humanTotalPower += card.cardData.attack + card.currentHealth;
}
return state;
}
function calculateThreatLevel() {
var threat = 0;
// Player health threat
if (humanPlayer.health <= 15) threat += 30;else if (humanPlayer.health <= 25) threat += 15;
// AI health threat
if (aiPlayer.health <= 20) threat += 40;else if (aiPlayer.health <= 35) threat += 20;
// Board control threat
var powerDifference = 0;
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
powerDifference += humanPlayer.battlefield[i].cardData.attack;
}
for (var i = 0; i < aiPlayer.battlefield.length; i++) {
powerDifference -= aiPlayer.battlefield[i].cardData.attack;
}
if (powerDifference > 5) threat += 25;else if (powerDifference > 0) threat += 10;
return Math.min(100, threat);
}
function determineStrategy(boardState, threatLevel) {
if (threatLevel > 60) return "defensive";
if (aiPlayer.health > humanPlayer.health * 1.5) return "aggressive";
if (boardState.manaEfficiency > 0.8) return "tempo";
if (boardState.aiSynergies.count >= 2) return "synergy";
return "balanced";
}
function makeSpellDecision(usableSpells, boardState, threatLevel) {
var bestSpell = null;
var bestTarget = null;
var bestValue = -1;
for (var s = 0; s < usableSpells.length; s++) {
var spell = usableSpells[s];
var targets = [];
if (spell.spellData.target === "enemy") {
targets = humanPlayer.battlefield.slice();
} else if (spell.spellData.target === "ally") {
targets = aiPlayer.battlefield.slice();
}
for (var t = 0; t < targets.length; t++) {
var target = targets[t];
var value = evaluateSpellValue(spell, target, boardState, threatLevel);
if (value > bestValue) {
bestValue = value;
bestSpell = spell;
bestTarget = target;
}
}
}
// Difficulty-based casting probability - made more aggressive
var castProbability = 0.7; // Increased base probability
if (gameDifficulty === "medium") castProbability = 0.8;else if (gameDifficulty === "hard") castProbability = 0.95;else if (gameDifficulty === "easy") castProbability = 0.6;
// Increase probability based on threat level
castProbability += threatLevel * 0.005;
// Always cast if spell can kill an enemy or has very high value
if (bestValue > 80) castProbability = 1.0;
if (Math.random() < castProbability && bestSpell && bestTarget) {
return {
spell: bestSpell,
target: bestTarget
};
}
return {
spell: null,
target: null
};
}
function evaluateSpellValue(spell, target, boardState, threatLevel) {
var value = 0;
if (spell.spellData.target === "enemy") {
// Damage spells on enemies
if (spell.spellData.name === "Fire Ball") {
// Prioritize killing high-value targets
if (target.currentHealth <= spell.spellData.damage) {
value = 100 + target.cardData.cost * 15 + target.cardData.attack * 10;
// Extra value for removing synergy threats
var targetClass = getCardClass(target.cardData.name);
var humanClassCount = countClassCards(humanPlayer.battlefield, targetClass);
if (humanClassCount >= 2) value += 50;
// Extra value for removing taunt
if (target.cardData.passive === "taunt") value += 30;
} else {
value = spell.spellData.damage * 5;
}
} else if (spell.spellData.name === "Freeze") {
// Freeze high-attack threats
var attackValue = target.cardData.attack + (target.synergyAttackBonus || 0);
value = attackValue * 15;
// Extra value for freezing synergy engines
var targetClass = getCardClass(target.cardData.name);
var humanClassCount = countClassCards(humanPlayer.battlefield, targetClass);
if (humanClassCount >= 2) value += 40;
}
} else if (spell.spellData.target === "ally") {
// Heal spells on allies
if (spell.spellData.name === "Şifa") {
var missingHealth = target.maxHealth - target.currentHealth;
if (missingHealth > 0) {
value = Math.min(missingHealth, Math.abs(spell.spellData.damage)) * 8;
value += target.cardData.cost * 5; // Value keeping expensive cards alive
// Extra value for healing synergy cards
var targetClass = getCardClass(target.cardData.name);
var aiClassCount = countClassCards(aiPlayer.battlefield, targetClass);
if (aiClassCount >= 2) value += 25;
}
}
}
// Adjust value based on difficulty
if (gameDifficulty === "easy") value *= 0.7;else if (gameDifficulty === "hard") value *= 1.3;
return value;
}
function makeCardDecision(playableCards, boardState, threatLevel, strategy) {
if (playableCards.length === 0) {
return {
card: null,
lane: -1
};
}
var bestCard = null;
var bestLane = -1;
var bestValue = -999; //{DE} // Start with very low value
var availableLanes = getAvailableLanes();
// If no lanes available, return null
if (availableLanes.length === 0) {
return {
card: null,
lane: -1
};
}
for (var c = 0; c < playableCards.length; c++) {
var card = playableCards[c];
for (var l = 0; l < availableLanes.length; l++) {
var lane = availableLanes[l];
var value = evaluateCardPlacement(card, lane, boardState, threatLevel, strategy);
if (value > bestValue) {
bestValue = value;
bestCard = card;
bestLane = lane;
}
}
}
// Fallback: if no good placement found, pick first available card and lane
if (bestCard === null && playableCards.length > 0 && availableLanes.length > 0) {
bestCard = playableCards[0];
bestLane = availableLanes[0];
console.log("AI fallback: playing", bestCard.cardData.name, "in lane", bestLane);
}
return {
card: bestCard,
lane: bestLane
};
}
function evaluateCardPlacement(card, lane, boardState, threatLevel, strategy) {
var value = 50; // Start with base positive value to ensure AI plays cards
// Base card value
var costEfficiency = card.cardData.cost > 0 ? (card.cardData.attack + card.cardData.health / 2) / card.cardData.cost : card.cardData.attack + card.cardData.health;
value += costEfficiency * 15;
// Synergy bonus evaluation
var cardClass = getCardClass(card.cardData.name);
var currentClassCount = countClassCards(aiPlayer.battlefield, cardClass);
if (currentClassCount >= 1) {
// Will create or strengthen synergy
var synergyValue = calculateSynergyValue(cardClass, currentClassCount + 1);
value += synergyValue;
}
// Lane-specific evaluation
var humanCardInLane = findHumanCardInLane(lane);
if (humanCardInLane) {
// Can we win this matchup?
var ourAttack = card.cardData.attack;
var theirHealth = humanCardInLane.currentHealth;
var ourHealth = card.cardData.health;
var theirAttack = humanCardInLane.cardData.attack;
if (ourAttack >= theirHealth && theirAttack < ourHealth) {
value += 60; // Great trade
} else if (ourAttack >= theirHealth) {
value += 30; // We kill them but might die
} else if (theirAttack < ourHealth) {
value += 20; // We survive their attack
} else {
value -= 20; // Bad matchup
}
// Avoid Lucifer conflicts
if (card.cardData.name === "Lucifer" && humanCardInLane.cardData.name === "Lucifer") {
value -= 200;
}
} else {
// Empty lane - good for pressure
value += 25;
if (lane === 1) value += 10; // Center lane preference
}
// Strategy adjustments
if (strategy === "aggressive") {
value += card.cardData.attack * 10;
} else if (strategy === "defensive") {
value += card.cardData.health * 8;
if (card.cardData.passive === "taunt") value += 40;
} else if (strategy === "synergy") {
if (currentClassCount >= 1) value += 50;
}
// Passive ability values
if (card.cardData.passive) {
value += evaluatePassiveValue(card.cardData.passive, boardState, threatLevel);
}
// Difficulty scaling
if (gameDifficulty === "easy") {
value *= 0.6 + Math.random() * 0.4; // Add randomness for easy
} else if (gameDifficulty === "hard") {
value *= 1.2; // Better evaluation for hard
}
return value;
}
function calculateSynergyValue(cardClass, newCount) {
if (newCount < 2) return 0;
var value = 0;
switch (cardClass) {
case "Tank":
value = newCount * 25;
break;
// Health regen
case "Mage":
value = newCount * 35;
break;
// Rage damage
case "Rogue":
value = newCount * 30;
break;
// Attack/health boost
case "Warrior":
value = newCount * 40;
break;
// Attack boost
case "Vampire":
value = newCount * 30;
break;
// Lifesteal
}
return value;
}
function evaluatePassiveValue(passive, boardState, threatLevel) {
switch (passive) {
case "burn":
return 25 + humanPlayer.battlefield.length * 10;
case "heal":
return 20;
case "taunt":
return threatLevel > 40 ? 35 : 15;
case "evasion":
return 20;
case "shock":
return humanPlayer.battlefield.length * 15;
case "lifesteal":
return 25;
case "stealth":
return 15;
case "divine_shield":
return 30;
default:
return 0;
}
}
function calculateAISynergies() {
var synergies = {
count: 0,
types: []
};
var classCounts = {};
for (var i = 0; i < aiPlayer.battlefield.length; i++) {
var cardClass = getCardClass(aiPlayer.battlefield[i].cardData.name);
classCounts[cardClass] = (classCounts[cardClass] || 0) + 1;
}
for (var cardClass in classCounts) {
if (classCounts[cardClass] >= 2) {
synergies.count++;
synergies.types.push(cardClass);
}
}
return synergies;
}
function calculateHumanSynergies() {
var synergies = {
count: 0,
types: []
};
var classCounts = {};
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
var cardClass = getCardClass(humanPlayer.battlefield[i].cardData.name);
classCounts[cardClass] = (classCounts[cardClass] || 0) + 1;
}
for (var cardClass in classCounts) {
if (classCounts[cardClass] >= 2) {
synergies.count++;
synergies.types.push(cardClass);
}
}
return synergies;
}
function countClassCards(battlefield, cardClass) {
var count = 0;
for (var i = 0; i < battlefield.length; i++) {
if (getCardClass(battlefield[i].cardData.name) === cardClass) {
count++;
}
}
return count;
}
function getAvailableLanes() {
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);
}
}
return availableLanes;
}
function findHumanCardInLane(lane) {
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
if (humanPlayer.battlefield[i].laneIndex === lane) {
return humanPlayer.battlefield[i];
}
}
return null;
}
function calculateTurnDelay(boardState, threatLevel) {
var baseDelay = 1500;
if (gameDifficulty === "easy") {
baseDelay = 2200; // Slower for easy
} else if (gameDifficulty === "hard") {
baseDelay = 1000; // Faster for hard
}
// Faster decisions under high threat
if (threatLevel > 70) baseDelay *= 0.8;
// Add some variation
baseDelay += (Math.random() - 0.5) * 400;
return Math.max(800, baseDelay);
}
}
// 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
// Button hover tracking
var mainMenuButtonHover = false;
// 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) {
switch (passiveType) {
case "burn":
return "Burns all enemies for 1 damage at end of turn";
case "heal":
return "Heals 1 health at start of turn";
case "taunt":
return "Forces enemies to attack this card first";
case "evasion":
return "25% chance to dodge attacks";
case "shock":
return "Deals 3 damage to all enemies when played";
case "lifesteal":
return "Heals 1 when dealing damage to other cards";
case "stealth":
return "Cannot be targeted by spells for first turn";
case "divine_shield":
return "Ignores the first damage taken";
case "frost":
return "Slows enemy cards when attacking them";
case "rebirth":
return "Revives once when destroyed with half health";
case "void":
return "30% chance to teleport to different lane when taking damage";
case "crystal_shield":
return "Reduces damage taken by all friendly cards by 1";
case "stone_skin":
return "Reduces all damage taken by 1 (minimum 1 damage)";
case "shadow":
return "Becomes invisible for 2 turns when played, harder to target";
default:
return "No passive ability";
}
}
function createClassFeatureDisplay(className) {
if (isShowingClassFeature) {
destroyClassFeatureDisplay();
}
var classInfo = classFeatures[className];
if (!classInfo) return;
// Create dark overlay background
var overlay = game.addChild(LK.getAsset('menuOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.85
}));
// Class name title
var titleText = new Text2(classInfo.name + " SINIFI", {
size: 60,
fill: 0xf39c12
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
game.addChild(titleText);
// Class feature
var featureText = new Text2("Özellik: " + classInfo.feature, {
size: 48,
fill: 0x3498db
});
featureText.anchor.set(0.5, 0.5);
featureText.x = 1024;
featureText.y = 900;
game.addChild(featureText);
// Synergy bonus
var synergyText = new Text2("Sinerji Bonusu: " + classInfo.synergy, {
size: 44,
fill: 0xFFD700
});
synergyText.anchor.set(0.5, 0.5);
synergyText.x = 1024;
synergyText.y = 1000;
game.addChild(synergyText);
// Description (split into multiple lines for better readability)
var descLines = classInfo.description.split('. ');
for (var i = 0; i < descLines.length; i++) {
var lineText = new Text2(descLines[i] + (i < descLines.length - 1 ? '.' : ''), {
size: 36,
fill: 0xecf0f1
});
lineText.anchor.set(0.5, 0.5);
lineText.x = 1024;
lineText.y = 1150 + i * 60;
game.addChild(lineText);
}
// Close instruction
var closeText = new Text2("Kapatmak için herhangi bir yere tıklayın", {
size: 32,
fill: 0x7f8c8d
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 1024;
closeText.y = 1600;
game.addChild(closeText);
// Store references for cleanup
classFeatureDisplay = {
overlay: overlay,
titleText: titleText,
featureText: featureText,
synergyText: synergyText,
descLines: [],
closeText: closeText
};
// Add description lines to cleanup list
for (var i = 0; i < descLines.length; i++) {
classFeatureDisplay.descLines.push(game.children[game.children.length - 2 - i]);
}
isShowingClassFeature = true;
// Auto-hide after 5 seconds
LK.setTimeout(function () {
destroyClassFeatureDisplay();
}, 5000);
}
function destroyClassFeatureDisplay() {
if (!isShowingClassFeature || !classFeatureDisplay) return;
if (classFeatureDisplay.overlay) {
game.removeChild(classFeatureDisplay.overlay);
}
if (classFeatureDisplay.titleText) {
game.removeChild(classFeatureDisplay.titleText);
}
if (classFeatureDisplay.featureText) {
game.removeChild(classFeatureDisplay.featureText);
}
if (classFeatureDisplay.synergyText) {
game.removeChild(classFeatureDisplay.synergyText);
}
for (var i = 0; i < classFeatureDisplay.descLines.length; i++) {
if (classFeatureDisplay.descLines[i]) {
game.removeChild(classFeatureDisplay.descLines[i]);
}
}
if (classFeatureDisplay.closeText) {
game.removeChild(classFeatureDisplay.closeText);
}
classFeatureDisplay = null;
isShowingClassFeature = false;
}
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();
}
// Close class feature display if showing
if (isShowingClassFeature) {
destroyClassFeatureDisplay();
return;
}
// Check if a synergy class icon was clicked
var classNames = ["Tank", "Mage", "Rogue", "Warrior"];
var synergyStartY = 800;
var synergySpacing = 200;
for (var i = 0; i < classNames.length; i++) {
var className = classNames[i];
var yPos = synergyStartY + i * synergySpacing;
var iconBounds = {
left: 50,
right: 150,
top: yPos - 40,
bottom: yPos + 40
};
if (x >= iconBounds.left && x <= iconBounds.right && y >= iconBounds.top && y <= iconBounds.bottom) {
createClassFeatureDisplay(className);
return;
}
}
// Check if end turn button was clicked
if (x >= 1700 && x <= 1900 && y >= 1910 && y <= 1990) {
endTurn();
return;
}
// Check if main menu button was clicked
if (x >= 1480 && x <= 1720 && y >= 110 && y <= 190) {
// Button press effect
tween(mainMenuBtn, {
scaleX: 0.55,
scaleY: 0.55,
tint: 0x2980b9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(mainMenuBtn, {
scaleX: 0.6,
scaleY: 0.6,
tint: 0x3498db
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Return to main menu and reset game
LK.setTimeout(function () {
resetGame();
}, 200);
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];
// Ensure card is properly displayed in game
if (!game.children.includes(card)) {
continue;
}
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 && humanPlayer.canPlayCard(card)) {
selectedCard = card;
draggedCard = card;
// Start long press timer for zoom preview
if (zoomPreviewTimeout) {
LK.clearTimeout(zoomPreviewTimeout);
}
zoomPreviewTimeout = LK.setTimeout(function () {
if (selectedCard === card && game.children.includes(card)) {
createZoomPreview(card);
draggedCard = null; // Cancel drag when showing zoom
}
}, 800); // 800ms long press
}
return;
}
}
// Check battlefield cards for zoom preview and drag (human player cards only)
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
var card = humanPlayer.battlefield[i];
// Ensure card is properly displayed in game
if (!game.children.includes(card)) {
continue;
}
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;
// Allow dragging battlefield cards if not locked in
if (!cardsLockedIn && card.isOnBattlefield) {
draggedCard = card;
selectedCard = card;
}
// Start long press timer for battlefield card zoom
if (zoomPreviewTimeout) {
LK.clearTimeout(zoomPreviewTimeout);
}
zoomPreviewTimeout = LK.setTimeout(function () {
if (!draggedCard && game.children.includes(card)) {
// Only show zoom if not dragging
createZoomPreview(card);
}
}, 800);
return;
}
}
// Check AI battlefield cards for zoom preview only (no dragging)
for (var i = 0; i < aiPlayer.battlefield.length; i++) {
var card = aiPlayer.battlefield[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 AI 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 AI 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;
}
// Check if mouse is over main menu button
var isOverMainMenuButton = x >= 1480 && x <= 1720 && y >= 110 && y <= 190;
if (isOverMainMenuButton && !mainMenuButtonHover) {
mainMenuButtonHover = true;
tween(mainMenuBtn, {
scaleX: 0.7,
scaleY: 0.7,
tint: 0x5dade2
}, {
duration: 200,
easing: tween.easeOut
});
} else if (!isOverMainMenuButton && mainMenuButtonHover) {
mainMenuButtonHover = false;
tween(mainMenuBtn, {
scaleX: 0.6,
scaleY: 0.6,
tint: 0x3498db
}, {
duration: 200,
easing: tween.easeOut
});
}
// Handle card dragging
if (draggedCard && game.children.includes(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++) {
if (game.children.includes(aiPlayer.battlefield[i])) {
aiPlayer.battlefield[i].alpha = 1.0;
}
}
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
if (game.children.includes(humanPlayer.battlefield[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];
if (game.children.includes(card)) {
var distance = Math.sqrt((card.x - x) * (card.x - x) + (card.y - y) * (card.y - y));
if (distance < 150) {
card.alpha = 0.7;
}
}
}
}
} else {
// Reset dragged card if it's not in the game anymore
draggedCard = null;
selectedCard = null;
}
};
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();
}
}
}
// Check if card is being dragged from battlefield back to hand area (return to deck functionality)
else if (draggedCard && y > 1900 && draggedCard.isOnBattlefield && !cardsLockedIn) {
// Find the card on battlefield and return it to deck
var battlefieldIndex = humanPlayer.battlefield.indexOf(draggedCard);
if (battlefieldIndex >= 0) {
// Store original card data before removing
var originalCardData = {
name: draggedCard.cardData.name,
cost: draggedCard.cardData.cost,
attack: draggedCard.cardData.attack,
health: draggedCard.cardData.health,
description: draggedCard.cardData.description,
passive: draggedCard.cardData.passive
};
// Return mana to player
humanPlayer.currentMana = Math.min(humanPlayer.maxMana, humanPlayer.currentMana + draggedCard.cardData.cost);
// Remove from battlefield
humanPlayer.battlefield.splice(battlefieldIndex, 1);
// Clear lane assignment
draggedCard.laneIndex = undefined;
draggedCard.isOnBattlefield = false;
// Remove from game display
game.removeChild(draggedCard);
// Create a completely fresh new card instance with the original data
var newCard = new Card(originalCardData);
newCard.validateStats(); // Ensure stats are correct
// Add new card instance to deck
humanPlayer.deck.push(newCard);
// Visual feedback for successful return
var returnText = new Text2("KARTA DESTEYE DÖNDÜ!", {
size: 40,
fill: 0x27ae60
});
returnText.anchor.set(0.5, 0.5);
returnText.x = 1024;
returnText.y = 1500;
returnText.alpha = 1.0;
game.addChild(returnText);
// Animate feedback text
tween(returnText, {
y: returnText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(returnText);
}
});
draggedCard = null;
selectedCard = null;
updateUI();
arrangeHand();
arrangeBattlefield();
}
}
// Check if card from hand is being dragged onto an occupied lane (card replacement)
else if (draggedCard && !draggedCard.isOnBattlefield && 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 occupied by player's card
var existingCardInLane = null;
for (var i = 0; i < humanPlayer.battlefield.length; i++) {
if (humanPlayer.battlefield[i].laneIndex === targetLane) {
existingCardInLane = humanPlayer.battlefield[i];
break;
}
}
// If lane is occupied and we can play the new card, replace it
if (targetLane >= 0 && existingCardInLane && humanPlayer.canPlayCard(draggedCard)) {
// 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 (!luciferBlocked) {
// Store the existing card data
var existingCardData = {
name: existingCardInLane.cardData.name,
cost: existingCardInLane.cardData.cost,
attack: existingCardInLane.cardData.attack,
health: existingCardInLane.cardData.health,
description: existingCardInLane.cardData.description,
passive: existingCardInLane.cardData.passive
};
// Remove existing card from battlefield
var existingIndex = humanPlayer.battlefield.indexOf(existingCardInLane);
humanPlayer.battlefield.splice(existingIndex, 1);
existingCardInLane.laneIndex = undefined;
existingCardInLane.isOnBattlefield = false;
game.removeChild(existingCardInLane);
// Create new card instance for the replaced card and add to deck
var replacedCard = new Card(existingCardData);
replacedCard.validateStats();
humanPlayer.deck.push(replacedCard);
// Play the new card in the same lane
if (humanPlayer.playCard(draggedCard)) {
draggedCard.laneIndex = targetLane;
draggedCard.targetLane = targetLane;
// Visual feedback for successful replacement
var replaceText = new Text2("KART YER DEĞİŞTİRDİ!", {
size: 40,
fill: 0xf39c12
});
replaceText.anchor.set(0.5, 0.5);
replaceText.x = 1024;
replaceText.y = 1500;
replaceText.alpha = 1.0;
game.addChild(replaceText);
// Animate feedback text
tween(replaceText, {
y: replaceText.y - 80,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(replaceText);
}
});
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();
}
};
function initializeGameplay() {
// Initialize starting hands
for (var i = 0; i < 4; i++) {
humanPlayer.drawCard();
aiPlayer.drawCard();
}
// Play background music
LK.playMusic('Darksouls');
// Initial setup
updateUI();
arrangeHand();
arrangeBattlefield();
arrangeSpells();
}
function showMainMenu() {
if (mainMenu) {
game.removeChild(mainMenu);
}
mainMenu = new MainMenu();
game.addChild(mainMenu);
}
function showOpeningScreen() {
var opening = new OpeningScreen();
game.addChild(opening);
}
// Initialize with opening screen
if (gameState === "menu") {
showOpeningScreen();
}
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