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