User prompt
Lane deki kendi kartlarını yerine başka bir kart koymak için yer değiştirme özelliği olsun
User prompt
Shadow drake pasif ekle
User prompt
Shadow drake pasifini sil
User prompt
Golemin pasifini değiştir
User prompt
Freeze büyüsündeki fireball efektini değiştir yerine kar efekti getir
User prompt
Yeni 1 büyü ekle
User prompt
Crystal Guardian karakterini oyuna ekle assetini ekle
User prompt
Please fix the bug: 'Timeout.tick error: canTargetCard is not defined' in or related to this line: 'if (!canTargetCard(humanCard, aiCard) || !canTargetCard(aiCard, humanCard)) {' Line Number: 4750
User prompt
Please fix the bug: 'Timeout.tick error: hasPlayerTauntInLane is not defined' in or related to this line: 'var tauntCard = hasPlayerTauntInLane(humanPlayer, checkLane);' Line Number: 4813
User prompt
Please fix the bug: 'Timeout.tick error: hasPlayerTauntInLane is not defined' in or related to this line: 'var tauntCard = hasPlayerTauntInLane(humanPlayer, checkLane);' Line Number: 4813
User prompt
Golemin taunt özelliği çalışmıyor düzelt
User prompt
Void Stalker adlı karakteri ekle assetini ekle
User prompt
Phoenix adlı karakter ekle ve assetini ekle
/**** * 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 = "taunt"; 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 = "stealth"; 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; } } 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; } 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; } // 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 passiveResult = self.triggerPassive("before_damage", { attacker: attacker, damage: damage }); if (passiveResult === -1) { // Damage was negated by passive ability return; } // 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 } } } 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; } 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" }]; // 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; } } // 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" }]; // 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 = self.spellData.name === "Şifa" ? 'healSpell' : 'fireballSpell'; var projectile = game.addChild(LK.getAsset(projectileAsset, { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y })); var targetX = target ? target.x : 1024 + (Math.random() - 0.5) * 200; var targetY = target ? target.y : aiPlayer.battlefield.length > 0 ? 650 : 300; // Animate projectile to target tween(projectile, { x: targetX, y: targetY, scaleX: 1.5, scaleY: 1.5, rotation: Math.PI * 2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Impact effect LK.effects.flashScreen(0xff4444, 300); // Handle 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 === "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 }]; // 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"; 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(); } } 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 = "taunt";
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 = "stealth";
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;
}
}
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;
}
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;
}
// 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 passiveResult = self.triggerPassive("before_damage", {
attacker: attacker,
damage: damage
});
if (passiveResult === -1) {
// Damage was negated by passive ability
return;
}
// 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
}
}
}
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;
}
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"
}];
// 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;
}
}
// 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"
}];
// 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 = self.spellData.name === "Şifa" ? 'healSpell' : 'fireballSpell';
var projectile = game.addChild(LK.getAsset(projectileAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
}));
var targetX = target ? target.x : 1024 + (Math.random() - 0.5) * 200;
var targetY = target ? target.y : aiPlayer.battlefield.length > 0 ? 650 : 300;
// Animate projectile to target
tween(projectile, {
x: targetX,
y: targetY,
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Impact effect
LK.effects.flashScreen(0xff4444, 300);
// Handle 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 === "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
}];
// 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";
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();
}
}
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