/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
/**** * Classes ****/
var Card = Container.expand(function (cardData) {
var self = Container.call(this);
self.cardData = cardData;
self.isSelected = false;
self.attachAsset(cardData.element.toLowerCase() + 'CardBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.15
});
self.attachAsset(cardData.name.toLowerCase() + 'Card', {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
self.attachAsset('textBackground', {
anchorX: 0.5,
anchorY: 0.5,
y: 95,
alpha: 0.7
});
self.nameText = new Text2(cardData.name, {
size: 24,
fill: 0x000000
});
self.nameText.anchor.set(0.5, 0.5);
self.nameText.y = 70;
self.addChild(self.nameText);
// Referencias directas para facilitar la actualización segura de stats
self.attackText = new Text2('ATK: ' + cardData.attack, {
size: 20,
fill: 0xcc1010,
stroke: 0xFFFFFF,
strokeThickness: 2
});
self.attackText.anchor.set(0.5, 0.5);
self.attackText.y = 95;
self.addChild(self.attackText);
self.defenseText = new Text2('DEF: ' + cardData.defense, {
size: 20,
fill: 0x2795c4,
stroke: 0xFFFFFF,
strokeThickness: 2
});
self.defenseText.anchor.set(0.5, 0.5);
self.defenseText.y = 120;
self.addChild(self.defenseText);
self.setSelected = function (selected) {
self.isSelected = selected;
self.scaleX = selected ? 1.65 : 1.5;
self.scaleY = selected ? 1.65 : 1.5;
};
self.down = function () {
if (gameState === GAME_STATE.SELECT_CARD && !self.isSelected || gameState === GAME_STATE.SELECT_MODE && !self.isSelected) {
selectCard(self);
LK.getSound('cardSelect').play();
}
};
return self;
});
var ModeButton = Container.expand(function (mode) {
var self = Container.call(this);
self.mode = mode;
self.attachAsset(mode.toLowerCase() + 'Button', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(mode.toUpperCase(), {
size: 45,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function () {
if (gameState === GAME_STATE.SELECT_MODE && selectedCard) {
playerMode = mode.toLowerCase();
startBattle();
}
};
return self;
});
var PlayButton = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2('PLAY', {
size: 50,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function () {
if (gameState === GAME_STATE.MENU) {
startGame();
}
};
return self;
});
/****
* Initialize Game
****/
/**** * Main Game Object ****/
var game = new LK.Game({
backgroundColor: 0x0f1419
});
/****
* Game Code
****/
/**** * Constants & Configurations ****/
/**** * Plugins ****/
/**** * State Variables ****/
var GAME_STATE = {
MENU: 'menu',
SELECT_CARD: 'selectCard',
SELECT_MODE: 'selectMode',
BATTLE: 'battle',
RESULT: 'result'
};
var COMBAT_MODE = {
ATTACK: 'attack',
DEFENSE: 'defense'
};
var BATTLE_RESULT = {
PLAYER_WIN: 'playerWin',
ENEMY_WIN: 'enemyWin',
TIE: 'tie'
};
var SCREEN = {
CENTER_X: 1024,
CENTER_Y: 1200
};
var GAME_RULES = {
MAX_HP: 250,
BASE_DAMAGE_MIN: 10,
ADVANTAGE_BONUS: 20
};
var ELEMENT_ADVANTAGES = {
'Fire': 'Air',
'Air': 'Water',
'Water': 'Earth',
'Earth': 'Fire'
};
var cardDatabase = [{
name: 'Sea',
element: 'Water',
attack: 100,
defense: 90
}, {
name: 'Rain',
element: 'Water',
attack: 80,
defense: 90
}, {
name: 'Tsunami',
element: 'Water',
attack: 90,
defense: 100
}, {
name: 'River',
element: 'Water',
attack: 90,
defense: 80
}, {
name: 'Ice',
element: 'Water',
attack: 90,
defense: 90
}, {
name: 'Inferno',
element: 'Fire',
attack: 100,
defense: 90
}, {
name: 'Ember',
element: 'Fire',
attack: 90,
defense: 80
}, {
name: 'Lightning',
element: 'Fire',
attack: 90,
defense: 100
}, {
name: 'Flame',
element: 'Fire',
attack: 90,
defense: 90
}, {
name: 'Spark',
element: 'Fire',
attack: 80,
defense: 90
}, {
name: 'Mountain',
element: 'Earth',
attack: 100,
defense: 90
}, {
name: 'Stone',
element: 'Earth',
attack: 90,
defense: 80
}, {
name: 'Boulder',
element: 'Earth',
attack: 90,
defense: 100
}, {
name: 'Sand',
element: 'Earth',
attack: 80,
defense: 90
}, {
name: 'Crystal',
element: 'Earth',
attack: 90,
defense: 90
}, {
name: 'Tornado',
element: 'Air',
attack: 100,
defense: 90
}, {
name: 'Breeze',
element: 'Air',
attack: 80,
defense: 90
}, {
name: 'Gale',
element: 'Air',
attack: 90,
defense: 90
}, {
name: 'Wind',
element: 'Air',
attack: 90,
defense: 80
}, {
name: 'Storm',
element: 'Air',
attack: 90,
defense: 100
}, {
name: 'Metal',
element: 'Earth',
attack: 100,
defense: 80
}, {
name: 'Cave',
element: 'Earth',
attack: 80,
defense: 100
}, {
name: 'Glacier',
element: 'Water',
attack: 100,
defense: 80
}, {
name: 'Mist',
element: 'Water',
attack: 80,
defense: 100
}, {
name: 'Volcano',
element: 'Fire',
attack: 100,
defense: 80
}, {
name: 'Ashes',
element: 'Fire',
attack: 80,
defense: 100
}, {
name: 'Cloud',
element: 'Air',
attack: 80,
defense: 100
}, {
name: 'Whirlwind',
element: 'Air',
attack: 100,
defense: 80
}, {
name: 'Gaia',
element: 'Earth',
attack: 100,
defense: 100
}, {
name: 'Moon',
element: 'Water',
attack: 100,
defense: 100
}, {
name: 'Sun',
element: 'Fire',
attack: 100,
defense: 100
}, {
name: 'Ether',
element: 'Air',
attack: 100,
defense: 100
}];
var gameState = GAME_STATE.MENU;
var playerHand = [],
enemyHand = [],
usedCards = [];
var selectedCard = null,
enemySelectedCard = null;
var playerMode = null,
enemyMode = null;
var playerHP = GAME_RULES.MAX_HP,
enemyHP = GAME_RULES.MAX_HP;
// UI Containers
var handContainer = new Container(),
modeButtons = new Container(),
battleSquareContainer = new Container();
var battleSquares = [],
statusText = null,
playerModeText = null,
enemyModeText = null;
var enlargedCardContainer = new Container(),
enemyCardContainer = new Container();
var enlargedCard = null,
enemyCard = null;
var playerHPText = null,
enemyHPText = null;
var enemyHandContainer = new Container(),
menuContainer = new Container();
/**** * Core Systems ****/
function initializeGame() {
usedCards = [];
playerHP = GAME_RULES.MAX_HP;
enemyHP = GAME_RULES.MAX_HP;
var shuffledDeck = shuffleArray([].concat(cardDatabase));
for (var i = 0; i < 5; i++) {
playerHand.push(shuffledDeck[i]);
enemyHand.push(shuffledDeck[i + 5]);
usedCards.push(shuffledDeck[i], shuffledDeck[i + 5]);
}
setupUI();
displayPlayerHand();
displayEnemyHand();
updateHPDisplays();
LK.playMusic('backgroundMusic');
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var _ref = [array[j], array[i]];
array[i] = _ref[0];
array[j] = _ref[1];
}
return array;
}
function getUnusedCards() {
return cardDatabase.filter(function (card) {
return !usedCards.some(function (used) {
return used.name === card.name;
});
});
}
function drawNewCard() {
var unused = getUnusedCards();
// Lógica de reciclaje del mazo cuando nos quedamos sin cartas
if (unused.length === 0) {
usedCards = [];
// Mantenemos registradas únicamente las cartas que actualmente están en juego en las manos
playerHand.forEach(function (c) {
if (c) {
usedCards.push(c);
}
});
enemyHand.forEach(function (c) {
if (c) {
usedCards.push(c);
}
});
unused = getUnusedCards(); // Recalculamos con el descarte devuelto al mazo
}
if (unused.length > 0) {
var newCard = unused[Math.floor(Math.random() * unused.length)];
usedCards.push(newCard);
return newCard;
}
return null;
}
function replaceCardInHand(hand, index) {
var newCard = drawNewCard();
if (newCard) {
hand[index] = newCard;
} else {
hand.splice(index, 1);
}
}
/**** * VFX / Game Feel Functions ****/
function showFloatingText(x, y, text, color) {
var floatingObj = new Text2(text, {
size: 100,
fill: color,
stroke: 0xFFFFFF,
strokeThickness: 5
});
floatingObj.anchor.set(0.5, 0.5);
floatingObj.x = x;
floatingObj.y = y;
game.addChild(floatingObj);
tween(floatingObj, {
y: y - 200,
alpha: 0
}, {
duration: 1800,
easing: tween.easeOut,
onFinish: function onFinish() {
return game.removeChild(floatingObj);
}
});
}
function shakeScreen() {
var shakeAmount = 20;
var originalX = game.x;
var originalY = game.y;
var shakes = 0;
var shakeInterval = LK.setInterval(function () {
game.x = originalX + (Math.random() * shakeAmount - shakeAmount / 2);
game.y = originalY + (Math.random() * shakeAmount - shakeAmount / 2);
shakes++;
if (shakes > 10) {
LK.clearInterval(shakeInterval);
game.x = originalX;
game.y = originalY;
}
}, 20);
}
/**** * UI Setup ****/
function setupMenu() {
var centerBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
centerBg.x = SCREEN.CENTER_X;
centerBg.y = SCREEN.CENTER_Y;
game.addChild(centerBg);
for (var i = 0; i < 4; i++) {
var square = LK.getAsset("battleSquare".concat(i + 1), {
anchorX: 0.5,
anchorY: 0.5
});
var angle = i * Math.PI * 2 / 4;
square.x = SCREEN.CENTER_X + Math.cos(angle) * 200;
square.y = SCREEN.CENTER_Y + Math.sin(angle) * 200;
square.startAngle = angle;
game.addChild(square);
battleSquares.push(square);
}
var titleText = new Text2('ELEMENTAL BATTLE', {
size: 150,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4,
font: "serif"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = SCREEN.CENTER_X;
titleText.y = 600;
menuContainer.addChild(titleText);
var playButton = new PlayButton();
playButton.x = SCREEN.CENTER_X;
playButton.y = 1600;
menuContainer.addChild(playButton);
game.addChild(menuContainer);
}
function setupUI() {
handContainer.x = SCREEN.CENTER_X;
handContainer.y = 2400;
game.addChild(handContainer);
var btnAtk = new ModeButton('Attack');
btnAtk.x = 800;
btnAtk.y = 1800;
var btnDef = new ModeButton('Defense');
btnDef.x = 1250;
btnDef.y = 1800;
modeButtons.addChild(btnAtk);
modeButtons.addChild(btnDef);
game.addChild(modeButtons);
modeButtons.visible = false;
battleSquareContainer.x = SCREEN.CENTER_X;
battleSquareContainer.y = SCREEN.CENTER_Y;
game.addChild(battleSquareContainer);
statusText = new Text2('Select a card from your hand', {
size: 100,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = SCREEN.CENTER_X;
statusText.y = 2100;
game.addChild(statusText);
playerModeText = new Text2('', {
size: 72,
fill: 0xFFFF00
});
playerModeText.anchor.set(0.5, 0.5);
playerModeText.x = 800;
playerModeText.y = 1700;
game.addChild(playerModeText);
enemyModeText = new Text2('', {
size: 72,
fill: 0xFF8800
});
enemyModeText.anchor.set(0.5, 0.5);
enemyModeText.x = 1248;
enemyModeText.y = 700;
game.addChild(enemyModeText);
enlargedCardContainer.x = 350;
enlargedCardContainer.y = SCREEN.CENTER_Y;
game.addChild(enlargedCardContainer);
enemyCardContainer.x = 1700;
enemyCardContainer.y = SCREEN.CENTER_Y;
game.addChild(enemyCardContainer);
playerHPText = new Text2('HP: ' + GAME_RULES.MAX_HP, {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
playerHPText.anchor.set(0.5, 0.5);
playerHPText.x = 400;
playerHPText.y = 150;
game.addChild(playerHPText);
enemyHPText = new Text2('HP: ' + GAME_RULES.MAX_HP, {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
enemyHPText.anchor.set(0.5, 0.5);
enemyHPText.x = 1648;
enemyHPText.y = 150;
game.addChild(enemyHPText);
enemyHandContainer.x = SCREEN.CENTER_X;
enemyHandContainer.y = 400;
game.addChild(enemyHandContainer);
}
function updateHPDisplays() {
if (playerHPText) {
playerHPText.setText('HP: ' + Math.max(0, playerHP));
}
if (enemyHPText) {
enemyHPText.setText('HP: ' + Math.max(0, enemyHP));
}
}
function startGame() {
gameState = GAME_STATE.SELECT_CARD;
menuContainer.visible = false;
initializeGame();
[handContainer, enemyHandContainer, statusText, playerModeText, enemyModeText, enlargedCardContainer, enemyCardContainer, playerHPText, enemyHPText].forEach(function (el) {
if (el) {
el.visible = true;
}
});
}
function displayPlayerHand() {
while (handContainer.children.length > 0) {
handContainer.removeChild(handContainer.children[0]);
}
for (var i = 0; i < playerHand.length; i++) {
var card = new Card(playerHand[i]);
card.scaleX = 1.5;
card.scaleY = 1.5;
card.x = (i - 2) * 350;
card.handIndex = i;
handContainer.addChild(card);
}
}
function displayEnemyHand() {
while (enemyHandContainer.children.length > 0) {
enemyHandContainer.removeChild(enemyHandContainer.children[0]);
}
for (var i = 0; i < enemyHand.length; i++) {
var cardBack = LK.getAsset(enemyHand[i].element.toLowerCase() + 'CardBack', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
cardBack.x = (i - 2) * 280;
enemyHandContainer.addChild(cardBack);
}
}
/**** * Battle Flow ****/
function selectCard(cardObj) {
if (selectedCard === cardObj && gameState === GAME_STATE.SELECT_MODE) {
return;
}
for (var i = 0; i < handContainer.children.length; i++) {
handContainer.children[i].setSelected(false);
}
cardObj.setSelected(true);
selectedCard = cardObj;
if (enlargedCard) {
tween.stop(enlargedCard);
tween(enlargedCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 150,
onFinish: function onFinish() {
enlargedCardContainer.removeChild(enlargedCard);
createEnlargedCard(cardObj);
}
});
} else {
createEnlargedCard(cardObj);
}
if (gameState !== GAME_STATE.SELECT_MODE) {
gameState = GAME_STATE.SELECT_MODE;
statusText.setText('Choose Attack or Defense mode');
modeButtons.visible = true;
}
}
function createEnlargedCard(cardObj) {
enlargedCard = new Card(cardObj.cardData);
if (gameState === GAME_STATE.BATTLE && enemySelectedCard && hasTypeAdvantage(cardObj.cardData.element, enemySelectedCard.element)) {
applyBonusVisuals(enlargedCard, cardObj.cardData);
}
setupCardAnimation(enlargedCard, enlargedCardContainer);
}
function createEnemyCardPreview(cardData) {
if (enemyCard) {
tween.stop(enemyCard);
tween(enemyCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 150,
onFinish: function onFinish() {
enemyCardContainer.removeChild(enemyCard);
enemyCard = new Card(cardData);
if (gameState === GAME_STATE.BATTLE && selectedCard && hasTypeAdvantage(cardData.element, selectedCard.cardData.element)) {
applyBonusVisuals(enemyCard, cardData);
}
setupCardAnimation(enemyCard, enemyCardContainer);
}
});
} else {
enemyCard = new Card(cardData);
if (gameState === GAME_STATE.BATTLE && selectedCard && hasTypeAdvantage(cardData.element, selectedCard.cardData.element)) {
applyBonusVisuals(enemyCard, cardData);
}
setupCardAnimation(enemyCard, enemyCardContainer);
}
}
function applyBonusVisuals(cardUI, cardData) {
// Actualización segura utilizando las referencias guardadas
cardUI.attackText.setText('ATK: ' + cardData.attack + " + ".concat(GAME_RULES.ADVANTAGE_BONUS));
cardUI.defenseText.setText('DEF: ' + cardData.defense + " + ".concat(GAME_RULES.ADVANTAGE_BONUS));
var bonus = new Text2("+ ".concat(GAME_RULES.ADVANTAGE_BONUS), {
size: 80,
fill: 0x00FF00,
stroke: 0xFFFFFF,
strokeThickness: 3
});
bonus.anchor.set(0.5, 0.5);
bonus.y = -80;
cardUI.addChild(bonus);
}
function setupCardAnimation(cardUI, container) {
cardUI.scaleX = 0.5;
cardUI.scaleY = 0.5;
cardUI.alpha = 0;
container.addChild(cardUI);
tween(cardUI, {
alpha: 1,
scaleX: 2.75,
scaleY: 2.75
}, {
duration: 300,
easing: tween.easeOut
});
}
function startBattle() {
gameState = GAME_STATE.BATTLE;
modeButtons.visible = false;
if (enlargedCard) {
tween(enlargedCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
return enlargedCardContainer.removeChild(enlargedCard);
}
});
}
enemySelectedCard = enemyHand[Math.floor(Math.random() * enemyHand.length)];
enemyMode = Math.random() < 0.5 ? COMBAT_MODE.ATTACK : COMBAT_MODE.DEFENSE;
statusText.setText('Battle in progress...');
playerModeText.setText('Player: ' + playerMode.toUpperCase());
enemyModeText.setText('Enemy: ' + enemyMode.toUpperCase());
LK.setTimeout(function () {
if (selectedCard) {
createEnlargedCard(selectedCard);
}
createEnemyCardPreview(enemySelectedCard);
}, 300);
LK.setTimeout(resolveBattle, 2500);
LK.getSound('cardBattle').play();
}
function hasTypeAdvantage(attacker, defender) {
return ELEMENT_ADVANTAGES[attacker] === defender;
}
function resolveBattle() {
var playerCard = selectedCard.cardData,
enemyData = enemySelectedCard;
var playerValue = playerMode === COMBAT_MODE.ATTACK ? playerCard.attack : playerCard.defense;
var enemyValue = enemyMode === COMBAT_MODE.ATTACK ? enemyData.attack : enemyData.defense;
if (hasTypeAdvantage(playerCard.element, enemyData.element)) {
playerValue += GAME_RULES.ADVANTAGE_BONUS;
}
if (hasTypeAdvantage(enemyData.element, playerCard.element)) {
enemyValue += GAME_RULES.ADVANTAGE_BONUS;
}
var resultText = '';
if (playerMode === COMBAT_MODE.DEFENSE && enemyMode === COMBAT_MODE.DEFENSE) {
resultText = 'Both defended - no damage taken';
} else if (playerValue > enemyValue) {
var damage = Math.max(GAME_RULES.BASE_DAMAGE_MIN, playerValue - enemyValue);
enemyHP -= damage;
updateHPDisplays();
showFloatingText(1648, 250, '-' + damage, 0xFF0000);
shakeScreen();
resultText = "You strike for ".concat(damage, " damage!");
usedCards.push(enemyData, playerCard);
replaceCardInHand(enemyHand, enemyHand.indexOf(enemySelectedCard));
replaceCardInHand(playerHand, selectedCard.handIndex);
displayEnemyHand();
LK.getSound('cardWin').play();
} else if (enemyValue > playerValue) {
var damage = Math.max(GAME_RULES.BASE_DAMAGE_MIN, enemyValue - playerValue);
playerHP -= damage;
updateHPDisplays();
showFloatingText(400, 250, '-' + damage, 0xFF0000);
shakeScreen();
resultText = "Enemy hits you for ".concat(damage, " damage!");
usedCards.push(playerCard, enemyData);
replaceCardInHand(playerHand, selectedCard.handIndex);
replaceCardInHand(enemyHand, enemyHand.indexOf(enemySelectedCard));
displayEnemyHand();
LK.getSound('cardLose').play();
} else {
resultText = 'Clash tied - no damage taken';
}
statusText.setText(resultText);
LK.setTimeout(checkWinCondition, 2500);
}
function checkWinCondition() {
if (enemyHP <= 0) {
statusText.setText('Victory - The enemy has fallen!');
LK.setTimeout(resetGameToMenu, 3000);
} else if (playerHP <= 0) {
statusText.setText('Game Over - Your HP reached 0!');
LK.setTimeout(resetGameToMenu, 3000);
} else {
resetForNextRound();
}
}
function resetForNextRound() {
selectedCard = null;
enemySelectedCard = null;
playerMode = null;
enemyMode = null;
playerModeText.setText('');
enemyModeText.setText('');
gameState = GAME_STATE.SELECT_CARD;
statusText.setText('Select a card from your hand');
if (enlargedCard) {
tween(enlargedCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
return enlargedCardContainer.removeChild(enlargedCard);
}
});
}
if (enemyCard) {
tween(enemyCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
return enemyCardContainer.removeChild(enemyCard);
}
});
}
displayPlayerHand();
}
// Init
setupMenu();
LK.playMusic('backgroundMusic');
game.update = function () {
var time = LK.ticks * 0.02;
for (var i = 0; i < battleSquares.length; i++) {
var square = battleSquares[i];
if (square && square.startAngle !== undefined) {
square.x = SCREEN.CENTER_X + 200 * Math.cos(square.startAngle + time);
square.y = SCREEN.CENTER_Y + 200 * Math.sin(square.startAngle + time);
}
}
};
function resetGameToMenu() {
gameState = GAME_STATE.MENU;
playerHand = [];
enemyHand = [];
usedCards = [];
selectedCard = null;
enemySelectedCard = null;
while (handContainer.children.length > 0) {
handContainer.removeChild(handContainer.children[0]);
}
while (enemyHandContainer.children.length > 0) {
enemyHandContainer.removeChild(enemyHandContainer.children[0]);
}
if (enlargedCard) {
enlargedCardContainer.removeChild(enlargedCard);
}
if (enemyCard) {
enemyCardContainer.removeChild(enemyCard);
}
[statusText, playerModeText, enemyModeText, playerHPText, enemyHPText, modeButtons, handContainer, enemyHandContainer, enlargedCardContainer, enemyCardContainer].forEach(function (el) {
if (el) {
el.visible = false;
}
});
menuContainer.visible = true;
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
/**** * Classes ****/
var Card = Container.expand(function (cardData) {
var self = Container.call(this);
self.cardData = cardData;
self.isSelected = false;
self.attachAsset(cardData.element.toLowerCase() + 'CardBase', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.15
});
self.attachAsset(cardData.name.toLowerCase() + 'Card', {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
self.attachAsset('textBackground', {
anchorX: 0.5,
anchorY: 0.5,
y: 95,
alpha: 0.7
});
self.nameText = new Text2(cardData.name, {
size: 24,
fill: 0x000000
});
self.nameText.anchor.set(0.5, 0.5);
self.nameText.y = 70;
self.addChild(self.nameText);
// Referencias directas para facilitar la actualización segura de stats
self.attackText = new Text2('ATK: ' + cardData.attack, {
size: 20,
fill: 0xcc1010,
stroke: 0xFFFFFF,
strokeThickness: 2
});
self.attackText.anchor.set(0.5, 0.5);
self.attackText.y = 95;
self.addChild(self.attackText);
self.defenseText = new Text2('DEF: ' + cardData.defense, {
size: 20,
fill: 0x2795c4,
stroke: 0xFFFFFF,
strokeThickness: 2
});
self.defenseText.anchor.set(0.5, 0.5);
self.defenseText.y = 120;
self.addChild(self.defenseText);
self.setSelected = function (selected) {
self.isSelected = selected;
self.scaleX = selected ? 1.65 : 1.5;
self.scaleY = selected ? 1.65 : 1.5;
};
self.down = function () {
if (gameState === GAME_STATE.SELECT_CARD && !self.isSelected || gameState === GAME_STATE.SELECT_MODE && !self.isSelected) {
selectCard(self);
LK.getSound('cardSelect').play();
}
};
return self;
});
var ModeButton = Container.expand(function (mode) {
var self = Container.call(this);
self.mode = mode;
self.attachAsset(mode.toLowerCase() + 'Button', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(mode.toUpperCase(), {
size: 45,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function () {
if (gameState === GAME_STATE.SELECT_MODE && selectedCard) {
playerMode = mode.toLowerCase();
startBattle();
}
};
return self;
});
var PlayButton = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2('PLAY', {
size: 50,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function () {
if (gameState === GAME_STATE.MENU) {
startGame();
}
};
return self;
});
/****
* Initialize Game
****/
/**** * Main Game Object ****/
var game = new LK.Game({
backgroundColor: 0x0f1419
});
/****
* Game Code
****/
/**** * Constants & Configurations ****/
/**** * Plugins ****/
/**** * State Variables ****/
var GAME_STATE = {
MENU: 'menu',
SELECT_CARD: 'selectCard',
SELECT_MODE: 'selectMode',
BATTLE: 'battle',
RESULT: 'result'
};
var COMBAT_MODE = {
ATTACK: 'attack',
DEFENSE: 'defense'
};
var BATTLE_RESULT = {
PLAYER_WIN: 'playerWin',
ENEMY_WIN: 'enemyWin',
TIE: 'tie'
};
var SCREEN = {
CENTER_X: 1024,
CENTER_Y: 1200
};
var GAME_RULES = {
MAX_HP: 250,
BASE_DAMAGE_MIN: 10,
ADVANTAGE_BONUS: 20
};
var ELEMENT_ADVANTAGES = {
'Fire': 'Air',
'Air': 'Water',
'Water': 'Earth',
'Earth': 'Fire'
};
var cardDatabase = [{
name: 'Sea',
element: 'Water',
attack: 100,
defense: 90
}, {
name: 'Rain',
element: 'Water',
attack: 80,
defense: 90
}, {
name: 'Tsunami',
element: 'Water',
attack: 90,
defense: 100
}, {
name: 'River',
element: 'Water',
attack: 90,
defense: 80
}, {
name: 'Ice',
element: 'Water',
attack: 90,
defense: 90
}, {
name: 'Inferno',
element: 'Fire',
attack: 100,
defense: 90
}, {
name: 'Ember',
element: 'Fire',
attack: 90,
defense: 80
}, {
name: 'Lightning',
element: 'Fire',
attack: 90,
defense: 100
}, {
name: 'Flame',
element: 'Fire',
attack: 90,
defense: 90
}, {
name: 'Spark',
element: 'Fire',
attack: 80,
defense: 90
}, {
name: 'Mountain',
element: 'Earth',
attack: 100,
defense: 90
}, {
name: 'Stone',
element: 'Earth',
attack: 90,
defense: 80
}, {
name: 'Boulder',
element: 'Earth',
attack: 90,
defense: 100
}, {
name: 'Sand',
element: 'Earth',
attack: 80,
defense: 90
}, {
name: 'Crystal',
element: 'Earth',
attack: 90,
defense: 90
}, {
name: 'Tornado',
element: 'Air',
attack: 100,
defense: 90
}, {
name: 'Breeze',
element: 'Air',
attack: 80,
defense: 90
}, {
name: 'Gale',
element: 'Air',
attack: 90,
defense: 90
}, {
name: 'Wind',
element: 'Air',
attack: 90,
defense: 80
}, {
name: 'Storm',
element: 'Air',
attack: 90,
defense: 100
}, {
name: 'Metal',
element: 'Earth',
attack: 100,
defense: 80
}, {
name: 'Cave',
element: 'Earth',
attack: 80,
defense: 100
}, {
name: 'Glacier',
element: 'Water',
attack: 100,
defense: 80
}, {
name: 'Mist',
element: 'Water',
attack: 80,
defense: 100
}, {
name: 'Volcano',
element: 'Fire',
attack: 100,
defense: 80
}, {
name: 'Ashes',
element: 'Fire',
attack: 80,
defense: 100
}, {
name: 'Cloud',
element: 'Air',
attack: 80,
defense: 100
}, {
name: 'Whirlwind',
element: 'Air',
attack: 100,
defense: 80
}, {
name: 'Gaia',
element: 'Earth',
attack: 100,
defense: 100
}, {
name: 'Moon',
element: 'Water',
attack: 100,
defense: 100
}, {
name: 'Sun',
element: 'Fire',
attack: 100,
defense: 100
}, {
name: 'Ether',
element: 'Air',
attack: 100,
defense: 100
}];
var gameState = GAME_STATE.MENU;
var playerHand = [],
enemyHand = [],
usedCards = [];
var selectedCard = null,
enemySelectedCard = null;
var playerMode = null,
enemyMode = null;
var playerHP = GAME_RULES.MAX_HP,
enemyHP = GAME_RULES.MAX_HP;
// UI Containers
var handContainer = new Container(),
modeButtons = new Container(),
battleSquareContainer = new Container();
var battleSquares = [],
statusText = null,
playerModeText = null,
enemyModeText = null;
var enlargedCardContainer = new Container(),
enemyCardContainer = new Container();
var enlargedCard = null,
enemyCard = null;
var playerHPText = null,
enemyHPText = null;
var enemyHandContainer = new Container(),
menuContainer = new Container();
/**** * Core Systems ****/
function initializeGame() {
usedCards = [];
playerHP = GAME_RULES.MAX_HP;
enemyHP = GAME_RULES.MAX_HP;
var shuffledDeck = shuffleArray([].concat(cardDatabase));
for (var i = 0; i < 5; i++) {
playerHand.push(shuffledDeck[i]);
enemyHand.push(shuffledDeck[i + 5]);
usedCards.push(shuffledDeck[i], shuffledDeck[i + 5]);
}
setupUI();
displayPlayerHand();
displayEnemyHand();
updateHPDisplays();
LK.playMusic('backgroundMusic');
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var _ref = [array[j], array[i]];
array[i] = _ref[0];
array[j] = _ref[1];
}
return array;
}
function getUnusedCards() {
return cardDatabase.filter(function (card) {
return !usedCards.some(function (used) {
return used.name === card.name;
});
});
}
function drawNewCard() {
var unused = getUnusedCards();
// Lógica de reciclaje del mazo cuando nos quedamos sin cartas
if (unused.length === 0) {
usedCards = [];
// Mantenemos registradas únicamente las cartas que actualmente están en juego en las manos
playerHand.forEach(function (c) {
if (c) {
usedCards.push(c);
}
});
enemyHand.forEach(function (c) {
if (c) {
usedCards.push(c);
}
});
unused = getUnusedCards(); // Recalculamos con el descarte devuelto al mazo
}
if (unused.length > 0) {
var newCard = unused[Math.floor(Math.random() * unused.length)];
usedCards.push(newCard);
return newCard;
}
return null;
}
function replaceCardInHand(hand, index) {
var newCard = drawNewCard();
if (newCard) {
hand[index] = newCard;
} else {
hand.splice(index, 1);
}
}
/**** * VFX / Game Feel Functions ****/
function showFloatingText(x, y, text, color) {
var floatingObj = new Text2(text, {
size: 100,
fill: color,
stroke: 0xFFFFFF,
strokeThickness: 5
});
floatingObj.anchor.set(0.5, 0.5);
floatingObj.x = x;
floatingObj.y = y;
game.addChild(floatingObj);
tween(floatingObj, {
y: y - 200,
alpha: 0
}, {
duration: 1800,
easing: tween.easeOut,
onFinish: function onFinish() {
return game.removeChild(floatingObj);
}
});
}
function shakeScreen() {
var shakeAmount = 20;
var originalX = game.x;
var originalY = game.y;
var shakes = 0;
var shakeInterval = LK.setInterval(function () {
game.x = originalX + (Math.random() * shakeAmount - shakeAmount / 2);
game.y = originalY + (Math.random() * shakeAmount - shakeAmount / 2);
shakes++;
if (shakes > 10) {
LK.clearInterval(shakeInterval);
game.x = originalX;
game.y = originalY;
}
}, 20);
}
/**** * UI Setup ****/
function setupMenu() {
var centerBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
centerBg.x = SCREEN.CENTER_X;
centerBg.y = SCREEN.CENTER_Y;
game.addChild(centerBg);
for (var i = 0; i < 4; i++) {
var square = LK.getAsset("battleSquare".concat(i + 1), {
anchorX: 0.5,
anchorY: 0.5
});
var angle = i * Math.PI * 2 / 4;
square.x = SCREEN.CENTER_X + Math.cos(angle) * 200;
square.y = SCREEN.CENTER_Y + Math.sin(angle) * 200;
square.startAngle = angle;
game.addChild(square);
battleSquares.push(square);
}
var titleText = new Text2('ELEMENTAL BATTLE', {
size: 150,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4,
font: "serif"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = SCREEN.CENTER_X;
titleText.y = 600;
menuContainer.addChild(titleText);
var playButton = new PlayButton();
playButton.x = SCREEN.CENTER_X;
playButton.y = 1600;
menuContainer.addChild(playButton);
game.addChild(menuContainer);
}
function setupUI() {
handContainer.x = SCREEN.CENTER_X;
handContainer.y = 2400;
game.addChild(handContainer);
var btnAtk = new ModeButton('Attack');
btnAtk.x = 800;
btnAtk.y = 1800;
var btnDef = new ModeButton('Defense');
btnDef.x = 1250;
btnDef.y = 1800;
modeButtons.addChild(btnAtk);
modeButtons.addChild(btnDef);
game.addChild(modeButtons);
modeButtons.visible = false;
battleSquareContainer.x = SCREEN.CENTER_X;
battleSquareContainer.y = SCREEN.CENTER_Y;
game.addChild(battleSquareContainer);
statusText = new Text2('Select a card from your hand', {
size: 100,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = SCREEN.CENTER_X;
statusText.y = 2100;
game.addChild(statusText);
playerModeText = new Text2('', {
size: 72,
fill: 0xFFFF00
});
playerModeText.anchor.set(0.5, 0.5);
playerModeText.x = 800;
playerModeText.y = 1700;
game.addChild(playerModeText);
enemyModeText = new Text2('', {
size: 72,
fill: 0xFF8800
});
enemyModeText.anchor.set(0.5, 0.5);
enemyModeText.x = 1248;
enemyModeText.y = 700;
game.addChild(enemyModeText);
enlargedCardContainer.x = 350;
enlargedCardContainer.y = SCREEN.CENTER_Y;
game.addChild(enlargedCardContainer);
enemyCardContainer.x = 1700;
enemyCardContainer.y = SCREEN.CENTER_Y;
game.addChild(enemyCardContainer);
playerHPText = new Text2('HP: ' + GAME_RULES.MAX_HP, {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
playerHPText.anchor.set(0.5, 0.5);
playerHPText.x = 400;
playerHPText.y = 150;
game.addChild(playerHPText);
enemyHPText = new Text2('HP: ' + GAME_RULES.MAX_HP, {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
enemyHPText.anchor.set(0.5, 0.5);
enemyHPText.x = 1648;
enemyHPText.y = 150;
game.addChild(enemyHPText);
enemyHandContainer.x = SCREEN.CENTER_X;
enemyHandContainer.y = 400;
game.addChild(enemyHandContainer);
}
function updateHPDisplays() {
if (playerHPText) {
playerHPText.setText('HP: ' + Math.max(0, playerHP));
}
if (enemyHPText) {
enemyHPText.setText('HP: ' + Math.max(0, enemyHP));
}
}
function startGame() {
gameState = GAME_STATE.SELECT_CARD;
menuContainer.visible = false;
initializeGame();
[handContainer, enemyHandContainer, statusText, playerModeText, enemyModeText, enlargedCardContainer, enemyCardContainer, playerHPText, enemyHPText].forEach(function (el) {
if (el) {
el.visible = true;
}
});
}
function displayPlayerHand() {
while (handContainer.children.length > 0) {
handContainer.removeChild(handContainer.children[0]);
}
for (var i = 0; i < playerHand.length; i++) {
var card = new Card(playerHand[i]);
card.scaleX = 1.5;
card.scaleY = 1.5;
card.x = (i - 2) * 350;
card.handIndex = i;
handContainer.addChild(card);
}
}
function displayEnemyHand() {
while (enemyHandContainer.children.length > 0) {
enemyHandContainer.removeChild(enemyHandContainer.children[0]);
}
for (var i = 0; i < enemyHand.length; i++) {
var cardBack = LK.getAsset(enemyHand[i].element.toLowerCase() + 'CardBack', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
cardBack.x = (i - 2) * 280;
enemyHandContainer.addChild(cardBack);
}
}
/**** * Battle Flow ****/
function selectCard(cardObj) {
if (selectedCard === cardObj && gameState === GAME_STATE.SELECT_MODE) {
return;
}
for (var i = 0; i < handContainer.children.length; i++) {
handContainer.children[i].setSelected(false);
}
cardObj.setSelected(true);
selectedCard = cardObj;
if (enlargedCard) {
tween.stop(enlargedCard);
tween(enlargedCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 150,
onFinish: function onFinish() {
enlargedCardContainer.removeChild(enlargedCard);
createEnlargedCard(cardObj);
}
});
} else {
createEnlargedCard(cardObj);
}
if (gameState !== GAME_STATE.SELECT_MODE) {
gameState = GAME_STATE.SELECT_MODE;
statusText.setText('Choose Attack or Defense mode');
modeButtons.visible = true;
}
}
function createEnlargedCard(cardObj) {
enlargedCard = new Card(cardObj.cardData);
if (gameState === GAME_STATE.BATTLE && enemySelectedCard && hasTypeAdvantage(cardObj.cardData.element, enemySelectedCard.element)) {
applyBonusVisuals(enlargedCard, cardObj.cardData);
}
setupCardAnimation(enlargedCard, enlargedCardContainer);
}
function createEnemyCardPreview(cardData) {
if (enemyCard) {
tween.stop(enemyCard);
tween(enemyCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 150,
onFinish: function onFinish() {
enemyCardContainer.removeChild(enemyCard);
enemyCard = new Card(cardData);
if (gameState === GAME_STATE.BATTLE && selectedCard && hasTypeAdvantage(cardData.element, selectedCard.cardData.element)) {
applyBonusVisuals(enemyCard, cardData);
}
setupCardAnimation(enemyCard, enemyCardContainer);
}
});
} else {
enemyCard = new Card(cardData);
if (gameState === GAME_STATE.BATTLE && selectedCard && hasTypeAdvantage(cardData.element, selectedCard.cardData.element)) {
applyBonusVisuals(enemyCard, cardData);
}
setupCardAnimation(enemyCard, enemyCardContainer);
}
}
function applyBonusVisuals(cardUI, cardData) {
// Actualización segura utilizando las referencias guardadas
cardUI.attackText.setText('ATK: ' + cardData.attack + " + ".concat(GAME_RULES.ADVANTAGE_BONUS));
cardUI.defenseText.setText('DEF: ' + cardData.defense + " + ".concat(GAME_RULES.ADVANTAGE_BONUS));
var bonus = new Text2("+ ".concat(GAME_RULES.ADVANTAGE_BONUS), {
size: 80,
fill: 0x00FF00,
stroke: 0xFFFFFF,
strokeThickness: 3
});
bonus.anchor.set(0.5, 0.5);
bonus.y = -80;
cardUI.addChild(bonus);
}
function setupCardAnimation(cardUI, container) {
cardUI.scaleX = 0.5;
cardUI.scaleY = 0.5;
cardUI.alpha = 0;
container.addChild(cardUI);
tween(cardUI, {
alpha: 1,
scaleX: 2.75,
scaleY: 2.75
}, {
duration: 300,
easing: tween.easeOut
});
}
function startBattle() {
gameState = GAME_STATE.BATTLE;
modeButtons.visible = false;
if (enlargedCard) {
tween(enlargedCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
return enlargedCardContainer.removeChild(enlargedCard);
}
});
}
enemySelectedCard = enemyHand[Math.floor(Math.random() * enemyHand.length)];
enemyMode = Math.random() < 0.5 ? COMBAT_MODE.ATTACK : COMBAT_MODE.DEFENSE;
statusText.setText('Battle in progress...');
playerModeText.setText('Player: ' + playerMode.toUpperCase());
enemyModeText.setText('Enemy: ' + enemyMode.toUpperCase());
LK.setTimeout(function () {
if (selectedCard) {
createEnlargedCard(selectedCard);
}
createEnemyCardPreview(enemySelectedCard);
}, 300);
LK.setTimeout(resolveBattle, 2500);
LK.getSound('cardBattle').play();
}
function hasTypeAdvantage(attacker, defender) {
return ELEMENT_ADVANTAGES[attacker] === defender;
}
function resolveBattle() {
var playerCard = selectedCard.cardData,
enemyData = enemySelectedCard;
var playerValue = playerMode === COMBAT_MODE.ATTACK ? playerCard.attack : playerCard.defense;
var enemyValue = enemyMode === COMBAT_MODE.ATTACK ? enemyData.attack : enemyData.defense;
if (hasTypeAdvantage(playerCard.element, enemyData.element)) {
playerValue += GAME_RULES.ADVANTAGE_BONUS;
}
if (hasTypeAdvantage(enemyData.element, playerCard.element)) {
enemyValue += GAME_RULES.ADVANTAGE_BONUS;
}
var resultText = '';
if (playerMode === COMBAT_MODE.DEFENSE && enemyMode === COMBAT_MODE.DEFENSE) {
resultText = 'Both defended - no damage taken';
} else if (playerValue > enemyValue) {
var damage = Math.max(GAME_RULES.BASE_DAMAGE_MIN, playerValue - enemyValue);
enemyHP -= damage;
updateHPDisplays();
showFloatingText(1648, 250, '-' + damage, 0xFF0000);
shakeScreen();
resultText = "You strike for ".concat(damage, " damage!");
usedCards.push(enemyData, playerCard);
replaceCardInHand(enemyHand, enemyHand.indexOf(enemySelectedCard));
replaceCardInHand(playerHand, selectedCard.handIndex);
displayEnemyHand();
LK.getSound('cardWin').play();
} else if (enemyValue > playerValue) {
var damage = Math.max(GAME_RULES.BASE_DAMAGE_MIN, enemyValue - playerValue);
playerHP -= damage;
updateHPDisplays();
showFloatingText(400, 250, '-' + damage, 0xFF0000);
shakeScreen();
resultText = "Enemy hits you for ".concat(damage, " damage!");
usedCards.push(playerCard, enemyData);
replaceCardInHand(playerHand, selectedCard.handIndex);
replaceCardInHand(enemyHand, enemyHand.indexOf(enemySelectedCard));
displayEnemyHand();
LK.getSound('cardLose').play();
} else {
resultText = 'Clash tied - no damage taken';
}
statusText.setText(resultText);
LK.setTimeout(checkWinCondition, 2500);
}
function checkWinCondition() {
if (enemyHP <= 0) {
statusText.setText('Victory - The enemy has fallen!');
LK.setTimeout(resetGameToMenu, 3000);
} else if (playerHP <= 0) {
statusText.setText('Game Over - Your HP reached 0!');
LK.setTimeout(resetGameToMenu, 3000);
} else {
resetForNextRound();
}
}
function resetForNextRound() {
selectedCard = null;
enemySelectedCard = null;
playerMode = null;
enemyMode = null;
playerModeText.setText('');
enemyModeText.setText('');
gameState = GAME_STATE.SELECT_CARD;
statusText.setText('Select a card from your hand');
if (enlargedCard) {
tween(enlargedCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
return enlargedCardContainer.removeChild(enlargedCard);
}
});
}
if (enemyCard) {
tween(enemyCard, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
return enemyCardContainer.removeChild(enemyCard);
}
});
}
displayPlayerHand();
}
// Init
setupMenu();
LK.playMusic('backgroundMusic');
game.update = function () {
var time = LK.ticks * 0.02;
for (var i = 0; i < battleSquares.length; i++) {
var square = battleSquares[i];
if (square && square.startAngle !== undefined) {
square.x = SCREEN.CENTER_X + 200 * Math.cos(square.startAngle + time);
square.y = SCREEN.CENTER_Y + 200 * Math.sin(square.startAngle + time);
}
}
};
function resetGameToMenu() {
gameState = GAME_STATE.MENU;
playerHand = [];
enemyHand = [];
usedCards = [];
selectedCard = null;
enemySelectedCard = null;
while (handContainer.children.length > 0) {
handContainer.removeChild(handContainer.children[0]);
}
while (enemyHandContainer.children.length > 0) {
enemyHandContainer.removeChild(enemyHandContainer.children[0]);
}
if (enlargedCard) {
enlargedCardContainer.removeChild(enlargedCard);
}
if (enemyCard) {
enemyCardContainer.removeChild(enemyCard);
}
[statusText, playerModeText, enemyModeText, playerHPText, enemyHPText, modeButtons, handContainer, enemyHandContainer, enlargedCardContainer, enemyCardContainer].forEach(function (el) {
if (el) {
el.visible = false;
}
});
menuContainer.visible = true;
}
Un tsunami
A Stone
A boulder
An ember
A spark
Three small ember
A river
A wind symbol
Ice floe
A purple cristal rock
Columnas de fuego rojo y azul
Big storm
A cold gale
El margen para una carta que representa el tipo tierra
Un marco para una carta que represente al tipo aire
Un marco para una carta que represente al tipo agua
The rain
A big mountain
Pile of yellow sand
El margen para una carta que representa el tipo fuego
A tornado
The sea
El margen de un botón que indica ataque de un juego de mesa, color rojo sin texto
Crea una versión de este marco en color azul
Marco cuadrado, delgado color dorado con un fondo blanco. In-Game asset. 2d. High contrast. No shadows. card
Símbolo del elemento aire
Símbolo de la tierra color verde
Símbolo del fuego color rojo
Símbolo del agua color azul
A lightning
Crea la parte inversa de una carta que representa el elemento agua, no debe tener texto ni espacio vacío, deben ser corrientes de agua y rocas en la parte inferior
Crea la parte inversa de una carta que representa el elemento fuego, no debe tener texto ni espacio vacío, deben ser flamas y montículos rojos en la parte inferior
Crea la parte inversa de una carta que representa el elemento tierra, no debe tener texto ni espacio vacío, deben ser montículos de tierra y algunas hierbas verdes repartidas
A whirlwind
A cloud
A volcano with lava
Un cubo de hielo
Una niebla densa
an ashes
A brown cave
Una pieza en forma de prisma hexagonal de metal
4 segmentos de flecha que forman un circulo en sentido horario, color morado
The ether
The moon
El símbolo de Gaia, sin texto, color verde y café
The sun