/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Card = Container.expand(function (type, cost) {
var self = Container.call(this);
self.type = type;
self.cost = cost;
self.selected = false;
var cardBg = self.attachAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5
});
var unitPreview = self.addChild(LK.getAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
y: -30
}));
var costText = self.addChild(new Text2(cost.toString(), {
size: 40,
fill: 0xFFFFFF
}));
costText.anchor.set(0.5, 0.5);
costText.y = 80;
// Add card name in Turkish
var nameText = self.addChild(new Text2(getCardName(type).toUpperCase(), {
size: 28,
fill: 0xFFFFFF
}));
nameText.anchor.set(0.5, 0.5);
nameText.y = 120;
// Add health display for cards
var cardHealth = getCardHealth(type);
var healthText = self.addChild(new Text2('HP: ' + cardHealth, {
size: 24,
fill: 0xFF0000
}));
healthText.anchor.set(0.5, 0.5);
healthText.y = -110;
// Card selection state
self.selected = false;
self.down = function (x, y, obj) {
if (deckBuilder && deckBuilder.isOpen) {
deckBuilder.selectCard(self.type);
return;
}
// Simple touch deployment - select this card for deployment
if (currentEnergy >= self.cost) {
// Deselect previously selected card
if (selectedCard) {
selectedCard.children[0].tint = 0xFFFFFF;
selectedCard.selected = false;
}
// Select this card
selectedCard = self;
self.selected = true;
cardBg.tint = 0x00FF00;
} else {
// Visual feedback for insufficient energy
cardBg.tint = 0xFF0000;
LK.setTimeout(function () {
cardBg.tint = 0xFFFFFF;
}, 500);
}
};
return self;
});
var DeckBuilder = Container.expand(function () {
var self = Container.call(this);
self.isOpen = false;
self.selectedDeck = [];
self.availableCards = allCardTypes.slice();
var bg = self.attachAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.6
});
bg.tint = 0x222222;
var titleText = self.addChild(new Text2("Tüm Kartlar - 8 Seç", {
size: 60,
fill: 0xFFFFFF
}));
titleText.anchor.set(0.5, 0.5);
titleText.y = -400;
self.show = function () {
self.isOpen = true;
self.visible = true;
self.selectedDeck = [];
titleText.setText("Tüm Kartlar - 8 Seç");
self.refreshCards();
};
self.hide = function () {
self.isOpen = false;
self.visible = false;
};
self.refreshCards = function () {
for (var i = self.children.length - 1; i >= 0; i--) {
if (self.children[i].isCardOption) {
self.children[i].destroy();
}
}
// Show all 15 cards in a 5x3 grid layout
for (var i = 0; i < self.availableCards.length; i++) {
var cardType = self.availableCards[i];
var cost = allCardCosts[allCardTypes.indexOf(cardType)];
var cardOption = self.addChild(new Card(cardType, cost));
cardOption.isCardOption = true;
cardOption.x = -400 + i % 5 * 200;
cardOption.y = -200 + Math.floor(i / 5) * 300;
cardOption.scaleX = 0.8;
cardOption.scaleY = 0.8;
// Update card name text to uppercase for deck builder cards with larger font size
if (cardOption.children.length > 4 && cardOption.children[4] && cardOption.children[4].setText) {
// Create new text with larger font size for deck builder
var oldNameText = cardOption.children[4];
oldNameText.destroy();
var newNameText = cardOption.addChild(new Text2(getCardName(cardType).toUpperCase(), {
size: 45,
fill: 0xFFFFFF
}));
newNameText.anchor.set(0.5, 0.5);
newNameText.y = 135;
}
// Add scale up animation for card preview
tween(cardOption, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeOut
});
// Highlight already selected cards
for (var j = 0; j < self.selectedDeck.length; j++) {
if (self.selectedDeck[j] === cardType) {
cardOption.children[0].tint = 0x00FF00;
break;
}
}
}
};
self.selectCard = function (cardType) {
if (self.selectedDeck.length < 8) {
self.selectedDeck.push(cardType);
// Update title to show progress
titleText.setText("Seçilen: " + self.selectedDeck.length + "/8");
if (self.selectedDeck.length === 8) {
playerDeck = self.selectedDeck.slice();
self.hide();
setupPlayerCards();
}
}
};
self.visible = false;
return self;
});
var Projectile = Container.expand(function (startX, startY, target, damage) {
var self = Container.call(this);
self.x = startX;
self.y = startY;
self.target = target;
self.damage = damage;
self.speed = 8;
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (!self.target || self.target.health <= 0) {
self.destroy();
return;
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.target.height / 2 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 30) {
// Hit target
self.target.takeDamage(self.damage);
self.destroy();
} else {
// Move toward target
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var Tower = Container.expand(function (isPlayer, isKing) {
var self = Container.call(this);
self.isPlayer = isPlayer;
self.isKing = isKing;
self.maxHealth = isKing ? 3000 : 2000;
self.health = self.maxHealth;
self.attackDamage = isKing ? 200 : 150;
self.attackRange = 250;
self.attackCooldown = 0;
self.attackSpeed = 60; // frames between attacks
var assetName = (isPlayer ? 'player' : 'enemy') + (isKing ? 'KingTower' : 'Tower');
var towerGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0
});
// Add health bar background
var healthBarBg = self.attachAsset('energyBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 0.8,
y: -150
});
healthBarBg.tint = 0x444444;
// Add health bar
var healthBar = self.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 0.8,
x: -100,
y: -150
});
healthBar.tint = 0x00FF00;
// Add health text
var healthText = self.addChild(new Text2(self.health + '/' + self.maxHealth, {
size: 30,
fill: 0xFFFFFF
}));
healthText.anchor.set(0.5, 0.5);
healthText.y = -150;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = 2.0 * healthPercent;
healthText.setText(self.health + '/' + self.maxHealth);
// Color health bar based on health percentage
if (healthPercent > 0.6) {
healthBar.tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
healthBar.tint = 0xFFFF00; // Yellow for medium health
} else {
healthBar.tint = 0xFF0000; // Red for low health
}
// Flash effect
LK.effects.flashObject(towerGraphics, 0xFF0000, 300);
LK.getSound('towerHit').play();
if (self.health <= 0) {
// Gain elixir when destroying enemy towers
if (self.isPlayer === false && currentElixir < maxElixir) {
currentElixir += 3; // More elixir for towers
if (currentElixir > maxElixir) currentElixir = maxElixir;
var elixirPercent = currentElixir / maxElixir;
elixirBar.scaleX = 1.0 * elixirPercent;
elixirText.setText("İksir: " + currentElixir + "/" + maxElixir);
}
self.destroy();
if (isKing) {
if (isPlayer) {
LK.showGameOver();
} else {
LK.showYouWin();
}
}
}
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
return;
}
// Find closest enemy unit
var targetUnits = self.isPlayer ? enemyUnits : playerUnits;
var closestUnit = null;
var closestDistance = Infinity;
for (var i = 0; i < targetUnits.length; i++) {
var unit = targetUnits[i];
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.attackRange && distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
if (closestUnit) {
self.attackCooldown = self.attackSpeed;
// Create projectile
var projectile = new Projectile(self.x, self.y - 50, closestUnit, self.attackDamage);
game.addChild(projectile);
projectiles.push(projectile);
}
};
return self;
});
var Unit = Container.expand(function (type, isPlayer) {
var self = Container.call(this);
self.isPlayer = isPlayer;
self.type = type;
self.moveSpeed = 2;
self.attackDamage = 100;
self.attackRange = 80;
self.attackCooldown = 0;
self.attackSpeed = 60;
self.target = null;
// Set stats based on type
switch (type) {
case 'soldier':
self.maxHealth = 400;
self.moveSpeed = 2;
self.attackDamage = 80;
break;
case 'archer':
self.maxHealth = 200;
self.moveSpeed = 2.5;
self.attackDamage = 60;
self.attackRange = 150;
break;
case 'tank':
self.maxHealth = 800;
self.moveSpeed = 1;
self.attackDamage = 120;
break;
case 'wizard':
self.maxHealth = 300;
self.moveSpeed = 2;
self.attackDamage = 150;
self.attackRange = 180;
break;
case 'dragon':
self.maxHealth = 1200;
self.moveSpeed = 1.5;
self.attackDamage = 200;
self.attackRange = 200;
break;
case 'freeze':
self.maxHealth = 280;
self.moveSpeed = 1.8;
self.attackDamage = 80;
self.attackRange = 150;
break;
case 'goblin':
self.maxHealth = 150;
self.moveSpeed = 3;
self.attackDamage = 50;
break;
case 'giant':
self.maxHealth = 1500;
self.moveSpeed = 0.8;
self.attackDamage = 250;
break;
case 'healer':
self.maxHealth = 250;
self.moveSpeed = 2;
self.attackDamage = 20;
self.attackRange = 160;
break;
case 'assassin':
self.maxHealth = 180;
self.moveSpeed = 3.5;
self.attackDamage = 120;
break;
case 'bomber':
self.maxHealth = 220;
self.moveSpeed = 2.2;
self.attackDamage = 180;
self.attackRange = 140;
break;
break;
case 'guardian':
self.maxHealth = 215; // Reduced from 750 since 7 spawn
self.moveSpeed = 1.5;
self.attackDamage = 32; // Reduced from 95 since 7 spawn
break;
case 'berserker':
self.maxHealth = 500;
self.moveSpeed = 2.3;
self.attackDamage = 140;
break;
break;
}
self.health = self.maxHealth;
var unitGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 1.0
});
if (!isPlayer) {
unitGraphics.scaleX = -1; // Flip enemy units
}
// Add health bar background
var healthBarBg = self.attachAsset('energyBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.4,
y: -120
});
healthBarBg.tint = 0x000000;
// Add health bar
var healthBar = self.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.4,
x: -50,
y: -120
});
healthBar.tint = 0x00FF00;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = 1.0 * healthPercent;
// Color health bar based on health percentage
if (healthPercent > 0.6) {
healthBar.tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
healthBar.tint = 0xFFFF00; // Yellow for medium health
} else {
healthBar.tint = 0xFF0000; // Red for low health
}
if (self.health <= 0) {
LK.effects.flashObject(unitGraphics, 0xFF0000, 200);
LK.getSound('unitDeath').play();
// Gain elixir when destroying enemy units
if (self.isPlayer === false && currentElixir < maxElixir) {
currentElixir += elixirGainAmount;
if (currentElixir > maxElixir) currentElixir = maxElixir;
var elixirPercent = currentElixir / maxElixir;
elixirBar.scaleX = 1.0 * elixirPercent;
elixirText.setText("İksir: " + currentElixir + "/" + maxElixir);
}
self.destroy();
} else {
LK.effects.flashObject(unitGraphics, 0xFF0000, 150);
}
};
self.findTarget = function () {
var targetUnits = self.isPlayer ? enemyUnits : playerUnits;
var targetTowers = self.isPlayer ? enemyTowers : playerTowers;
var allTargets = targetUnits.concat(targetTowers);
var closest = null;
var closestDistance = Infinity;
for (var i = 0; i < allTargets.length; i++) {
var target = allTargets[i];
if (!target || target.health <= 0) continue;
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closest = target;
}
}
return closest;
};
self.update = function () {
// Special behavior for healer units
if (self.type === 'healer') {
// Find injured teammates to heal
var targetUnits = self.isPlayer ? playerUnits : enemyUnits;
var healTarget = null;
var closestDistance = Infinity;
// Find closest injured teammate within healing range
for (var i = 0; i < targetUnits.length; i++) {
var unit = targetUnits[i];
if (unit && unit !== self && unit.health > 0 && unit.health < unit.maxHealth) {
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && distance < closestDistance) {
closestDistance = distance;
healTarget = unit;
}
}
}
if (healTarget) {
// Heal teammate
if (self.attackCooldown <= 0) {
self.attackCooldown = self.attackSpeed;
// Heal the target
var healAmount = 50; // Healing amount per cast
healTarget.health += healAmount;
if (healTarget.health > healTarget.maxHealth) {
healTarget.health = healTarget.maxHealth;
}
// Update healed unit's health bar
var healedHealthPercent = healTarget.health / healTarget.maxHealth;
if (healTarget.children[3]) {
healTarget.children[3].scaleX = 1.0 * healedHealthPercent;
// Color health bar based on health percentage
if (healedHealthPercent > 0.6) {
healTarget.children[3].tint = 0x00FF00; // Green for high health
} else if (healedHealthPercent > 0.3) {
healTarget.children[3].tint = 0xFFFF00; // Yellow for medium health
} else {
healTarget.children[3].tint = 0xFF0000; // Red for low health
}
}
// Visual healing effects
// Visual healing effects
LK.effects.flashObject(self, 0x00FF00, 200); // Green flash for healer
LK.effects.flashObject(healTarget, 0x00FF00, 300); // Green flash for healed unit
}
} else {
// No injured teammates nearby, find enemy to attack
if (!self.target || self.target.health <= 0) {
self.target = self.findTarget();
}
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange) {
// Attack enemy
if (self.attackCooldown <= 0) {
self.attackCooldown = self.attackSpeed;
LK.effects.flashObject(self, 0xFFFF00, 200);
var projectile = new Projectile(self.x, self.y - 40, self.target, self.attackDamage);
game.addChild(projectile);
projectiles.push(projectile);
}
} else {
// Move toward enemy target
var moveX = dx / distance * self.moveSpeed;
var moveY = dy / distance * self.moveSpeed;
self.x += moveX;
self.y += moveY;
}
}
}
} else {
// Normal unit behavior for non-healers
if (!self.target || self.target.health <= 0) {
self.target = self.findTarget();
}
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange) {
// Attack
if (self.attackCooldown <= 0) {
self.attackCooldown = self.attackSpeed;
// Create attack effects
LK.effects.flashObject(self, 0xFFFF00, 200);
if (self.type === 'archer' || self.type === 'wizard' || self.type === 'dragon' || self.type === 'bomber' || self.type === 'freeze') {
// Ranged attack with projectile
var projectile = new Projectile(self.x, self.y - 40, self.target, self.attackDamage);
game.addChild(projectile);
projectiles.push(projectile);
} else {
// Melee attack with effects
if (self.type === 'bomber') {
// Bomber creates explosion effect
LK.effects.flashObject(self.target, 0xFF4500, 400);
LK.getSound('explosion').play();
} else if (self.type === 'berserker') {
// Berserker gets damage boost when low health
var damageBonus = self.health < self.maxHealth * 0.3 ? 50 : 0;
self.target.takeDamage(self.attackDamage + damageBonus);
LK.effects.flashObject(self, 0xDC143C, 300);
} else {
self.target.takeDamage(self.attackDamage);
}
}
}
} else {
// Move toward target
var moveX = dx / distance * self.moveSpeed;
var moveY = dy / distance * self.moveSpeed;
self.x += moveX;
self.y += moveY;
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var currentEnergy = 10;
var maxEnergy = 10;
var energyRegenRate = 1; // energy per second
var energyRegenTimer = 0;
var currentElixir = 0;
var maxElixir = 10;
var elixirGainAmount = 1;
var playerUnits = [];
var enemyUnits = [];
var playerTowers = [];
var enemyTowers = [];
var projectiles = [];
var playerCards = [];
var selectedCard = null;
var playerCups = storage.playerCups || 100; // Starting cups
var matchInProgress = false;
var matchTimer = 120 * 60; // 2 minutes in frames (60 FPS)
var matchTimerText = null;
var inOvertime = false;
// Override LK's game over and win functions to handle cup system
LK.showGameOver = function () {
playerCups -= 5;
if (playerCups < 0) playerCups = 0;
storage.playerCups = playerCups;
matchInProgress = false;
// Reset game state
game.destroy();
// Restart the game
location.reload();
};
LK.showYouWin = function () {
playerCups += 30;
storage.playerCups = playerCups;
matchInProgress = false;
// Reset game state
game.destroy();
// Restart the game
location.reload();
};
// Arena setup
var arena = game.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// Add red centerline
var centerLine = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// River removed
// Bridges removed
// Create towers
// Player towers (bottom)
var playerKingTower = new Tower(true, true);
playerKingTower.x = 1024;
playerKingTower.y = 2200;
game.addChild(playerKingTower);
playerTowers.push(playerKingTower);
var playerLeftTower = new Tower(true, false);
playerLeftTower.x = 600;
playerLeftTower.y = 2000;
game.addChild(playerLeftTower);
playerTowers.push(playerLeftTower);
var playerRightTower = new Tower(true, false);
playerRightTower.x = 1448;
playerRightTower.y = 2000;
game.addChild(playerRightTower);
playerTowers.push(playerRightTower);
// Enemy towers (top)
var enemyKingTower = new Tower(false, true);
enemyKingTower.x = 1024;
enemyKingTower.y = 600;
game.addChild(enemyKingTower);
enemyTowers.push(enemyKingTower);
var enemyLeftTower = new Tower(false, false);
enemyLeftTower.x = 600;
enemyLeftTower.y = 800;
game.addChild(enemyLeftTower);
enemyTowers.push(enemyLeftTower);
var enemyRightTower = new Tower(false, false);
enemyRightTower.x = 1448;
enemyRightTower.y = 800;
game.addChild(enemyRightTower);
enemyTowers.push(enemyRightTower);
// UI Setup - moved to bottom left corner
var energyBarBg = LK.gui.bottomLeft.addChild(LK.getAsset('energyBar', {
anchorX: 0,
anchorY: 1.0,
x: 10,
y: -300,
scaleX: 1.0,
scaleY: 0.8
}));
energyBarBg.tint = 0x333333;
var energyBar = LK.gui.bottomLeft.addChild(LK.getAsset('energyBar', {
anchorX: 0,
anchorY: 1.0,
y: -300,
x: 10,
scaleX: 1.0,
scaleY: 0.8
}));
var energyText = LK.gui.bottomLeft.addChild(new Text2("10/10", {
size: 35,
fill: 0xFFFFFF
}));
energyText.anchor.set(0, 1.0);
energyText.x = 60;
energyText.y = -270;
// Elixir bar setup - moved to bottom right corner
var elixirBarBg = LK.gui.bottomRight.addChild(LK.getAsset('energyBar', {
anchorX: 1.0,
anchorY: 1.0,
x: -5,
y: -400,
scaleX: 0.8,
scaleY: 0.6
}));
elixirBarBg.tint = 0x8B4513;
var elixirBar = LK.gui.bottomRight.addChild(LK.getAsset('energyBar', {
anchorX: 0,
anchorY: 1.0,
x: -85,
y: -400,
scaleX: 0.8,
scaleY: 0.6
}));
elixirBar.tint = 0xDDA0DD;
var elixirText = LK.gui.bottomRight.addChild(new Text2("İksir: 0/10", {
size: 30,
fill: 0xFFFFFF
}));
elixirText.anchor.set(0.5, 1.0);
elixirText.x = -45;
elixirText.y = -370;
// Add match timer display
matchTimerText = LK.gui.top.addChild(new Text2("2:00", {
size: 60,
fill: 0xFFFFFF
}));
matchTimerText.anchor.set(0.5, 0);
matchTimerText.y = 100;
matchTimerText.visible = false;
// All available card types (15 total)
var allCardTypes = ['soldier', 'archer', 'tank', 'wizard', 'dragon', 'poison', 'goblin', 'giant', 'healer', 'assassin', 'bomber', 'freeze', 'berserker', 'guardian', 'fireball'];
var allCardCosts = [2, 3, 4, 5, 8, 3, 1, 6, 4, 2, 4, 5, 4, 7, 3];
var playerDeck = ['soldier', 'archer', 'tank', 'wizard', 'dragon', 'poison', 'goblin', 'giant']; // Default 8-card deck
function getCardName(type) {
switch (type) {
case 'soldier':
return 'Asker';
case 'archer':
return 'Okçu';
case 'tank':
return 'Tank';
case 'wizard':
return 'Büyücü';
case 'dragon':
return 'Ejder';
case 'poison':
return 'Zehir';
case 'freeze':
return 'Dondurma';
case 'guardian':
return 'Koruyucu';
case 'goblin':
return 'Goblin';
case 'giant':
return 'Dev';
case 'healer':
return 'Şifacı';
case 'assassin':
return 'Suikastçi';
case 'bomber':
return 'Bombacı';
case 'berserker':
return 'Berserker';
case 'fireball':
return 'Alev Topu';
default:
return 'Bilinmiyen';
}
}
function getCardHealth(type) {
switch (type) {
case 'soldier':
return 400;
case 'archer':
return 200;
case 'tank':
return 800;
case 'wizard':
return 300;
case 'dragon':
return 1200;
case 'poison':
return 250;
case 'freeze':
return 280;
case 'guardian':
return 215;
// Adjusted for 7-unit spawn
case 'goblin':
return 150;
case 'giant':
return 1500;
case 'healer':
return 250;
case 'assassin':
return 180;
case 'bomber':
return 220;
case 'berserker':
return 500;
case 'fireball':
return 100;
default:
return 100;
}
}
function setupPlayerCards() {
// Clear existing cards
for (var i = 0; i < playerCards.length; i++) {
playerCards[i].destroy();
}
playerCards = [];
// Create cards from player deck - ensure different cards in hand
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
var availableTypes = playerDeck.slice(); // Copy of deck
for (var i = 0; i < 4; i++) {
// Randomly select from available types to ensure variety
var randomIndex = Math.floor(Math.random() * availableTypes.length);
var cardType = availableTypes[randomIndex];
// Remove selected type to prevent immediate duplicates
availableTypes.splice(randomIndex, 1);
// If we run out of unique types, refill from deck
if (availableTypes.length === 0) {
availableTypes = playerDeck.slice();
}
var cost = allCardCosts[allCardTypes.indexOf(cardType)];
var card = new Card(cardType, cost);
card.x = startX + i * cardWidth;
card.y = -80;
LK.gui.bottom.addChild(card);
playerCards.push(card);
}
}
// Create main menu
var mainMenu = new Container();
mainMenu.x = 0;
mainMenu.y = 0;
LK.gui.center.addChild(mainMenu);
var menuBg = mainMenu.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
}));
menuBg.tint = 0x1a1a2e;
var titleText = mainMenu.addChild(new Text2("Tower Defense Arena", {
size: 80,
fill: 0xFFFFFF
}));
titleText.anchor.set(0.5, 0.5);
titleText.y = -500;
var myCardsBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var myCardsText = mainMenu.addChild(new Text2("Kartlarım", {
size: 40,
fill: 0xFFFFFF
}));
myCardsText.anchor.set(0.5, 0.5);
myCardsText.x = -300;
myCardsText.y = -250;
var vsBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -100,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var vsText = mainMenu.addChild(new Text2("İki Kişilik", {
size: 40,
fill: 0xFFFFFF
}));
vsText.anchor.set(0.5, 0.5);
vsText.x = -100;
vsText.y = -250;
var shopBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var shopText = mainMenu.addChild(new Text2("Mağaza", {
size: 40,
fill: 0xFFFFFF
}));
shopText.anchor.set(0.5, 0.5);
shopText.x = 100;
shopText.y = -250;
var extraBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var extraText = mainMenu.addChild(new Text2("Ekstra", {
size: 40,
fill: 0xFFFFFF
}));
extraText.anchor.set(0.5, 0.5);
extraText.x = 300;
extraText.y = -250;
// Add Enter Match button
var enterMatchBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50,
scaleX: 1.2,
scaleY: 0.8
}));
enterMatchBtn.tint = 0x00AA00;
var enterMatchText = mainMenu.addChild(new Text2("Maça Girme", {
size: 50,
fill: 0xFFFFFF
}));
enterMatchText.anchor.set(0.5, 0.5);
enterMatchText.x = 0;
enterMatchText.y = -50;
var saveBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 150,
scaleX: 0.8,
scaleY: 0.8
}));
var saveText = mainMenu.addChild(new Text2("Kaydet", {
size: 40,
fill: 0xFFFFFF
}));
saveText.anchor.set(0.5, 0.5);
saveText.x = -200;
saveText.y = 150;
var loadBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 150,
scaleX: 0.8,
scaleY: 0.8
}));
var loadText = mainMenu.addChild(new Text2("Yükle", {
size: 40,
fill: 0xFFFFFF
}));
loadText.anchor.set(0.5, 0.5);
loadText.x = 200;
loadText.y = 150;
var cupBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 300,
scaleX: 0.8,
scaleY: 0.8
}));
var cupText = mainMenu.addChild(new Text2("Kupa", {
size: 40,
fill: 0xFFFFFF
}));
cupText.anchor.set(0.5, 0.5);
cupText.x = -200;
cupText.y = 300;
var cupResetBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 300,
scaleX: 0.8,
scaleY: 0.8
}));
cupResetBtn.tint = 0xFF4444;
var cupResetText = mainMenu.addChild(new Text2("Kupa Sıfırla", {
size: 40,
fill: 0xFFFFFF
}));
cupResetText.anchor.set(0.5, 0.5);
cupResetText.x = 200;
cupResetText.y = 300;
// Add cup counter display
var cupCountText = mainMenu.addChild(new Text2("Kupalar: " + playerCups, {
size: 50,
fill: 0xFFD700
}));
cupCountText.anchor.set(0.5, 0.5);
cupCountText.x = 0;
cupCountText.y = 400;
// Update cup display function
function updateCupDisplay() {
cupCountText.setText("Kupalar: " + playerCups);
}
// Save game function
function saveGame() {
if (!matchInProgress) return;
var gameState = {
currentEnergy: currentEnergy,
playerCups: playerCups,
playerDeck: playerDeck.slice(),
playerUnitsData: [],
enemyUnitsData: [],
playerTowersData: [],
enemyTowersData: []
};
// Save player units data
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
gameState.playerUnitsData.push({
type: unit.type,
x: unit.x,
y: unit.y,
health: unit.health,
attackCooldown: unit.attackCooldown
});
}
// Save enemy units data
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
gameState.enemyUnitsData.push({
type: unit.type,
x: unit.x,
y: unit.y,
health: unit.health,
attackCooldown: unit.attackCooldown
});
}
// Save player towers data
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
gameState.playerTowersData.push({
health: tower.health,
x: tower.x,
y: tower.y,
isKing: tower.isKing
});
}
// Save enemy towers data
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
gameState.enemyTowersData.push({
health: tower.health,
x: tower.x,
y: tower.y,
isKing: tower.isKing
});
}
storage.savedGame = gameState;
}
// Load game function
function loadGame() {
var gameState = storage.savedGame;
if (!gameState) return;
// Clear existing game state
for (var i = 0; i < playerUnits.length; i++) {
playerUnits[i].destroy();
}
playerUnits = [];
for (var i = 0; i < enemyUnits.length; i++) {
enemyUnits[i].destroy();
}
enemyUnits = [];
for (var i = 0; i < projectiles.length; i++) {
projectiles[i].destroy();
}
projectiles = [];
// Restore basic game state
currentEnergy = gameState.currentEnergy || 10;
playerCups = gameState.playerCups || 100;
playerDeck = gameState.playerDeck || ['soldier', 'archer', 'tank', 'wizard'];
// Update UI
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
updateCupDisplay();
// Restore player units
for (var i = 0; i < gameState.playerUnitsData.length; i++) {
var unitData = gameState.playerUnitsData[i];
var unit = new Unit(unitData.type, true);
unit.x = unitData.x;
unit.y = unitData.y;
unit.health = unitData.health;
unit.attackCooldown = unitData.attackCooldown;
game.addChild(unit);
playerUnits.push(unit);
}
// Restore enemy units
for (var i = 0; i < gameState.enemyUnitsData.length; i++) {
var unitData = gameState.enemyUnitsData[i];
var unit = new Unit(unitData.type, false);
unit.x = unitData.x;
unit.y = unitData.y;
unit.health = unitData.health;
unit.attackCooldown = unitData.attackCooldown;
game.addChild(unit);
enemyUnits.push(unit);
}
// Restore towers health
for (var i = 0; i < gameState.playerTowersData.length && i < playerTowers.length; i++) {
var towerData = gameState.playerTowersData[i];
playerTowers[i].health = towerData.health;
// Update tower health bar
var tower = playerTowers[i];
var healthPercent = tower.health / tower.maxHealth;
tower.children[2].scaleX = 2.0 * healthPercent;
tower.children[3].setText(tower.health + '/' + tower.maxHealth);
if (healthPercent > 0.6) {
tower.children[2].tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
tower.children[2].tint = 0xFFFF00; // Yellow for medium health
} else {
tower.children[2].tint = 0xFF0000; // Red for low health
}
}
for (var i = 0; i < gameState.enemyTowersData.length && i < enemyTowers.length; i++) {
var towerData = gameState.enemyTowersData[i];
enemyTowers[i].health = towerData.health;
// Update tower health bar
var tower = enemyTowers[i];
var healthPercent = tower.health / tower.maxHealth;
tower.children[2].scaleX = 2.0 * healthPercent;
tower.children[3].setText(tower.health + '/' + tower.maxHealth);
if (healthPercent > 0.6) {
tower.children[2].tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
tower.children[2].tint = 0xFFFF00; // Yellow for medium health
} else {
tower.children[2].tint = 0xFF0000; // Red for low health
}
}
setupPlayerCards();
mainMenu.visible = false;
matchInProgress = true;
matchTimer = 120 * 60; // Reset timer when loading
matchTimerText.visible = true;
inOvertime = false;
matchTimerText.tint = 0xFFFFFF; // Reset timer color
}
// Button interactions using LK event system
enterMatchBtn.down = function () {
mainMenu.visible = false;
matchInProgress = true;
matchTimer = 120 * 60; // Reset timer to 2 minutes
matchTimerText.visible = true;
inOvertime = false;
matchTimerText.tint = 0xFFFFFF; // Reset timer color
};
myCardsBtn.down = function () {
deckBuilder.show();
};
vsBtn.down = function () {
mainMenu.visible = false;
};
shopBtn.down = function () {
// Shop functionality to be added
};
saveBtn.down = function () {
saveGame();
};
loadBtn.down = function () {
loadGame();
};
cupBtn.down = function () {
// Cup/Trophy functionality to be added
};
cupResetBtn.down = function () {
playerCups = 0;
storage.playerCups = playerCups;
updateCupDisplay();
};
extraBtn.down = function () {
// Extra functionality to be added
};
// Create deck builder
var deckBuilder = new DeckBuilder();
deckBuilder.x = 0;
deckBuilder.y = 0;
LK.gui.center.addChild(deckBuilder);
// Show main menu at start
mainMenu.visible = true;
// Setup initial cards
setupPlayerCards();
// Add deployment area indicator
var deploymentArea = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1783,
scaleY: 0.5
}));
deploymentArea.tint = 0x00FF00;
deploymentArea.alpha = 0.3;
// Add fireball restricted area indicator
var fireballArea = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1683,
scaleX: 0.7,
scaleY: 0.3
}));
fireballArea.tint = 0xFF4500;
fireballArea.alpha = 0.2;
// Add white targeting circle for fireball (initially hidden)
var targetingCircle = game.addChild(LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.4,
scaleY: 2.4
}));
targetingCircle.tint = 0xFFFFFF;
targetingCircle.alpha = 0.5;
targetingCircle.visible = false;
// Simple AI for enemy
var aiTimer = 0;
var aiDeployInterval = 180; // Deploy every 3 seconds
var enemyEnergy = 10;
var enemyMaxEnergy = 10;
var enemyEnergyRegenTimer = 0;
// Enemy deck system - 8 different cards
var enemyDeck = ['soldier', 'archer', 'wizard', 'tank', 'goblin', 'giant', 'healer', 'berserker'];
var enemyHand = [];
var enemyHandSize = 4;
// Initialize enemy hand with different cards from deck
function setupEnemyHand() {
enemyHand = [];
var availableCards = enemyDeck.slice(); // Copy of deck
for (var i = 0; i < enemyHandSize; i++) {
if (availableCards.length === 0) {
availableCards = enemyDeck.slice(); // Refill if needed
}
var randomIndex = Math.floor(Math.random() * availableCards.length);
var cardType = availableCards[randomIndex];
enemyHand.push(cardType);
availableCards.splice(randomIndex, 1); // Remove to prevent duplicates
}
}
// Replace a used card in enemy hand
function replaceEnemyCard(usedCardIndex) {
var currentTypesInHand = [];
for (var i = 0; i < enemyHand.length; i++) {
if (i !== usedCardIndex) {
currentTypesInHand.push(enemyHand[i]);
}
}
// Get available cards not in hand
var availableCards = enemyDeck.filter(function (type) {
return currentTypesInHand.indexOf(type) === -1;
});
// If all cards are in hand, select randomly from deck
var newCardType;
if (availableCards.length > 0) {
newCardType = availableCards[Math.floor(Math.random() * availableCards.length)];
} else {
newCardType = enemyDeck[Math.floor(Math.random() * enemyDeck.length)];
}
enemyHand[usedCardIndex] = newCardType;
}
// Initialize enemy hand
setupEnemyHand();
function updateEnergy() {
// Don't update energy when deck builder is open or match is not in progress
if (deckBuilder.isOpen || !matchInProgress) {
return;
}
energyRegenTimer++;
if (energyRegenTimer >= 60) {
// 1 second at 60 FPS
energyRegenTimer = 0;
if (currentEnergy < maxEnergy) {
currentEnergy++;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
}
}
}
function updateMatchTimer() {
// Don't update timer when deck builder is open or match is not in progress
if (deckBuilder.isOpen || !matchInProgress) {
return;
}
matchTimer--;
if (matchTimer < 0) matchTimer = 0;
// Update timer display
var minutes = Math.floor(matchTimer / (60 * 60));
var seconds = Math.floor(matchTimer % (60 * 60) / 60);
var timeString = (inOvertime ? "UZATMA " : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
matchTimerText.setText(timeString);
// Check if time is up
if (matchTimer <= 0) {
if (!inOvertime) {
// Enter overtime when 2 minutes expire regardless of tower status
inOvertime = true;
matchTimer = 60 * 60; // 1 minute in frames
matchTimerText.tint = 0xFF0000; // Make timer red for overtime
} else {
// Overtime has ended - first check tower count, then total health
var playerTowersAlive = 0;
var enemyTowersAlive = 0;
var playerTowerHealth = 0;
var enemyTowerHealth = 0;
// Count alive towers and sum their health
for (var i = 0; i < playerTowers.length; i++) {
if (playerTowers[i].health > 0) {
playerTowersAlive++;
playerTowerHealth += playerTowers[i].health;
}
}
for (var i = 0; i < enemyTowers.length; i++) {
if (enemyTowers[i].health > 0) {
enemyTowersAlive++;
enemyTowerHealth += enemyTowers[i].health;
}
}
// First check: Compare tower count
if (playerTowersAlive < enemyTowersAlive) {
// Player loses - has fewer towers alive
playerCups -= 5;
if (playerCups < 0) playerCups = 0;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showGameOver();
} else if (enemyTowersAlive < playerTowersAlive) {
// Enemy loses - has fewer towers alive
playerCups += 30;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showYouWin();
} else if (playerTowersAlive === enemyTowersAlive) {
// Same number of towers - check total health
if (playerTowerHealth < enemyTowerHealth) {
// Player loses - has less tower health remaining
playerCups -= 5;
if (playerCups < 0) playerCups = 0;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showGameOver();
} else if (enemyTowerHealth < playerTowerHealth) {
// Enemy loses - has less tower health remaining
playerCups += 30;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showYouWin();
} else {
// Draw - same tower count and health, continue overtime indefinitely until someone wins
// Reset overtime timer for another minute
matchTimer = 60 * 60; // Another minute in frames
}
}
}
}
}
function updateAI() {
// Don't update AI when deck builder is open or match is not in progress
if (deckBuilder.isOpen || !matchInProgress) {
return;
}
// Update enemy energy
enemyEnergyRegenTimer++;
if (enemyEnergyRegenTimer >= 60) {
enemyEnergyRegenTimer = 0;
if (enemyEnergy < enemyMaxEnergy) {
enemyEnergy++;
}
}
aiTimer++;
if (aiTimer >= aiDeployInterval) {
aiTimer = 0;
// Simple AI: deploy random unit or fireball
var actionType = Math.random();
if (actionType < 0.15 && enemyEnergy >= 3) {
// Deploy fireball - only if there are player targets in range
var validTargets = [];
// Check for player units in player area
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0 && unit.y > 1366) {
validTargets.push({
x: unit.x,
y: unit.y
});
}
}
// Check for player towers
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
validTargets.push({
x: tower.x,
y: tower.y
});
}
}
// Only cast fireball if there are valid targets
if (validTargets.length > 0) {
var target = validTargets[Math.floor(Math.random() * validTargets.length)];
var fireballX = target.x + (Math.random() - 0.5) * 200; // Add some randomness
var fireballY = target.y + (Math.random() - 0.5) * 200;
// Keep within bounds
fireballX = Math.max(300, Math.min(1748, fireballX));
fireballY = Math.max(1366, Math.min(2200, fireballY));
// Create fireball projectile
var fireballProjectile = game.addChild(LK.getAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600
}));
// Animate projectile to target location
tween(fireballProjectile, {
x: fireballX,
y: fireballY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create explosion damage area
var explosionRadius = 120;
var explosionDamage = 200;
// Damage all player units in radius
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - fireballX;
var dy = unit.y - fireballY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
unit.takeDamage(explosionDamage);
}
}
}
// Damage player towers in radius
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - fireballX;
var dy = tower.y - fireballY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
tower.takeDamage(explosionDamage);
}
}
}
// Visual effects
LK.effects.flashScreen(0xFF4500, 300);
LK.getSound('explosion').play();
// Remove fireball projectile
fireballProjectile.destroy();
}
});
enemyEnergy -= 3;
}
} else if (actionType < 0.25 && enemyEnergy >= 5) {
// Deploy freeze spell - only if there are player units to freeze
var validFreezeTargets = [];
// Check for player units in any area (freeze can target anywhere)
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
validFreezeTargets.push({
x: unit.x,
y: unit.y
});
}
}
// Only cast freeze if there are valid targets
if (validFreezeTargets.length > 0) {
var target = validFreezeTargets[Math.floor(Math.random() * validFreezeTargets.length)];
var freezeX = target.x + (Math.random() - 0.5) * 200; // Add some randomness
var freezeY = target.y + (Math.random() - 0.5) * 200;
// Keep within bounds
freezeX = Math.max(300, Math.min(1748, freezeX));
freezeY = Math.max(600, Math.min(2200, freezeY));
// Create freeze projectile
var freezeProjectile = game.addChild(LK.getAsset('freeze', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600
}));
// Animate projectile to target location
tween(freezeProjectile, {
x: freezeX,
y: freezeY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create freeze effect area
var freezeRadius = 150;
// Freeze all player units in radius for 3 seconds with rotation
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - freezeX;
var dy = unit.y - freezeY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < freezeRadius) {
// Store original move speed
if (!unit.originalMoveSpeed) unit.originalMoveSpeed = unit.moveSpeed;
// Freeze unit (stop movement)
unit.moveSpeed = 0;
// Add spinning rotation effect
tween(unit, {
rotation: unit.rotation + Math.PI * 6
}, {
duration: 3000,
easing: tween.linear
});
// Restore movement after 3 seconds using closure to capture unit reference
(function (frozenUnit) {
LK.setTimeout(function () {
if (frozenUnit && frozenUnit.health > 0 && frozenUnit.originalMoveSpeed) {
frozenUnit.moveSpeed = frozenUnit.originalMoveSpeed;
}
}, 3000);
})(unit);
}
}
}
// Visual effects
LK.effects.flashScreen(0x87CEEB, 300);
// Remove freeze projectile
freezeProjectile.destroy();
}
});
enemyEnergy -= 5;
}
} else if (actionType < 0.35 && enemyEnergy >= 3) {
// Deploy poison spell - only if there are player targets
var validPoisonTargets = [];
// Check for player units
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
validPoisonTargets.push({
x: unit.x,
y: unit.y
});
}
}
// Check for player towers
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
validPoisonTargets.push({
x: tower.x,
y: tower.y
});
}
}
// Only cast poison if there are valid targets
if (validPoisonTargets.length > 0) {
var target = validPoisonTargets[Math.floor(Math.random() * validPoisonTargets.length)];
var poisonX = target.x + (Math.random() - 0.5) * 200; // Add some randomness
var poisonY = target.y + (Math.random() - 0.5) * 200;
// Keep within bounds
poisonX = Math.max(300, Math.min(1748, poisonX));
poisonY = Math.max(600, Math.min(2200, poisonY));
// Create poison projectile
var poisonProjectile = game.addChild(LK.getAsset('poison', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600
}));
// Animate projectile to target location
tween(poisonProjectile, {
x: poisonX,
y: poisonY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create poison effect circle
var poisonEffect = game.addChild(LK.getAsset('poison', {
anchorX: 0.5,
anchorY: 0.5,
x: poisonX,
y: poisonY,
scaleX: 2,
scaleY: 2
}));
poisonEffect.tint = 0x9ACD32; // Yellow-green poison color
poisonEffect.alpha = 0.7;
// Create poison damage area indicator circle
var poisonAreaCircle = game.addChild(LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: poisonX,
y: poisonY,
scaleX: 2.4,
scaleY: 2.4
}));
poisonAreaCircle.tint = 0x9ACD32; // Yellow-green for poison area
poisonAreaCircle.alpha = 0.3;
// Create poison damage area
var poisonRadius = 120;
var poisonDamage = 80;
// Apply poison damage over 5 seconds for AI poison
var enemyPoisonTimer = 0;
var enemyPoisonInterval = LK.setInterval(function () {
enemyPoisonTimer += 1000;
// Damage all player units in radius every second
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - poisonX;
var dy = unit.y - poisonY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
unit.takeDamage(poisonDamage);
}
}
}
// Damage player towers in radius
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - poisonX;
var dy = tower.y - poisonY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
tower.takeDamage(poisonDamage);
}
}
}
// Stop poison after 5 seconds
if (enemyPoisonTimer >= 5000) {
LK.clearInterval(enemyPoisonInterval);
}
}, 1000);
// Visual effects
LK.effects.flashScreen(0x9ACD32, 300);
// Remove poison effect and area circle after 5 seconds
LK.setTimeout(function () {
poisonEffect.destroy();
poisonAreaCircle.destroy();
LK.clearInterval(enemyPoisonInterval);
}, 5000);
// Remove poison projectile
poisonProjectile.destroy();
}
});
enemyEnergy -= 3;
}
} else if (enemyEnergy >= 2) {
// Deploy regular unit from enemy hand - enemy units spawn in enemy area (above centerline)
var availableCards = [];
for (var i = 0; i < enemyHand.length; i++) {
var cardType = enemyHand[i];
var unitCost = allCardCosts[allCardTypes.indexOf(cardType)];
if (enemyEnergy >= unitCost) {
availableCards.push({
type: cardType,
cost: unitCost,
index: i
});
}
}
if (availableCards.length > 0) {
// Select random available card
var selectedCard = availableCards[Math.floor(Math.random() * availableCards.length)];
// Special case for guardian - spawn 7 units
if (selectedCard.type === 'guardian') {
var baseX = 800 + Math.random() * 400;
var baseY = 900 + Math.random() * 300;
var guardianPositions = [{
x: baseX,
y: baseY
},
// Center
{
x: baseX - 80,
y: baseY - 40
},
// Top left
{
x: baseX + 80,
y: baseY - 40
},
// Top right
{
x: baseX - 80,
y: baseY + 40
},
// Bottom left
{
x: baseX + 80,
y: baseY + 40
},
// Bottom right
{
x: baseX - 120,
y: baseY
},
// Left
{
x: baseX + 120,
y: baseY
} // Right
];
for (var g = 0; g < guardianPositions.length; g++) {
var enemyUnit = new Unit(selectedCard.type, false);
enemyUnit.x = guardianPositions[g].x;
enemyUnit.y = guardianPositions[g].y;
game.addChild(enemyUnit);
enemyUnits.push(enemyUnit);
}
} else {
// Deploy single unit for all other types
var enemyUnit = new Unit(selectedCard.type, false);
enemyUnit.x = 800 + Math.random() * 400;
enemyUnit.y = 900 + Math.random() * 300; // Enemy area only
game.addChild(enemyUnit);
enemyUnits.push(enemyUnit);
}
enemyEnergy -= selectedCard.cost;
// Replace used card in hand
replaceEnemyCard(selectedCard.index);
}
}
}
}
game.move = function (x, y, obj) {
// Show targeting circle for spell cards when selected
if (selectedCard && (selectedCard.type === 'fireball' || selectedCard.type === 'freeze' || selectedCard.type === 'poison')) {
// Show targeting circle for fireball, freeze, and poison
targetingCircle.visible = true;
targetingCircle.x = x;
targetingCircle.y = y;
// Change circle color based on spell type
if (selectedCard.type === 'freeze') {
targetingCircle.tint = 0x87CEEB; // Light blue for freeze
} else if (selectedCard.type === 'poison') {
targetingCircle.tint = 0x9ACD32; // Yellow-green for poison
} else {
targetingCircle.tint = 0xFFFFFF; // White for fireball
}
} else {
targetingCircle.visible = false;
}
};
game.down = function (x, y, obj) {
if (selectedCard) {
// Special handling for fireball spell
if (selectedCard.type === 'fireball') {
// Hide targeting circle
targetingCircle.visible = false;
// Fireball can be deployed anywhere on the battlefield within bounds
var fireballAllowed = y > 600 && y < 2200 && x > 300 && x < 1748;
if (fireballAllowed && currentEnergy >= selectedCard.cost) {
// Create fireball projectile that travels like freeze
var fireballProjectile = game.addChild(LK.getAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2200
}));
// Animate projectile to target location
tween(fireballProjectile, {
x: x,
y: y
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create explosion damage area
var explosionRadius = 120;
var explosionDamage = 200;
// Damage all enemy units in radius
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
unit.takeDamage(explosionDamage);
}
}
}
// Damage enemy towers in radius
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
tower.takeDamage(explosionDamage);
}
}
}
// Visual effects
LK.effects.flashScreen(0xFF4500, 500);
LK.getSound('explosion').play();
// Remove fireball projectile
fireballProjectile.destroy();
}
});
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card and replace
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypesFireball = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypesFireball.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypesFireball = playerDeck.filter(function (type) {
return currentTypesFireball.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypesFireball.length > 0) {
newCardType = availableTypesFireball[Math.floor(Math.random() * availableTypesFireball.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else if (selectedCard.type === 'poison') {
// Hide targeting circle
targetingCircle.visible = false;
// Poison can be thrown anywhere on the field
if (currentEnergy >= selectedCard.cost) {
// Create poison effect circle that damages units in area
var poisonEffect = game.addChild(LK.getAsset('poison', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 2,
scaleY: 2
}));
poisonEffect.tint = 0x9ACD32; // Yellow-green poison color
poisonEffect.alpha = 0.7;
// Create poison damage area indicator circle
var poisonAreaCircle = game.addChild(LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 2.4,
scaleY: 2.4
}));
poisonAreaCircle.tint = 0x9ACD32; // Yellow-green for poison area
poisonAreaCircle.alpha = 0.3;
// Create poison damage area
var poisonRadius = 120;
var poisonDamage = 80;
// Apply poison damage over 5 seconds
var poisonTimer = 0;
var poisonInterval = LK.setInterval(function () {
poisonTimer += 1000;
// Damage all units in radius every second
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
unit.takeDamage(poisonDamage);
}
}
}
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
unit.takeDamage(poisonDamage);
}
}
}
// Damage towers in radius
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
tower.takeDamage(poisonDamage);
}
}
}
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
tower.takeDamage(poisonDamage);
}
}
}
// Stop poison after 5 seconds
if (poisonTimer >= 5000) {
LK.clearInterval(poisonInterval);
}
}, 1000);
// Visual effects
LK.effects.flashScreen(0x9ACD32, 300);
// Remove poison effect and area circle after 5 seconds
LK.setTimeout(function () {
poisonEffect.destroy();
poisonAreaCircle.destroy();
LK.clearInterval(poisonInterval);
}, 5000);
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card and replace
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypesPoison = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypesPoison.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypesPoison = playerDeck.filter(function (type) {
return currentTypesPoison.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypesPoison.length > 0) {
newCardType = availableTypesPoison[Math.floor(Math.random() * availableTypesPoison.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else if (selectedCard.type === 'freeze') {
// Hide targeting circle
targetingCircle.visible = false;
// Freeze can be thrown anywhere on the field
if (currentEnergy >= selectedCard.cost) {
// Create freeze projectile that travels like fireball
var freezeProjectile = game.addChild(LK.getAsset('freeze', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2200
}));
// Animate projectile to target location
tween(freezeProjectile, {
x: x,
y: y
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create freeze effect area
var freezeRadius = 150;
// Freeze all units in radius for 3 seconds with rotation
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < freezeRadius) {
// Store original move speed
if (!unit.originalMoveSpeed) unit.originalMoveSpeed = unit.moveSpeed;
// Freeze unit (stop movement)
unit.moveSpeed = 0;
// Add spinning rotation effect
tween(unit, {
rotation: unit.rotation + Math.PI * 6
}, {
duration: 3000,
easing: tween.linear
});
// Restore movement after 3 seconds using closure to capture unit reference
(function (frozenUnit) {
LK.setTimeout(function () {
if (frozenUnit && frozenUnit.health > 0 && frozenUnit.originalMoveSpeed) {
frozenUnit.moveSpeed = frozenUnit.originalMoveSpeed;
}
}, 3000);
})(unit);
}
}
}
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < freezeRadius) {
// Store original move speed
if (!unit.originalMoveSpeed) unit.originalMoveSpeed = unit.moveSpeed;
// Freeze unit (stop movement)
unit.moveSpeed = 0;
// Add spinning rotation effect
tween(unit, {
rotation: unit.rotation + Math.PI * 6
}, {
duration: 3000,
easing: tween.linear
});
// Restore movement after 3 seconds using closure to capture unit reference
(function (frozenUnit) {
LK.setTimeout(function () {
if (frozenUnit && frozenUnit.health > 0 && frozenUnit.originalMoveSpeed) {
frozenUnit.moveSpeed = frozenUnit.originalMoveSpeed;
}
}, 3000);
})(unit);
}
}
}
// Visual effects
LK.effects.flashScreen(0x87CEEB, 300);
// Remove freeze projectile
freezeProjectile.destroy();
}
});
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card and replace
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypesFreeze = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypesFreeze.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypesFreeze = playerDeck.filter(function (type) {
return currentTypesFreeze.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypesFreeze.length > 0) {
newCardType = availableTypesFreeze[Math.floor(Math.random() * availableTypesFreeze.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else if (y > 1366 && y < 2200) {
// Regular unit deployment - restrict to player's area only (below centerline)
if (currentEnergy >= selectedCard.cost) {
// Deploy unit(s) - special case for guardian spawns 7 units
if (selectedCard.type === 'guardian') {
// Deploy 7 guardians in a formation around the target position
var guardianPositions = [{
x: x,
y: y
},
// Center
{
x: x - 80,
y: y - 40
},
// Top left
{
x: x + 80,
y: y - 40
},
// Top right
{
x: x - 80,
y: y + 40
},
// Bottom left
{
x: x + 80,
y: y + 40
},
// Bottom right
{
x: x - 120,
y: y
},
// Left
{
x: x + 120,
y: y
} // Right
];
for (var g = 0; g < guardianPositions.length; g++) {
var newUnit = new Unit(selectedCard.type, true);
newUnit.x = guardianPositions[g].x;
newUnit.y = guardianPositions[g].y;
game.addChild(newUnit);
playerUnits.push(newUnit);
}
} else {
// Deploy single unit for all other types
var newUnit = new Unit(selectedCard.type, true);
newUnit.x = x;
newUnit.y = y;
game.addChild(newUnit);
playerUnits.push(newUnit);
}
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card from hand and get replacement from deck
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypes = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypes.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypes = playerDeck.filter(function (type) {
return currentTypes.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypes.length > 0) {
newCardType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else {
// Deselect card if clicked outside valid area
if (selectedCard) {
selectedCard.children[0].tint = 0xFFFFFF;
selectedCard.selected = false;
selectedCard = null;
}
targetingCircle.visible = false;
}
}
};
game.update = function () {
updateEnergy();
updateMatchTimer();
updateAI();
// Clean up destroyed units
for (var i = playerUnits.length - 1; i >= 0; i--) {
if (playerUnits[i].health <= 0) {
playerUnits[i].destroy();
playerUnits.splice(i, 1);
}
}
for (var i = enemyUnits.length - 1; i >= 0; i--) {
if (enemyUnits[i].health <= 0) {
enemyUnits[i].destroy();
enemyUnits.splice(i, 1);
}
}
for (var i = projectiles.length - 1; i >= 0; i--) {
if (!projectiles[i].parent) {
projectiles.splice(i, 1);
}
}
// Clean up destroyed towers
for (var i = playerTowers.length - 1; i >= 0; i--) {
if (playerTowers[i].health <= 0 && playerTowers[i].parent) {
playerTowers.splice(i, 1);
}
}
for (var i = enemyTowers.length - 1; i >= 0; i--) {
if (enemyTowers[i].health <= 0 && enemyTowers[i].parent) {
enemyTowers.splice(i, 1);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Card = Container.expand(function (type, cost) {
var self = Container.call(this);
self.type = type;
self.cost = cost;
self.selected = false;
var cardBg = self.attachAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5
});
var unitPreview = self.addChild(LK.getAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
y: -30
}));
var costText = self.addChild(new Text2(cost.toString(), {
size: 40,
fill: 0xFFFFFF
}));
costText.anchor.set(0.5, 0.5);
costText.y = 80;
// Add card name in Turkish
var nameText = self.addChild(new Text2(getCardName(type).toUpperCase(), {
size: 28,
fill: 0xFFFFFF
}));
nameText.anchor.set(0.5, 0.5);
nameText.y = 120;
// Add health display for cards
var cardHealth = getCardHealth(type);
var healthText = self.addChild(new Text2('HP: ' + cardHealth, {
size: 24,
fill: 0xFF0000
}));
healthText.anchor.set(0.5, 0.5);
healthText.y = -110;
// Card selection state
self.selected = false;
self.down = function (x, y, obj) {
if (deckBuilder && deckBuilder.isOpen) {
deckBuilder.selectCard(self.type);
return;
}
// Simple touch deployment - select this card for deployment
if (currentEnergy >= self.cost) {
// Deselect previously selected card
if (selectedCard) {
selectedCard.children[0].tint = 0xFFFFFF;
selectedCard.selected = false;
}
// Select this card
selectedCard = self;
self.selected = true;
cardBg.tint = 0x00FF00;
} else {
// Visual feedback for insufficient energy
cardBg.tint = 0xFF0000;
LK.setTimeout(function () {
cardBg.tint = 0xFFFFFF;
}, 500);
}
};
return self;
});
var DeckBuilder = Container.expand(function () {
var self = Container.call(this);
self.isOpen = false;
self.selectedDeck = [];
self.availableCards = allCardTypes.slice();
var bg = self.attachAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.6
});
bg.tint = 0x222222;
var titleText = self.addChild(new Text2("Tüm Kartlar - 8 Seç", {
size: 60,
fill: 0xFFFFFF
}));
titleText.anchor.set(0.5, 0.5);
titleText.y = -400;
self.show = function () {
self.isOpen = true;
self.visible = true;
self.selectedDeck = [];
titleText.setText("Tüm Kartlar - 8 Seç");
self.refreshCards();
};
self.hide = function () {
self.isOpen = false;
self.visible = false;
};
self.refreshCards = function () {
for (var i = self.children.length - 1; i >= 0; i--) {
if (self.children[i].isCardOption) {
self.children[i].destroy();
}
}
// Show all 15 cards in a 5x3 grid layout
for (var i = 0; i < self.availableCards.length; i++) {
var cardType = self.availableCards[i];
var cost = allCardCosts[allCardTypes.indexOf(cardType)];
var cardOption = self.addChild(new Card(cardType, cost));
cardOption.isCardOption = true;
cardOption.x = -400 + i % 5 * 200;
cardOption.y = -200 + Math.floor(i / 5) * 300;
cardOption.scaleX = 0.8;
cardOption.scaleY = 0.8;
// Update card name text to uppercase for deck builder cards with larger font size
if (cardOption.children.length > 4 && cardOption.children[4] && cardOption.children[4].setText) {
// Create new text with larger font size for deck builder
var oldNameText = cardOption.children[4];
oldNameText.destroy();
var newNameText = cardOption.addChild(new Text2(getCardName(cardType).toUpperCase(), {
size: 45,
fill: 0xFFFFFF
}));
newNameText.anchor.set(0.5, 0.5);
newNameText.y = 135;
}
// Add scale up animation for card preview
tween(cardOption, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeOut
});
// Highlight already selected cards
for (var j = 0; j < self.selectedDeck.length; j++) {
if (self.selectedDeck[j] === cardType) {
cardOption.children[0].tint = 0x00FF00;
break;
}
}
}
};
self.selectCard = function (cardType) {
if (self.selectedDeck.length < 8) {
self.selectedDeck.push(cardType);
// Update title to show progress
titleText.setText("Seçilen: " + self.selectedDeck.length + "/8");
if (self.selectedDeck.length === 8) {
playerDeck = self.selectedDeck.slice();
self.hide();
setupPlayerCards();
}
}
};
self.visible = false;
return self;
});
var Projectile = Container.expand(function (startX, startY, target, damage) {
var self = Container.call(this);
self.x = startX;
self.y = startY;
self.target = target;
self.damage = damage;
self.speed = 8;
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (!self.target || self.target.health <= 0) {
self.destroy();
return;
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.target.height / 2 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 30) {
// Hit target
self.target.takeDamage(self.damage);
self.destroy();
} else {
// Move toward target
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var Tower = Container.expand(function (isPlayer, isKing) {
var self = Container.call(this);
self.isPlayer = isPlayer;
self.isKing = isKing;
self.maxHealth = isKing ? 3000 : 2000;
self.health = self.maxHealth;
self.attackDamage = isKing ? 200 : 150;
self.attackRange = 250;
self.attackCooldown = 0;
self.attackSpeed = 60; // frames between attacks
var assetName = (isPlayer ? 'player' : 'enemy') + (isKing ? 'KingTower' : 'Tower');
var towerGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0
});
// Add health bar background
var healthBarBg = self.attachAsset('energyBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 0.8,
y: -150
});
healthBarBg.tint = 0x444444;
// Add health bar
var healthBar = self.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 0.8,
x: -100,
y: -150
});
healthBar.tint = 0x00FF00;
// Add health text
var healthText = self.addChild(new Text2(self.health + '/' + self.maxHealth, {
size: 30,
fill: 0xFFFFFF
}));
healthText.anchor.set(0.5, 0.5);
healthText.y = -150;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = 2.0 * healthPercent;
healthText.setText(self.health + '/' + self.maxHealth);
// Color health bar based on health percentage
if (healthPercent > 0.6) {
healthBar.tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
healthBar.tint = 0xFFFF00; // Yellow for medium health
} else {
healthBar.tint = 0xFF0000; // Red for low health
}
// Flash effect
LK.effects.flashObject(towerGraphics, 0xFF0000, 300);
LK.getSound('towerHit').play();
if (self.health <= 0) {
// Gain elixir when destroying enemy towers
if (self.isPlayer === false && currentElixir < maxElixir) {
currentElixir += 3; // More elixir for towers
if (currentElixir > maxElixir) currentElixir = maxElixir;
var elixirPercent = currentElixir / maxElixir;
elixirBar.scaleX = 1.0 * elixirPercent;
elixirText.setText("İksir: " + currentElixir + "/" + maxElixir);
}
self.destroy();
if (isKing) {
if (isPlayer) {
LK.showGameOver();
} else {
LK.showYouWin();
}
}
}
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
return;
}
// Find closest enemy unit
var targetUnits = self.isPlayer ? enemyUnits : playerUnits;
var closestUnit = null;
var closestDistance = Infinity;
for (var i = 0; i < targetUnits.length; i++) {
var unit = targetUnits[i];
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.attackRange && distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
if (closestUnit) {
self.attackCooldown = self.attackSpeed;
// Create projectile
var projectile = new Projectile(self.x, self.y - 50, closestUnit, self.attackDamage);
game.addChild(projectile);
projectiles.push(projectile);
}
};
return self;
});
var Unit = Container.expand(function (type, isPlayer) {
var self = Container.call(this);
self.isPlayer = isPlayer;
self.type = type;
self.moveSpeed = 2;
self.attackDamage = 100;
self.attackRange = 80;
self.attackCooldown = 0;
self.attackSpeed = 60;
self.target = null;
// Set stats based on type
switch (type) {
case 'soldier':
self.maxHealth = 400;
self.moveSpeed = 2;
self.attackDamage = 80;
break;
case 'archer':
self.maxHealth = 200;
self.moveSpeed = 2.5;
self.attackDamage = 60;
self.attackRange = 150;
break;
case 'tank':
self.maxHealth = 800;
self.moveSpeed = 1;
self.attackDamage = 120;
break;
case 'wizard':
self.maxHealth = 300;
self.moveSpeed = 2;
self.attackDamage = 150;
self.attackRange = 180;
break;
case 'dragon':
self.maxHealth = 1200;
self.moveSpeed = 1.5;
self.attackDamage = 200;
self.attackRange = 200;
break;
case 'freeze':
self.maxHealth = 280;
self.moveSpeed = 1.8;
self.attackDamage = 80;
self.attackRange = 150;
break;
case 'goblin':
self.maxHealth = 150;
self.moveSpeed = 3;
self.attackDamage = 50;
break;
case 'giant':
self.maxHealth = 1500;
self.moveSpeed = 0.8;
self.attackDamage = 250;
break;
case 'healer':
self.maxHealth = 250;
self.moveSpeed = 2;
self.attackDamage = 20;
self.attackRange = 160;
break;
case 'assassin':
self.maxHealth = 180;
self.moveSpeed = 3.5;
self.attackDamage = 120;
break;
case 'bomber':
self.maxHealth = 220;
self.moveSpeed = 2.2;
self.attackDamage = 180;
self.attackRange = 140;
break;
break;
case 'guardian':
self.maxHealth = 215; // Reduced from 750 since 7 spawn
self.moveSpeed = 1.5;
self.attackDamage = 32; // Reduced from 95 since 7 spawn
break;
case 'berserker':
self.maxHealth = 500;
self.moveSpeed = 2.3;
self.attackDamage = 140;
break;
break;
}
self.health = self.maxHealth;
var unitGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 1.0
});
if (!isPlayer) {
unitGraphics.scaleX = -1; // Flip enemy units
}
// Add health bar background
var healthBarBg = self.attachAsset('energyBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.4,
y: -120
});
healthBarBg.tint = 0x000000;
// Add health bar
var healthBar = self.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.4,
x: -50,
y: -120
});
healthBar.tint = 0x00FF00;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = 1.0 * healthPercent;
// Color health bar based on health percentage
if (healthPercent > 0.6) {
healthBar.tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
healthBar.tint = 0xFFFF00; // Yellow for medium health
} else {
healthBar.tint = 0xFF0000; // Red for low health
}
if (self.health <= 0) {
LK.effects.flashObject(unitGraphics, 0xFF0000, 200);
LK.getSound('unitDeath').play();
// Gain elixir when destroying enemy units
if (self.isPlayer === false && currentElixir < maxElixir) {
currentElixir += elixirGainAmount;
if (currentElixir > maxElixir) currentElixir = maxElixir;
var elixirPercent = currentElixir / maxElixir;
elixirBar.scaleX = 1.0 * elixirPercent;
elixirText.setText("İksir: " + currentElixir + "/" + maxElixir);
}
self.destroy();
} else {
LK.effects.flashObject(unitGraphics, 0xFF0000, 150);
}
};
self.findTarget = function () {
var targetUnits = self.isPlayer ? enemyUnits : playerUnits;
var targetTowers = self.isPlayer ? enemyTowers : playerTowers;
var allTargets = targetUnits.concat(targetTowers);
var closest = null;
var closestDistance = Infinity;
for (var i = 0; i < allTargets.length; i++) {
var target = allTargets[i];
if (!target || target.health <= 0) continue;
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closest = target;
}
}
return closest;
};
self.update = function () {
// Special behavior for healer units
if (self.type === 'healer') {
// Find injured teammates to heal
var targetUnits = self.isPlayer ? playerUnits : enemyUnits;
var healTarget = null;
var closestDistance = Infinity;
// Find closest injured teammate within healing range
for (var i = 0; i < targetUnits.length; i++) {
var unit = targetUnits[i];
if (unit && unit !== self && unit.health > 0 && unit.health < unit.maxHealth) {
var dx = unit.x - self.x;
var dy = unit.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && distance < closestDistance) {
closestDistance = distance;
healTarget = unit;
}
}
}
if (healTarget) {
// Heal teammate
if (self.attackCooldown <= 0) {
self.attackCooldown = self.attackSpeed;
// Heal the target
var healAmount = 50; // Healing amount per cast
healTarget.health += healAmount;
if (healTarget.health > healTarget.maxHealth) {
healTarget.health = healTarget.maxHealth;
}
// Update healed unit's health bar
var healedHealthPercent = healTarget.health / healTarget.maxHealth;
if (healTarget.children[3]) {
healTarget.children[3].scaleX = 1.0 * healedHealthPercent;
// Color health bar based on health percentage
if (healedHealthPercent > 0.6) {
healTarget.children[3].tint = 0x00FF00; // Green for high health
} else if (healedHealthPercent > 0.3) {
healTarget.children[3].tint = 0xFFFF00; // Yellow for medium health
} else {
healTarget.children[3].tint = 0xFF0000; // Red for low health
}
}
// Visual healing effects
// Visual healing effects
LK.effects.flashObject(self, 0x00FF00, 200); // Green flash for healer
LK.effects.flashObject(healTarget, 0x00FF00, 300); // Green flash for healed unit
}
} else {
// No injured teammates nearby, find enemy to attack
if (!self.target || self.target.health <= 0) {
self.target = self.findTarget();
}
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange) {
// Attack enemy
if (self.attackCooldown <= 0) {
self.attackCooldown = self.attackSpeed;
LK.effects.flashObject(self, 0xFFFF00, 200);
var projectile = new Projectile(self.x, self.y - 40, self.target, self.attackDamage);
game.addChild(projectile);
projectiles.push(projectile);
}
} else {
// Move toward enemy target
var moveX = dx / distance * self.moveSpeed;
var moveY = dy / distance * self.moveSpeed;
self.x += moveX;
self.y += moveY;
}
}
}
} else {
// Normal unit behavior for non-healers
if (!self.target || self.target.health <= 0) {
self.target = self.findTarget();
}
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange) {
// Attack
if (self.attackCooldown <= 0) {
self.attackCooldown = self.attackSpeed;
// Create attack effects
LK.effects.flashObject(self, 0xFFFF00, 200);
if (self.type === 'archer' || self.type === 'wizard' || self.type === 'dragon' || self.type === 'bomber' || self.type === 'freeze') {
// Ranged attack with projectile
var projectile = new Projectile(self.x, self.y - 40, self.target, self.attackDamage);
game.addChild(projectile);
projectiles.push(projectile);
} else {
// Melee attack with effects
if (self.type === 'bomber') {
// Bomber creates explosion effect
LK.effects.flashObject(self.target, 0xFF4500, 400);
LK.getSound('explosion').play();
} else if (self.type === 'berserker') {
// Berserker gets damage boost when low health
var damageBonus = self.health < self.maxHealth * 0.3 ? 50 : 0;
self.target.takeDamage(self.attackDamage + damageBonus);
LK.effects.flashObject(self, 0xDC143C, 300);
} else {
self.target.takeDamage(self.attackDamage);
}
}
}
} else {
// Move toward target
var moveX = dx / distance * self.moveSpeed;
var moveY = dy / distance * self.moveSpeed;
self.x += moveX;
self.y += moveY;
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var currentEnergy = 10;
var maxEnergy = 10;
var energyRegenRate = 1; // energy per second
var energyRegenTimer = 0;
var currentElixir = 0;
var maxElixir = 10;
var elixirGainAmount = 1;
var playerUnits = [];
var enemyUnits = [];
var playerTowers = [];
var enemyTowers = [];
var projectiles = [];
var playerCards = [];
var selectedCard = null;
var playerCups = storage.playerCups || 100; // Starting cups
var matchInProgress = false;
var matchTimer = 120 * 60; // 2 minutes in frames (60 FPS)
var matchTimerText = null;
var inOvertime = false;
// Override LK's game over and win functions to handle cup system
LK.showGameOver = function () {
playerCups -= 5;
if (playerCups < 0) playerCups = 0;
storage.playerCups = playerCups;
matchInProgress = false;
// Reset game state
game.destroy();
// Restart the game
location.reload();
};
LK.showYouWin = function () {
playerCups += 30;
storage.playerCups = playerCups;
matchInProgress = false;
// Reset game state
game.destroy();
// Restart the game
location.reload();
};
// Arena setup
var arena = game.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// Add red centerline
var centerLine = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// River removed
// Bridges removed
// Create towers
// Player towers (bottom)
var playerKingTower = new Tower(true, true);
playerKingTower.x = 1024;
playerKingTower.y = 2200;
game.addChild(playerKingTower);
playerTowers.push(playerKingTower);
var playerLeftTower = new Tower(true, false);
playerLeftTower.x = 600;
playerLeftTower.y = 2000;
game.addChild(playerLeftTower);
playerTowers.push(playerLeftTower);
var playerRightTower = new Tower(true, false);
playerRightTower.x = 1448;
playerRightTower.y = 2000;
game.addChild(playerRightTower);
playerTowers.push(playerRightTower);
// Enemy towers (top)
var enemyKingTower = new Tower(false, true);
enemyKingTower.x = 1024;
enemyKingTower.y = 600;
game.addChild(enemyKingTower);
enemyTowers.push(enemyKingTower);
var enemyLeftTower = new Tower(false, false);
enemyLeftTower.x = 600;
enemyLeftTower.y = 800;
game.addChild(enemyLeftTower);
enemyTowers.push(enemyLeftTower);
var enemyRightTower = new Tower(false, false);
enemyRightTower.x = 1448;
enemyRightTower.y = 800;
game.addChild(enemyRightTower);
enemyTowers.push(enemyRightTower);
// UI Setup - moved to bottom left corner
var energyBarBg = LK.gui.bottomLeft.addChild(LK.getAsset('energyBar', {
anchorX: 0,
anchorY: 1.0,
x: 10,
y: -300,
scaleX: 1.0,
scaleY: 0.8
}));
energyBarBg.tint = 0x333333;
var energyBar = LK.gui.bottomLeft.addChild(LK.getAsset('energyBar', {
anchorX: 0,
anchorY: 1.0,
y: -300,
x: 10,
scaleX: 1.0,
scaleY: 0.8
}));
var energyText = LK.gui.bottomLeft.addChild(new Text2("10/10", {
size: 35,
fill: 0xFFFFFF
}));
energyText.anchor.set(0, 1.0);
energyText.x = 60;
energyText.y = -270;
// Elixir bar setup - moved to bottom right corner
var elixirBarBg = LK.gui.bottomRight.addChild(LK.getAsset('energyBar', {
anchorX: 1.0,
anchorY: 1.0,
x: -5,
y: -400,
scaleX: 0.8,
scaleY: 0.6
}));
elixirBarBg.tint = 0x8B4513;
var elixirBar = LK.gui.bottomRight.addChild(LK.getAsset('energyBar', {
anchorX: 0,
anchorY: 1.0,
x: -85,
y: -400,
scaleX: 0.8,
scaleY: 0.6
}));
elixirBar.tint = 0xDDA0DD;
var elixirText = LK.gui.bottomRight.addChild(new Text2("İksir: 0/10", {
size: 30,
fill: 0xFFFFFF
}));
elixirText.anchor.set(0.5, 1.0);
elixirText.x = -45;
elixirText.y = -370;
// Add match timer display
matchTimerText = LK.gui.top.addChild(new Text2("2:00", {
size: 60,
fill: 0xFFFFFF
}));
matchTimerText.anchor.set(0.5, 0);
matchTimerText.y = 100;
matchTimerText.visible = false;
// All available card types (15 total)
var allCardTypes = ['soldier', 'archer', 'tank', 'wizard', 'dragon', 'poison', 'goblin', 'giant', 'healer', 'assassin', 'bomber', 'freeze', 'berserker', 'guardian', 'fireball'];
var allCardCosts = [2, 3, 4, 5, 8, 3, 1, 6, 4, 2, 4, 5, 4, 7, 3];
var playerDeck = ['soldier', 'archer', 'tank', 'wizard', 'dragon', 'poison', 'goblin', 'giant']; // Default 8-card deck
function getCardName(type) {
switch (type) {
case 'soldier':
return 'Asker';
case 'archer':
return 'Okçu';
case 'tank':
return 'Tank';
case 'wizard':
return 'Büyücü';
case 'dragon':
return 'Ejder';
case 'poison':
return 'Zehir';
case 'freeze':
return 'Dondurma';
case 'guardian':
return 'Koruyucu';
case 'goblin':
return 'Goblin';
case 'giant':
return 'Dev';
case 'healer':
return 'Şifacı';
case 'assassin':
return 'Suikastçi';
case 'bomber':
return 'Bombacı';
case 'berserker':
return 'Berserker';
case 'fireball':
return 'Alev Topu';
default:
return 'Bilinmiyen';
}
}
function getCardHealth(type) {
switch (type) {
case 'soldier':
return 400;
case 'archer':
return 200;
case 'tank':
return 800;
case 'wizard':
return 300;
case 'dragon':
return 1200;
case 'poison':
return 250;
case 'freeze':
return 280;
case 'guardian':
return 215;
// Adjusted for 7-unit spawn
case 'goblin':
return 150;
case 'giant':
return 1500;
case 'healer':
return 250;
case 'assassin':
return 180;
case 'bomber':
return 220;
case 'berserker':
return 500;
case 'fireball':
return 100;
default:
return 100;
}
}
function setupPlayerCards() {
// Clear existing cards
for (var i = 0; i < playerCards.length; i++) {
playerCards[i].destroy();
}
playerCards = [];
// Create cards from player deck - ensure different cards in hand
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
var availableTypes = playerDeck.slice(); // Copy of deck
for (var i = 0; i < 4; i++) {
// Randomly select from available types to ensure variety
var randomIndex = Math.floor(Math.random() * availableTypes.length);
var cardType = availableTypes[randomIndex];
// Remove selected type to prevent immediate duplicates
availableTypes.splice(randomIndex, 1);
// If we run out of unique types, refill from deck
if (availableTypes.length === 0) {
availableTypes = playerDeck.slice();
}
var cost = allCardCosts[allCardTypes.indexOf(cardType)];
var card = new Card(cardType, cost);
card.x = startX + i * cardWidth;
card.y = -80;
LK.gui.bottom.addChild(card);
playerCards.push(card);
}
}
// Create main menu
var mainMenu = new Container();
mainMenu.x = 0;
mainMenu.y = 0;
LK.gui.center.addChild(mainMenu);
var menuBg = mainMenu.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
}));
menuBg.tint = 0x1a1a2e;
var titleText = mainMenu.addChild(new Text2("Tower Defense Arena", {
size: 80,
fill: 0xFFFFFF
}));
titleText.anchor.set(0.5, 0.5);
titleText.y = -500;
var myCardsBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var myCardsText = mainMenu.addChild(new Text2("Kartlarım", {
size: 40,
fill: 0xFFFFFF
}));
myCardsText.anchor.set(0.5, 0.5);
myCardsText.x = -300;
myCardsText.y = -250;
var vsBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -100,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var vsText = mainMenu.addChild(new Text2("İki Kişilik", {
size: 40,
fill: 0xFFFFFF
}));
vsText.anchor.set(0.5, 0.5);
vsText.x = -100;
vsText.y = -250;
var shopBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var shopText = mainMenu.addChild(new Text2("Mağaza", {
size: 40,
fill: 0xFFFFFF
}));
shopText.anchor.set(0.5, 0.5);
shopText.x = 100;
shopText.y = -250;
var extraBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: -250,
scaleX: 0.8,
scaleY: 0.8
}));
var extraText = mainMenu.addChild(new Text2("Ekstra", {
size: 40,
fill: 0xFFFFFF
}));
extraText.anchor.set(0.5, 0.5);
extraText.x = 300;
extraText.y = -250;
// Add Enter Match button
var enterMatchBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50,
scaleX: 1.2,
scaleY: 0.8
}));
enterMatchBtn.tint = 0x00AA00;
var enterMatchText = mainMenu.addChild(new Text2("Maça Girme", {
size: 50,
fill: 0xFFFFFF
}));
enterMatchText.anchor.set(0.5, 0.5);
enterMatchText.x = 0;
enterMatchText.y = -50;
var saveBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 150,
scaleX: 0.8,
scaleY: 0.8
}));
var saveText = mainMenu.addChild(new Text2("Kaydet", {
size: 40,
fill: 0xFFFFFF
}));
saveText.anchor.set(0.5, 0.5);
saveText.x = -200;
saveText.y = 150;
var loadBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 150,
scaleX: 0.8,
scaleY: 0.8
}));
var loadText = mainMenu.addChild(new Text2("Yükle", {
size: 40,
fill: 0xFFFFFF
}));
loadText.anchor.set(0.5, 0.5);
loadText.x = 200;
loadText.y = 150;
var cupBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 300,
scaleX: 0.8,
scaleY: 0.8
}));
var cupText = mainMenu.addChild(new Text2("Kupa", {
size: 40,
fill: 0xFFFFFF
}));
cupText.anchor.set(0.5, 0.5);
cupText.x = -200;
cupText.y = 300;
var cupResetBtn = mainMenu.addChild(LK.getAsset('cardSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 300,
scaleX: 0.8,
scaleY: 0.8
}));
cupResetBtn.tint = 0xFF4444;
var cupResetText = mainMenu.addChild(new Text2("Kupa Sıfırla", {
size: 40,
fill: 0xFFFFFF
}));
cupResetText.anchor.set(0.5, 0.5);
cupResetText.x = 200;
cupResetText.y = 300;
// Add cup counter display
var cupCountText = mainMenu.addChild(new Text2("Kupalar: " + playerCups, {
size: 50,
fill: 0xFFD700
}));
cupCountText.anchor.set(0.5, 0.5);
cupCountText.x = 0;
cupCountText.y = 400;
// Update cup display function
function updateCupDisplay() {
cupCountText.setText("Kupalar: " + playerCups);
}
// Save game function
function saveGame() {
if (!matchInProgress) return;
var gameState = {
currentEnergy: currentEnergy,
playerCups: playerCups,
playerDeck: playerDeck.slice(),
playerUnitsData: [],
enemyUnitsData: [],
playerTowersData: [],
enemyTowersData: []
};
// Save player units data
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
gameState.playerUnitsData.push({
type: unit.type,
x: unit.x,
y: unit.y,
health: unit.health,
attackCooldown: unit.attackCooldown
});
}
// Save enemy units data
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
gameState.enemyUnitsData.push({
type: unit.type,
x: unit.x,
y: unit.y,
health: unit.health,
attackCooldown: unit.attackCooldown
});
}
// Save player towers data
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
gameState.playerTowersData.push({
health: tower.health,
x: tower.x,
y: tower.y,
isKing: tower.isKing
});
}
// Save enemy towers data
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
gameState.enemyTowersData.push({
health: tower.health,
x: tower.x,
y: tower.y,
isKing: tower.isKing
});
}
storage.savedGame = gameState;
}
// Load game function
function loadGame() {
var gameState = storage.savedGame;
if (!gameState) return;
// Clear existing game state
for (var i = 0; i < playerUnits.length; i++) {
playerUnits[i].destroy();
}
playerUnits = [];
for (var i = 0; i < enemyUnits.length; i++) {
enemyUnits[i].destroy();
}
enemyUnits = [];
for (var i = 0; i < projectiles.length; i++) {
projectiles[i].destroy();
}
projectiles = [];
// Restore basic game state
currentEnergy = gameState.currentEnergy || 10;
playerCups = gameState.playerCups || 100;
playerDeck = gameState.playerDeck || ['soldier', 'archer', 'tank', 'wizard'];
// Update UI
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
updateCupDisplay();
// Restore player units
for (var i = 0; i < gameState.playerUnitsData.length; i++) {
var unitData = gameState.playerUnitsData[i];
var unit = new Unit(unitData.type, true);
unit.x = unitData.x;
unit.y = unitData.y;
unit.health = unitData.health;
unit.attackCooldown = unitData.attackCooldown;
game.addChild(unit);
playerUnits.push(unit);
}
// Restore enemy units
for (var i = 0; i < gameState.enemyUnitsData.length; i++) {
var unitData = gameState.enemyUnitsData[i];
var unit = new Unit(unitData.type, false);
unit.x = unitData.x;
unit.y = unitData.y;
unit.health = unitData.health;
unit.attackCooldown = unitData.attackCooldown;
game.addChild(unit);
enemyUnits.push(unit);
}
// Restore towers health
for (var i = 0; i < gameState.playerTowersData.length && i < playerTowers.length; i++) {
var towerData = gameState.playerTowersData[i];
playerTowers[i].health = towerData.health;
// Update tower health bar
var tower = playerTowers[i];
var healthPercent = tower.health / tower.maxHealth;
tower.children[2].scaleX = 2.0 * healthPercent;
tower.children[3].setText(tower.health + '/' + tower.maxHealth);
if (healthPercent > 0.6) {
tower.children[2].tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
tower.children[2].tint = 0xFFFF00; // Yellow for medium health
} else {
tower.children[2].tint = 0xFF0000; // Red for low health
}
}
for (var i = 0; i < gameState.enemyTowersData.length && i < enemyTowers.length; i++) {
var towerData = gameState.enemyTowersData[i];
enemyTowers[i].health = towerData.health;
// Update tower health bar
var tower = enemyTowers[i];
var healthPercent = tower.health / tower.maxHealth;
tower.children[2].scaleX = 2.0 * healthPercent;
tower.children[3].setText(tower.health + '/' + tower.maxHealth);
if (healthPercent > 0.6) {
tower.children[2].tint = 0x00FF00; // Green for high health
} else if (healthPercent > 0.3) {
tower.children[2].tint = 0xFFFF00; // Yellow for medium health
} else {
tower.children[2].tint = 0xFF0000; // Red for low health
}
}
setupPlayerCards();
mainMenu.visible = false;
matchInProgress = true;
matchTimer = 120 * 60; // Reset timer when loading
matchTimerText.visible = true;
inOvertime = false;
matchTimerText.tint = 0xFFFFFF; // Reset timer color
}
// Button interactions using LK event system
enterMatchBtn.down = function () {
mainMenu.visible = false;
matchInProgress = true;
matchTimer = 120 * 60; // Reset timer to 2 minutes
matchTimerText.visible = true;
inOvertime = false;
matchTimerText.tint = 0xFFFFFF; // Reset timer color
};
myCardsBtn.down = function () {
deckBuilder.show();
};
vsBtn.down = function () {
mainMenu.visible = false;
};
shopBtn.down = function () {
// Shop functionality to be added
};
saveBtn.down = function () {
saveGame();
};
loadBtn.down = function () {
loadGame();
};
cupBtn.down = function () {
// Cup/Trophy functionality to be added
};
cupResetBtn.down = function () {
playerCups = 0;
storage.playerCups = playerCups;
updateCupDisplay();
};
extraBtn.down = function () {
// Extra functionality to be added
};
// Create deck builder
var deckBuilder = new DeckBuilder();
deckBuilder.x = 0;
deckBuilder.y = 0;
LK.gui.center.addChild(deckBuilder);
// Show main menu at start
mainMenu.visible = true;
// Setup initial cards
setupPlayerCards();
// Add deployment area indicator
var deploymentArea = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1783,
scaleY: 0.5
}));
deploymentArea.tint = 0x00FF00;
deploymentArea.alpha = 0.3;
// Add fireball restricted area indicator
var fireballArea = game.addChild(LK.getAsset('centerLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1683,
scaleX: 0.7,
scaleY: 0.3
}));
fireballArea.tint = 0xFF4500;
fireballArea.alpha = 0.2;
// Add white targeting circle for fireball (initially hidden)
var targetingCircle = game.addChild(LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.4,
scaleY: 2.4
}));
targetingCircle.tint = 0xFFFFFF;
targetingCircle.alpha = 0.5;
targetingCircle.visible = false;
// Simple AI for enemy
var aiTimer = 0;
var aiDeployInterval = 180; // Deploy every 3 seconds
var enemyEnergy = 10;
var enemyMaxEnergy = 10;
var enemyEnergyRegenTimer = 0;
// Enemy deck system - 8 different cards
var enemyDeck = ['soldier', 'archer', 'wizard', 'tank', 'goblin', 'giant', 'healer', 'berserker'];
var enemyHand = [];
var enemyHandSize = 4;
// Initialize enemy hand with different cards from deck
function setupEnemyHand() {
enemyHand = [];
var availableCards = enemyDeck.slice(); // Copy of deck
for (var i = 0; i < enemyHandSize; i++) {
if (availableCards.length === 0) {
availableCards = enemyDeck.slice(); // Refill if needed
}
var randomIndex = Math.floor(Math.random() * availableCards.length);
var cardType = availableCards[randomIndex];
enemyHand.push(cardType);
availableCards.splice(randomIndex, 1); // Remove to prevent duplicates
}
}
// Replace a used card in enemy hand
function replaceEnemyCard(usedCardIndex) {
var currentTypesInHand = [];
for (var i = 0; i < enemyHand.length; i++) {
if (i !== usedCardIndex) {
currentTypesInHand.push(enemyHand[i]);
}
}
// Get available cards not in hand
var availableCards = enemyDeck.filter(function (type) {
return currentTypesInHand.indexOf(type) === -1;
});
// If all cards are in hand, select randomly from deck
var newCardType;
if (availableCards.length > 0) {
newCardType = availableCards[Math.floor(Math.random() * availableCards.length)];
} else {
newCardType = enemyDeck[Math.floor(Math.random() * enemyDeck.length)];
}
enemyHand[usedCardIndex] = newCardType;
}
// Initialize enemy hand
setupEnemyHand();
function updateEnergy() {
// Don't update energy when deck builder is open or match is not in progress
if (deckBuilder.isOpen || !matchInProgress) {
return;
}
energyRegenTimer++;
if (energyRegenTimer >= 60) {
// 1 second at 60 FPS
energyRegenTimer = 0;
if (currentEnergy < maxEnergy) {
currentEnergy++;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
}
}
}
function updateMatchTimer() {
// Don't update timer when deck builder is open or match is not in progress
if (deckBuilder.isOpen || !matchInProgress) {
return;
}
matchTimer--;
if (matchTimer < 0) matchTimer = 0;
// Update timer display
var minutes = Math.floor(matchTimer / (60 * 60));
var seconds = Math.floor(matchTimer % (60 * 60) / 60);
var timeString = (inOvertime ? "UZATMA " : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
matchTimerText.setText(timeString);
// Check if time is up
if (matchTimer <= 0) {
if (!inOvertime) {
// Enter overtime when 2 minutes expire regardless of tower status
inOvertime = true;
matchTimer = 60 * 60; // 1 minute in frames
matchTimerText.tint = 0xFF0000; // Make timer red for overtime
} else {
// Overtime has ended - first check tower count, then total health
var playerTowersAlive = 0;
var enemyTowersAlive = 0;
var playerTowerHealth = 0;
var enemyTowerHealth = 0;
// Count alive towers and sum their health
for (var i = 0; i < playerTowers.length; i++) {
if (playerTowers[i].health > 0) {
playerTowersAlive++;
playerTowerHealth += playerTowers[i].health;
}
}
for (var i = 0; i < enemyTowers.length; i++) {
if (enemyTowers[i].health > 0) {
enemyTowersAlive++;
enemyTowerHealth += enemyTowers[i].health;
}
}
// First check: Compare tower count
if (playerTowersAlive < enemyTowersAlive) {
// Player loses - has fewer towers alive
playerCups -= 5;
if (playerCups < 0) playerCups = 0;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showGameOver();
} else if (enemyTowersAlive < playerTowersAlive) {
// Enemy loses - has fewer towers alive
playerCups += 30;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showYouWin();
} else if (playerTowersAlive === enemyTowersAlive) {
// Same number of towers - check total health
if (playerTowerHealth < enemyTowerHealth) {
// Player loses - has less tower health remaining
playerCups -= 5;
if (playerCups < 0) playerCups = 0;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showGameOver();
} else if (enemyTowerHealth < playerTowerHealth) {
// Enemy loses - has less tower health remaining
playerCups += 30;
storage.playerCups = playerCups;
matchInProgress = false;
LK.showYouWin();
} else {
// Draw - same tower count and health, continue overtime indefinitely until someone wins
// Reset overtime timer for another minute
matchTimer = 60 * 60; // Another minute in frames
}
}
}
}
}
function updateAI() {
// Don't update AI when deck builder is open or match is not in progress
if (deckBuilder.isOpen || !matchInProgress) {
return;
}
// Update enemy energy
enemyEnergyRegenTimer++;
if (enemyEnergyRegenTimer >= 60) {
enemyEnergyRegenTimer = 0;
if (enemyEnergy < enemyMaxEnergy) {
enemyEnergy++;
}
}
aiTimer++;
if (aiTimer >= aiDeployInterval) {
aiTimer = 0;
// Simple AI: deploy random unit or fireball
var actionType = Math.random();
if (actionType < 0.15 && enemyEnergy >= 3) {
// Deploy fireball - only if there are player targets in range
var validTargets = [];
// Check for player units in player area
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0 && unit.y > 1366) {
validTargets.push({
x: unit.x,
y: unit.y
});
}
}
// Check for player towers
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
validTargets.push({
x: tower.x,
y: tower.y
});
}
}
// Only cast fireball if there are valid targets
if (validTargets.length > 0) {
var target = validTargets[Math.floor(Math.random() * validTargets.length)];
var fireballX = target.x + (Math.random() - 0.5) * 200; // Add some randomness
var fireballY = target.y + (Math.random() - 0.5) * 200;
// Keep within bounds
fireballX = Math.max(300, Math.min(1748, fireballX));
fireballY = Math.max(1366, Math.min(2200, fireballY));
// Create fireball projectile
var fireballProjectile = game.addChild(LK.getAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600
}));
// Animate projectile to target location
tween(fireballProjectile, {
x: fireballX,
y: fireballY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create explosion damage area
var explosionRadius = 120;
var explosionDamage = 200;
// Damage all player units in radius
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - fireballX;
var dy = unit.y - fireballY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
unit.takeDamage(explosionDamage);
}
}
}
// Damage player towers in radius
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - fireballX;
var dy = tower.y - fireballY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
tower.takeDamage(explosionDamage);
}
}
}
// Visual effects
LK.effects.flashScreen(0xFF4500, 300);
LK.getSound('explosion').play();
// Remove fireball projectile
fireballProjectile.destroy();
}
});
enemyEnergy -= 3;
}
} else if (actionType < 0.25 && enemyEnergy >= 5) {
// Deploy freeze spell - only if there are player units to freeze
var validFreezeTargets = [];
// Check for player units in any area (freeze can target anywhere)
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
validFreezeTargets.push({
x: unit.x,
y: unit.y
});
}
}
// Only cast freeze if there are valid targets
if (validFreezeTargets.length > 0) {
var target = validFreezeTargets[Math.floor(Math.random() * validFreezeTargets.length)];
var freezeX = target.x + (Math.random() - 0.5) * 200; // Add some randomness
var freezeY = target.y + (Math.random() - 0.5) * 200;
// Keep within bounds
freezeX = Math.max(300, Math.min(1748, freezeX));
freezeY = Math.max(600, Math.min(2200, freezeY));
// Create freeze projectile
var freezeProjectile = game.addChild(LK.getAsset('freeze', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600
}));
// Animate projectile to target location
tween(freezeProjectile, {
x: freezeX,
y: freezeY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create freeze effect area
var freezeRadius = 150;
// Freeze all player units in radius for 3 seconds with rotation
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - freezeX;
var dy = unit.y - freezeY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < freezeRadius) {
// Store original move speed
if (!unit.originalMoveSpeed) unit.originalMoveSpeed = unit.moveSpeed;
// Freeze unit (stop movement)
unit.moveSpeed = 0;
// Add spinning rotation effect
tween(unit, {
rotation: unit.rotation + Math.PI * 6
}, {
duration: 3000,
easing: tween.linear
});
// Restore movement after 3 seconds using closure to capture unit reference
(function (frozenUnit) {
LK.setTimeout(function () {
if (frozenUnit && frozenUnit.health > 0 && frozenUnit.originalMoveSpeed) {
frozenUnit.moveSpeed = frozenUnit.originalMoveSpeed;
}
}, 3000);
})(unit);
}
}
}
// Visual effects
LK.effects.flashScreen(0x87CEEB, 300);
// Remove freeze projectile
freezeProjectile.destroy();
}
});
enemyEnergy -= 5;
}
} else if (actionType < 0.35 && enemyEnergy >= 3) {
// Deploy poison spell - only if there are player targets
var validPoisonTargets = [];
// Check for player units
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
validPoisonTargets.push({
x: unit.x,
y: unit.y
});
}
}
// Check for player towers
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
validPoisonTargets.push({
x: tower.x,
y: tower.y
});
}
}
// Only cast poison if there are valid targets
if (validPoisonTargets.length > 0) {
var target = validPoisonTargets[Math.floor(Math.random() * validPoisonTargets.length)];
var poisonX = target.x + (Math.random() - 0.5) * 200; // Add some randomness
var poisonY = target.y + (Math.random() - 0.5) * 200;
// Keep within bounds
poisonX = Math.max(300, Math.min(1748, poisonX));
poisonY = Math.max(600, Math.min(2200, poisonY));
// Create poison projectile
var poisonProjectile = game.addChild(LK.getAsset('poison', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600
}));
// Animate projectile to target location
tween(poisonProjectile, {
x: poisonX,
y: poisonY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create poison effect circle
var poisonEffect = game.addChild(LK.getAsset('poison', {
anchorX: 0.5,
anchorY: 0.5,
x: poisonX,
y: poisonY,
scaleX: 2,
scaleY: 2
}));
poisonEffect.tint = 0x9ACD32; // Yellow-green poison color
poisonEffect.alpha = 0.7;
// Create poison damage area indicator circle
var poisonAreaCircle = game.addChild(LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: poisonX,
y: poisonY,
scaleX: 2.4,
scaleY: 2.4
}));
poisonAreaCircle.tint = 0x9ACD32; // Yellow-green for poison area
poisonAreaCircle.alpha = 0.3;
// Create poison damage area
var poisonRadius = 120;
var poisonDamage = 80;
// Apply poison damage over 5 seconds for AI poison
var enemyPoisonTimer = 0;
var enemyPoisonInterval = LK.setInterval(function () {
enemyPoisonTimer += 1000;
// Damage all player units in radius every second
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - poisonX;
var dy = unit.y - poisonY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
unit.takeDamage(poisonDamage);
}
}
}
// Damage player towers in radius
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - poisonX;
var dy = tower.y - poisonY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
tower.takeDamage(poisonDamage);
}
}
}
// Stop poison after 5 seconds
if (enemyPoisonTimer >= 5000) {
LK.clearInterval(enemyPoisonInterval);
}
}, 1000);
// Visual effects
LK.effects.flashScreen(0x9ACD32, 300);
// Remove poison effect and area circle after 5 seconds
LK.setTimeout(function () {
poisonEffect.destroy();
poisonAreaCircle.destroy();
LK.clearInterval(enemyPoisonInterval);
}, 5000);
// Remove poison projectile
poisonProjectile.destroy();
}
});
enemyEnergy -= 3;
}
} else if (enemyEnergy >= 2) {
// Deploy regular unit from enemy hand - enemy units spawn in enemy area (above centerline)
var availableCards = [];
for (var i = 0; i < enemyHand.length; i++) {
var cardType = enemyHand[i];
var unitCost = allCardCosts[allCardTypes.indexOf(cardType)];
if (enemyEnergy >= unitCost) {
availableCards.push({
type: cardType,
cost: unitCost,
index: i
});
}
}
if (availableCards.length > 0) {
// Select random available card
var selectedCard = availableCards[Math.floor(Math.random() * availableCards.length)];
// Special case for guardian - spawn 7 units
if (selectedCard.type === 'guardian') {
var baseX = 800 + Math.random() * 400;
var baseY = 900 + Math.random() * 300;
var guardianPositions = [{
x: baseX,
y: baseY
},
// Center
{
x: baseX - 80,
y: baseY - 40
},
// Top left
{
x: baseX + 80,
y: baseY - 40
},
// Top right
{
x: baseX - 80,
y: baseY + 40
},
// Bottom left
{
x: baseX + 80,
y: baseY + 40
},
// Bottom right
{
x: baseX - 120,
y: baseY
},
// Left
{
x: baseX + 120,
y: baseY
} // Right
];
for (var g = 0; g < guardianPositions.length; g++) {
var enemyUnit = new Unit(selectedCard.type, false);
enemyUnit.x = guardianPositions[g].x;
enemyUnit.y = guardianPositions[g].y;
game.addChild(enemyUnit);
enemyUnits.push(enemyUnit);
}
} else {
// Deploy single unit for all other types
var enemyUnit = new Unit(selectedCard.type, false);
enemyUnit.x = 800 + Math.random() * 400;
enemyUnit.y = 900 + Math.random() * 300; // Enemy area only
game.addChild(enemyUnit);
enemyUnits.push(enemyUnit);
}
enemyEnergy -= selectedCard.cost;
// Replace used card in hand
replaceEnemyCard(selectedCard.index);
}
}
}
}
game.move = function (x, y, obj) {
// Show targeting circle for spell cards when selected
if (selectedCard && (selectedCard.type === 'fireball' || selectedCard.type === 'freeze' || selectedCard.type === 'poison')) {
// Show targeting circle for fireball, freeze, and poison
targetingCircle.visible = true;
targetingCircle.x = x;
targetingCircle.y = y;
// Change circle color based on spell type
if (selectedCard.type === 'freeze') {
targetingCircle.tint = 0x87CEEB; // Light blue for freeze
} else if (selectedCard.type === 'poison') {
targetingCircle.tint = 0x9ACD32; // Yellow-green for poison
} else {
targetingCircle.tint = 0xFFFFFF; // White for fireball
}
} else {
targetingCircle.visible = false;
}
};
game.down = function (x, y, obj) {
if (selectedCard) {
// Special handling for fireball spell
if (selectedCard.type === 'fireball') {
// Hide targeting circle
targetingCircle.visible = false;
// Fireball can be deployed anywhere on the battlefield within bounds
var fireballAllowed = y > 600 && y < 2200 && x > 300 && x < 1748;
if (fireballAllowed && currentEnergy >= selectedCard.cost) {
// Create fireball projectile that travels like freeze
var fireballProjectile = game.addChild(LK.getAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2200
}));
// Animate projectile to target location
tween(fireballProjectile, {
x: x,
y: y
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create explosion damage area
var explosionRadius = 120;
var explosionDamage = 200;
// Damage all enemy units in radius
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
unit.takeDamage(explosionDamage);
}
}
}
// Damage enemy towers in radius
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) {
tower.takeDamage(explosionDamage);
}
}
}
// Visual effects
LK.effects.flashScreen(0xFF4500, 500);
LK.getSound('explosion').play();
// Remove fireball projectile
fireballProjectile.destroy();
}
});
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card and replace
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypesFireball = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypesFireball.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypesFireball = playerDeck.filter(function (type) {
return currentTypesFireball.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypesFireball.length > 0) {
newCardType = availableTypesFireball[Math.floor(Math.random() * availableTypesFireball.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else if (selectedCard.type === 'poison') {
// Hide targeting circle
targetingCircle.visible = false;
// Poison can be thrown anywhere on the field
if (currentEnergy >= selectedCard.cost) {
// Create poison effect circle that damages units in area
var poisonEffect = game.addChild(LK.getAsset('poison', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 2,
scaleY: 2
}));
poisonEffect.tint = 0x9ACD32; // Yellow-green poison color
poisonEffect.alpha = 0.7;
// Create poison damage area indicator circle
var poisonAreaCircle = game.addChild(LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 2.4,
scaleY: 2.4
}));
poisonAreaCircle.tint = 0x9ACD32; // Yellow-green for poison area
poisonAreaCircle.alpha = 0.3;
// Create poison damage area
var poisonRadius = 120;
var poisonDamage = 80;
// Apply poison damage over 5 seconds
var poisonTimer = 0;
var poisonInterval = LK.setInterval(function () {
poisonTimer += 1000;
// Damage all units in radius every second
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
unit.takeDamage(poisonDamage);
}
}
}
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
unit.takeDamage(poisonDamage);
}
}
}
// Damage towers in radius
for (var i = 0; i < playerTowers.length; i++) {
var tower = playerTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
tower.takeDamage(poisonDamage);
}
}
}
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.health > 0) {
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < poisonRadius) {
tower.takeDamage(poisonDamage);
}
}
}
// Stop poison after 5 seconds
if (poisonTimer >= 5000) {
LK.clearInterval(poisonInterval);
}
}, 1000);
// Visual effects
LK.effects.flashScreen(0x9ACD32, 300);
// Remove poison effect and area circle after 5 seconds
LK.setTimeout(function () {
poisonEffect.destroy();
poisonAreaCircle.destroy();
LK.clearInterval(poisonInterval);
}, 5000);
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card and replace
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypesPoison = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypesPoison.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypesPoison = playerDeck.filter(function (type) {
return currentTypesPoison.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypesPoison.length > 0) {
newCardType = availableTypesPoison[Math.floor(Math.random() * availableTypesPoison.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else if (selectedCard.type === 'freeze') {
// Hide targeting circle
targetingCircle.visible = false;
// Freeze can be thrown anywhere on the field
if (currentEnergy >= selectedCard.cost) {
// Create freeze projectile that travels like fireball
var freezeProjectile = game.addChild(LK.getAsset('freeze', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2200
}));
// Animate projectile to target location
tween(freezeProjectile, {
x: x,
y: y
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create freeze effect area
var freezeRadius = 150;
// Freeze all units in radius for 3 seconds with rotation
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < freezeRadius) {
// Store original move speed
if (!unit.originalMoveSpeed) unit.originalMoveSpeed = unit.moveSpeed;
// Freeze unit (stop movement)
unit.moveSpeed = 0;
// Add spinning rotation effect
tween(unit, {
rotation: unit.rotation + Math.PI * 6
}, {
duration: 3000,
easing: tween.linear
});
// Restore movement after 3 seconds using closure to capture unit reference
(function (frozenUnit) {
LK.setTimeout(function () {
if (frozenUnit && frozenUnit.health > 0 && frozenUnit.originalMoveSpeed) {
frozenUnit.moveSpeed = frozenUnit.originalMoveSpeed;
}
}, 3000);
})(unit);
}
}
}
for (var i = 0; i < enemyUnits.length; i++) {
var unit = enemyUnits[i];
if (unit && unit.health > 0) {
var dx = unit.x - x;
var dy = unit.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < freezeRadius) {
// Store original move speed
if (!unit.originalMoveSpeed) unit.originalMoveSpeed = unit.moveSpeed;
// Freeze unit (stop movement)
unit.moveSpeed = 0;
// Add spinning rotation effect
tween(unit, {
rotation: unit.rotation + Math.PI * 6
}, {
duration: 3000,
easing: tween.linear
});
// Restore movement after 3 seconds using closure to capture unit reference
(function (frozenUnit) {
LK.setTimeout(function () {
if (frozenUnit && frozenUnit.health > 0 && frozenUnit.originalMoveSpeed) {
frozenUnit.moveSpeed = frozenUnit.originalMoveSpeed;
}
}, 3000);
})(unit);
}
}
}
// Visual effects
LK.effects.flashScreen(0x87CEEB, 300);
// Remove freeze projectile
freezeProjectile.destroy();
}
});
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card and replace
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypesFreeze = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypesFreeze.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypesFreeze = playerDeck.filter(function (type) {
return currentTypesFreeze.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypesFreeze.length > 0) {
newCardType = availableTypesFreeze[Math.floor(Math.random() * availableTypesFreeze.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else if (y > 1366 && y < 2200) {
// Regular unit deployment - restrict to player's area only (below centerline)
if (currentEnergy >= selectedCard.cost) {
// Deploy unit(s) - special case for guardian spawns 7 units
if (selectedCard.type === 'guardian') {
// Deploy 7 guardians in a formation around the target position
var guardianPositions = [{
x: x,
y: y
},
// Center
{
x: x - 80,
y: y - 40
},
// Top left
{
x: x + 80,
y: y - 40
},
// Top right
{
x: x - 80,
y: y + 40
},
// Bottom left
{
x: x + 80,
y: y + 40
},
// Bottom right
{
x: x - 120,
y: y
},
// Left
{
x: x + 120,
y: y
} // Right
];
for (var g = 0; g < guardianPositions.length; g++) {
var newUnit = new Unit(selectedCard.type, true);
newUnit.x = guardianPositions[g].x;
newUnit.y = guardianPositions[g].y;
game.addChild(newUnit);
playerUnits.push(newUnit);
}
} else {
// Deploy single unit for all other types
var newUnit = new Unit(selectedCard.type, true);
newUnit.x = x;
newUnit.y = y;
game.addChild(newUnit);
playerUnits.push(newUnit);
}
currentEnergy -= selectedCard.cost;
var energyPercent = currentEnergy / maxEnergy;
energyBar.scaleX = 1.0 * energyPercent;
energyText.setText(currentEnergy + "/" + maxEnergy);
LK.getSound('cardPlay').play();
// Remove card from hand and get replacement from deck
var cardIndex = playerCards.indexOf(selectedCard);
if (cardIndex !== -1) {
selectedCard.destroy();
playerCards.splice(cardIndex, 1);
// Get current card types in hand to avoid duplicates
var currentTypes = [];
for (var j = 0; j < playerCards.length; j++) {
if (playerCards[j] && playerCards[j] !== selectedCard) {
currentTypes.push(playerCards[j].type);
}
}
// Select a card type not currently in hand if possible
var availableTypes = playerDeck.filter(function (type) {
return currentTypes.indexOf(type) === -1;
});
// If all types are in hand, select randomly from deck
var newCardType;
if (availableTypes.length > 0) {
newCardType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
} else {
newCardType = playerDeck[Math.floor(Math.random() * playerDeck.length)];
}
var newCardCost = allCardCosts[allCardTypes.indexOf(newCardType)];
var newCard = new Card(newCardType, newCardCost);
var cardWidth = 220;
var totalWidth = 4 * cardWidth;
var startX = -(totalWidth / 2) + cardWidth / 2;
newCard.x = startX + cardIndex * cardWidth;
newCard.y = -80;
LK.gui.bottom.addChild(newCard);
playerCards.splice(cardIndex, 0, newCard);
}
}
// Deselect card
selectedCard = null;
targetingCircle.visible = false;
} else {
// Deselect card if clicked outside valid area
if (selectedCard) {
selectedCard.children[0].tint = 0xFFFFFF;
selectedCard.selected = false;
selectedCard = null;
}
targetingCircle.visible = false;
}
}
};
game.update = function () {
updateEnergy();
updateMatchTimer();
updateAI();
// Clean up destroyed units
for (var i = playerUnits.length - 1; i >= 0; i--) {
if (playerUnits[i].health <= 0) {
playerUnits[i].destroy();
playerUnits.splice(i, 1);
}
}
for (var i = enemyUnits.length - 1; i >= 0; i--) {
if (enemyUnits[i].health <= 0) {
enemyUnits[i].destroy();
enemyUnits.splice(i, 1);
}
}
for (var i = projectiles.length - 1; i >= 0; i--) {
if (!projectiles[i].parent) {
projectiles.splice(i, 1);
}
}
// Clean up destroyed towers
for (var i = playerTowers.length - 1; i >= 0; i--) {
if (playerTowers[i].health <= 0 && playerTowers[i].parent) {
playerTowers.splice(i, 1);
}
}
for (var i = enemyTowers.length - 1; i >= 0; i--) {
if (enemyTowers[i].health <= 0 && enemyTowers[i].parent) {
enemyTowers.splice(i, 1);
}
}
};
2d Archer bird eye. In-Game asset. 2d. High contrast. No shadows
2d knight bird. In-Game asset. 2d. High contrast. No shadows
2d bird goblin. In-Game asset. 2d. High contrast. No shadows
2d bird giant. In-Game asset. 2d. High contrast. No shadows
Yer yeşil üstünde köyü yeşil çim olsun
2d assassin bird. In-Game asset. 2d. High contrast. No shadows
2d bird wizard. In-Game asset. 2d. High contrast. No shadows
2d bird bear. In-Game asset. 2d. High contrast. No shadows
2d bird berserker. In-Game asset. 2d. High contrast. No shadows
2d bird bomber. In-Game asset. 2d. High contrast. No shadows
2d bird dragon. In-Game asset. 2d. High contrast. No shadows
Fireball. In-Game asset. 2d. High contrast. No shadows
Card slot. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
2d bird healer. In-Game asset. 2d. High contrast. No shadows
2d Freeze. In-Game asset. 2d. High contrast. No shadows
2d Poison. In-Game asset. 2d. High contrast. No shadows
King tower. In-Game asset. 2d. High contrast. No shadows
Blue Tower. In-Game asset. 2d. High contrast. No shadows
King tower red. In-Game asset. 2d. High contrast. No shadows
Red tower. In-Game asset. 2d. High contrast. No shadows
2d bird guardian. In-Game asset. 2d. High contrast. No shadows