/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
playerLevel: 1,
playerDeck: undefined,
collectedCards: undefined,
currentOpponent: 1
});
/****
* Classes
****/
var Button = Container.expand(function (text) {
var self = Container.call(this);
var buttonBg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
self.buttonText = new Text2(text, {
size: 50,
fill: 0xFFFFFF
});
self.buttonText.anchor.set(0.5, 0.5);
self.addChild(self.buttonText);
self.setText = function (newText) {
self.buttonText.setText(newText);
};
self.down = function (x, y, obj) {
// Button press effect
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
LK.getSound('button_click').play();
};
return self;
});
var DeckCard = Container.expand(function (monster, isSelected) {
var self = Container.call(this);
self.monster = monster;
self.isSelected = isSelected || false;
// Card background
var cardBg = self.attachAsset('deck_select_bg', {
anchorX: 0.5,
anchorY: 0.5
});
// Highlight if selected
if (self.isSelected) {
cardBg.tint = 0x00AAFF;
}
// Monster name
self.nameText = new Text2(monster.name, {
size: 36,
fill: 0xFFFFFF
});
self.nameText.anchor.set(0.5, 0);
self.nameText.y = -150;
self.addChild(self.nameText);
// Monster stats
self.statsText = new Text2("ATK: " + monster.attack + " | HP: " + monster.health, {
size: 32,
fill: 0xFFFFFF
});
self.statsText.anchor.set(0.5, 0);
self.statsText.y = -100;
self.addChild(self.statsText);
// Energy cost
self.costText = new Text2("Cost: " + monster.cost, {
size: 32,
fill: 0xFFFFFF
});
self.costText.anchor.set(0.5, 0);
self.costText.y = -50;
self.addChild(self.costText);
self.toggleSelected = function () {
self.isSelected = !self.isSelected;
if (self.isSelected) {
cardBg.tint = 0x00AAFF;
} else {
cardBg.tint = 0xFFFFFF;
}
return self.isSelected;
};
self.setSelected = function (selected) {
self.isSelected = selected;
if (self.isSelected) {
cardBg.tint = 0x00AAFF;
} else {
cardBg.tint = 0xFFFFFF;
}
};
self.down = function (x, y, obj) {
var result = self.toggleSelected();
if (result) {
game.addToDeck(self.monster);
} else {
game.removeFromDeck(self.monster);
}
};
return self;
});
var GridSlot = Container.expand(function (gridX, gridY) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
self.card = null;
var slotBg = self.attachAsset('monster_bg_slot', {
anchorX: 0.5,
anchorY: 0.5
});
// Make it slightly transparent
slotBg.alpha = 0.5;
self.highlight = function (active) {
if (active) {
slotBg.alpha = 0.8;
} else {
slotBg.alpha = 0.5;
}
};
self.setCard = function (card) {
self.card = card;
if (card) {
card.inHand = false;
card.gridPosition = {
x: self.gridX,
y: self.gridY
};
}
};
self.down = function (x, y, obj) {
if (game.selectedCard && !self.card && game.currentTurn === "player") {
// If we have a selected card from hand and this slot is empty
game.placeCard(game.selectedCard, self);
} else if (game.selectedCardOnBoard && !self.card) {
// Move card on board to new position
game.moveCardOnBoard(game.selectedCardOnBoard, self);
}
};
return self;
});
var MonsterCard = Container.expand(function (monster, isPlayerCard) {
var self = Container.call(this);
self.monster = monster;
self.isPlayerCard = isPlayerCard || false;
self.inHand = true;
self.gridPosition = null;
self.currentHealth = monster.health;
// Card background
var cardBg = self.attachAsset('monster_card', {
anchorX: 0.5,
anchorY: 0.5
});
// Monster name
self.nameText = new Text2(monster.name, {
size: 40,
fill: 0x000000
});
self.nameText.anchor.set(0.5, 0);
self.nameText.y = -160;
self.addChild(self.nameText);
// Monster type
self.typeText = new Text2(monster.type, {
size: 30,
fill: 0x555555
});
self.typeText.anchor.set(0.5, 0);
self.typeText.y = -120;
self.addChild(self.typeText);
// Attack icon and value
var attackIcon = self.attachAsset('attack_icon', {
anchorX: 0.5,
anchorY: 0.5,
x: -80,
y: 120
});
self.attackText = new Text2(monster.attack.toString(), {
size: 40,
fill: 0xFFFFFF
});
self.attackText.anchor.set(0.5, 0.5);
self.attackText.x = -80;
self.attackText.y = 120;
self.addChild(self.attackText);
// Health icon and value
var healthIcon = self.attachAsset('health_icon', {
anchorX: 0.5,
anchorY: 0.5,
x: 80,
y: 120
});
self.healthText = new Text2(self.currentHealth.toString(), {
size: 40,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.healthText.x = 80;
self.healthText.y = 120;
self.addChild(self.healthText);
// Energy cost
var energyIcon = self.attachAsset('energy_icon', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80
});
self.energyText = new Text2(monster.cost.toString(), {
size: 40,
fill: 0xFFFFFF
});
self.energyText.anchor.set(0.5, 0.5);
self.energyText.x = 0;
self.energyText.y = -80;
self.addChild(self.energyText);
// Ability text
self.abilityText = new Text2(monster.ability, {
size: 26,
fill: 0x000000
});
self.abilityText.anchor.set(0.5, 0.5);
self.abilityText.y = 40;
self.abilityText.width = 230;
self.addChild(self.abilityText);
self.updateHealth = function (newHealth) {
self.currentHealth = newHealth;
self.healthText.setText(self.currentHealth.toString());
if (self.currentHealth <= 0) {
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
LK.getSound('card_destroyed').play();
} else {
// Flash the card when damaged
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.attack = function (targetCard) {
if (!targetCard) {
return;
}
LK.getSound('card_attack').play();
// Apply damage
targetCard.updateHealth(targetCard.currentHealth - self.monster.attack);
// Flash the attacking card
LK.effects.flashObject(self, 0xFFFF00, 300);
};
self.down = function (x, y, obj) {
if (self.isPlayerCard && self.inHand && game.currentTurn === "player" && !game.selectedCard) {
game.selectCard(self);
} else if (self.isPlayerCard && !self.inHand && game.selectedCard === null && game.currentTurn === "player") {
// Select card on board
game.selectCardOnBoard(self);
} else if (!self.isPlayerCard && game.selectedCardOnBoard) {
// Attack this enemy card
game.attackCard(game.selectedCardOnBoard, self);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x235789
});
/****
* Game Code
****/
// Game state variables
game.currentScreen = "menu"; // menu, deck, battle
game.selectedCard = null;
game.selectedCardOnBoard = null;
game.playerHand = [];
game.playerEnergy = 0;
game.maxPlayerEnergy = 0;
game.playerDeck = [];
game.playerBoard = []; // 3x3 grid for player
game.enemyBoard = []; // 3x3 grid for enemy
game.currentTurn = "player";
game.boardSlots = [];
game.enemyCards = [];
game.selectedDeck = [];
game.availableCards = [];
game.currentOpponent = 1;
game.battleWon = false;
// Define all monster cards data
var monsterData = [{
id: 1,
name: "Fire Wolf",
type: "Fire",
attack: 3,
health: 4,
cost: 3,
ability: "Deals +1 damage to Plant types"
}, {
id: 2,
name: "Water Sprite",
type: "Water",
attack: 2,
health: 5,
cost: 3,
ability: "Heals 1 HP each turn"
}, {
id: 3,
name: "Stone Golem",
type: "Earth",
attack: 2,
health: 7,
cost: 4,
ability: "Takes 1 less damage from attacks"
}, {
id: 4,
name: "Wind Eagle",
type: "Air",
attack: 4,
health: 2,
cost: 3,
ability: "Can attack any position"
}, {
id: 5,
name: "Leaf Guardian",
type: "Plant",
attack: 2,
health: 6,
cost: 3,
ability: "Heals adjacent allies 1 HP per turn"
}, {
id: 6,
name: "Shadow Thief",
type: "Dark",
attack: 5,
health: 2,
cost: 4,
ability: "50% chance to dodge attacks"
}, {
id: 7,
name: "Light Fairy",
type: "Light",
attack: 1,
health: 3,
cost: 1,
ability: "Generates +1 energy per turn"
}, {
id: 8,
name: "Thunder Drake",
type: "Electric",
attack: 4,
health: 3,
cost: 4,
ability: "Can attack all enemies in a row"
}, {
id: 9,
name: "Ice Bear",
type: "Ice",
attack: 3,
health: 5,
cost: 4,
ability: "Freezes enemy for 1 turn on attack"
}, {
id: 10,
name: "Lava Giant",
type: "Fire",
attack: 5,
health: 5,
cost: 6,
ability: "Deals 1 damage to all adjacent enemies"
}];
// Define opponent data
var opponents = [{
id: 1,
name: "Novice Trainer",
level: 1,
deck: [1, 2, 5, 7]
}, {
id: 2,
name: "Forest Guardian",
level: 2,
deck: [4, 5, 5, 7, 8]
}, {
id: 3,
name: "Flame Master",
level: 3,
deck: [1, 1, 6, 10, 10]
}, {
id: 4,
name: "Guild Champion",
level: 4,
deck: [3, 6, 8, 9, 10]
}];
// Initialize game state
function initGame() {
// Initialize default storage if not set
if (!storage.collectedCards) {
// Start with 6 basic cards
storage.collectedCards = [1, 2, 3, 4, 5, 7];
}
if (!storage.playerDeck) {
// Default deck
storage.playerDeck = [1, 2, 3, 4];
}
// Load player data
game.availableCards = storage.collectedCards;
game.selectedDeck = storage.playerDeck;
game.currentOpponent = storage.currentOpponent || 1;
// Show main menu
showMainMenu();
}
// Create main menu
function showMainMenu() {
game.currentScreen = "menu";
clearScreen();
// Game title
var titleText = new Text2("MONSTER GUILD", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 500;
game.addChild(titleText);
// Battle button
var battleButton = new Button("BATTLE");
battleButton.x = 1024;
battleButton.y = 1200;
battleButton.down = function () {
LK.getSound('button_click').play();
showBattleScreen();
};
game.addChild(battleButton);
// Deck button
var deckButton = new Button("DECK BUILDER");
deckButton.x = 1024;
deckButton.y = 1400;
deckButton.down = function () {
LK.getSound('button_click').play();
showDeckBuilder();
};
game.addChild(deckButton);
// Opponent info
var currentOpponent = opponents.find(function (o) {
return o.id === game.currentOpponent;
});
var opponentText = new Text2("Next Opponent: " + currentOpponent.name + " (Lvl " + currentOpponent.level + ")", {
size: 50,
fill: 0xFFFFFF
});
opponentText.anchor.set(0.5, 0.5);
opponentText.x = 1024;
opponentText.y = 900;
game.addChild(opponentText);
}
// Create deck builder screen
function showDeckBuilder() {
game.currentScreen = "deck";
clearScreen();
// Title
var titleText = new Text2("DECK BUILDER", {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
game.addChild(titleText);
// Instructions
var instructionText = new Text2("Select 5 cards for your deck:", {
size: 40,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 300;
game.addChild(instructionText);
// Display available cards
var cards = [];
game.selectedDeck = [];
for (var i = 0; i < game.availableCards.length; i++) {
var cardId = game.availableCards[i];
var monster = monsterData.find(function (m) {
return m.id === cardId;
});
var isSelected = storage.playerDeck.includes(cardId);
if (isSelected) {
game.selectedDeck.push(cardId);
}
var deckCard = new DeckCard(monster, isSelected);
deckCard.x = 400 + i % 3 * 600;
deckCard.y = 600 + Math.floor(i / 3) * 450;
deckCard.scale.set(0.8);
game.addChild(deckCard);
cards.push(deckCard);
}
// Save button
var saveButton = new Button("SAVE DECK");
saveButton.x = 1024;
saveButton.y = 2400;
saveButton.down = function () {
LK.getSound('button_click').play();
if (game.selectedDeck.length === 0) {
// Can't save empty deck
return;
}
storage.playerDeck = game.selectedDeck;
showMainMenu();
};
game.addChild(saveButton);
// Back button
var backButton = new Button("BACK");
backButton.x = 1024;
backButton.y = 2600;
backButton.down = function () {
LK.getSound('button_click').play();
showMainMenu();
};
game.addChild(backButton);
// Selected count
game.selectedCountText = new Text2("Selected: " + game.selectedDeck.length + " / 5", {
size: 50,
fill: 0xFFFFFF
});
game.selectedCountText.anchor.set(0.5, 0.5);
game.selectedCountText.x = 1024;
game.selectedCountText.y = 2200;
game.addChild(game.selectedCountText);
}
// Create battle screen
function showBattleScreen() {
game.currentScreen = "battle";
clearScreen();
// Play battle music
LK.playMusic('battle_music');
// Initialize battle state
game.playerEnergy = 3;
game.maxPlayerEnergy = 3;
game.currentTurn = "player";
game.playerHand = [];
game.battleWon = false;
// Create player deck for this battle
game.playerDeck = [];
for (var i = 0; i < storage.playerDeck.length; i++) {
var cardId = storage.playerDeck[i];
var monster = monsterData.find(function (m) {
return m.id === cardId;
});
game.playerDeck.push(monster);
}
// Shuffle deck
shuffleArray(game.playerDeck);
// Create grid board
createGameBoard();
// Deal initial hand
for (var j = 0; j < 3; j++) {
if (game.playerDeck.length > 0) {
dealCard();
}
}
// Create enemy deck
var opponent = opponents.find(function (o) {
return o.id === game.currentOpponent;
});
game.enemyDeck = [];
for (var k = 0; k < opponent.deck.length; k++) {
var enemyCardId = opponent.deck[k];
var enemyMonster = monsterData.find(function (m) {
return m.id === enemyCardId;
});
game.enemyDeck.push(enemyMonster);
}
// Shuffle enemy deck
shuffleArray(game.enemyDeck);
// Add opponent info
var opponentAvatar = game.addChild(LK.getAsset('opponent_avatar', {
anchorX: 0.5,
anchorY: 0.5,
x: 1750,
y: 250
}));
var opponentNameText = new Text2(opponent.name, {
size: 40,
fill: 0xFFFFFF
});
opponentNameText.anchor.set(0.5, 0.5);
opponentNameText.x = 1750;
opponentNameText.y = 350;
game.addChild(opponentNameText);
// Add player avatar
var playerAvatar = game.addChild(LK.getAsset('player_avatar', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: 2400
}));
// Add player energy display
game.energyText = new Text2("Energy: " + game.playerEnergy + "/" + game.maxPlayerEnergy, {
size: 40,
fill: 0xFFFFFF
});
game.energyText.anchor.set(0, 0.5);
game.energyText.x = 400;
game.energyText.y = 2400;
game.addChild(game.energyText);
// Add end turn button
game.endTurnButton = new Button("END TURN");
game.endTurnButton.x = 1750;
game.endTurnButton.y = 2400;
game.endTurnButton.down = function () {
if (game.currentTurn === "player") {
LK.getSound('button_click').play();
endPlayerTurn();
}
};
game.addChild(game.endTurnButton);
// Add turn indicator
game.turnText = new Text2("YOUR TURN", {
size: 60,
fill: 0xFFFFFF
});
game.turnText.anchor.set(0.5, 0.5);
game.turnText.x = 1024;
game.turnText.y = 250;
game.addChild(game.turnText);
}
// Create the 3x3 game board
function createGameBoard() {
game.boardSlots = [];
// Calculate board position
var boardCenterX = 1024;
var boardCenterY = 1366;
var slotSpacing = 350;
// Create 3x3 grid for player
for (var y = 0; y < 3; y++) {
for (var x = 0; x < 3; x++) {
var slotX = boardCenterX + (x - 1) * slotSpacing;
var slotY = boardCenterY + (1 - y) * slotSpacing; // Invert y so 0 is at the bottom
var slot = new GridSlot(x, y);
slot.x = slotX;
slot.y = slotY;
game.addChild(slot);
game.boardSlots.push({
slot: slot,
x: x,
y: y,
playerSide: y < 3 // First 3 rows are player side
});
}
}
}
// Deal a card to player's hand
function dealCard() {
if (game.playerDeck.length === 0 || game.playerHand.length >= 5) {
return;
}
var monster = game.playerDeck.shift();
var card = new MonsterCard(monster, true);
// Position in hand
updateHandPositions(card);
game.playerHand.push(card);
game.addChild(card);
}
// Update positions of cards in hand
function updateHandPositions(newCard) {
var handWidth = Math.min(game.playerHand.length + 1, 5) * 280;
var startX = 1024 - handWidth / 2 + 140;
for (var i = 0; i < game.playerHand.length; i++) {
var card = game.playerHand[i];
tween(card, {
x: startX + i * 280,
y: 2150,
rotation: 0
}, {
duration: 300
});
}
if (newCard) {
newCard.x = startX + game.playerHand.length * 280;
newCard.y = 2150;
}
}
// Select a card from hand
game.selectCard = function (card) {
// Check if player has enough energy
if (game.playerEnergy < card.monster.cost) {
// Flash red to indicate not enough energy
LK.effects.flashObject(card, 0xFF0000, 300);
return;
}
game.selectedCard = card;
// Highlight card
tween(card, {
y: 2050
}, {
duration: 200
});
// Highlight valid board positions
highlightValidBoardPositions();
};
// Highlight valid positions on board
function highlightValidBoardPositions() {
// For simplicity, any empty slot is valid
for (var i = 0; i < game.boardSlots.length; i++) {
var slotInfo = game.boardSlots[i];
if (!slotInfo.slot.card) {
slotInfo.slot.highlight(true);
}
}
}
// Unhighlight all board positions
function unhighlightBoardPositions() {
for (var i = 0; i < game.boardSlots.length; i++) {
game.boardSlots[i].slot.highlight(false);
}
}
// Place card on board
game.placeCard = function (card, slot) {
if (!card || !slot || game.playerEnergy < card.monster.cost) {
return;
}
// Remove from hand
var index = game.playerHand.indexOf(card);
if (index !== -1) {
game.playerHand.splice(index, 1);
}
// Use energy
game.playerEnergy -= card.monster.cost;
game.energyText.setText("Energy: " + game.playerEnergy + "/" + game.maxPlayerEnergy);
// Place on board
tween(card, {
x: slot.x,
y: slot.y,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
onFinish: function onFinish() {
slot.setCard(card);
LK.getSound('card_place').play();
}
});
// Update other cards in hand
updateHandPositions();
// Clear selection
game.selectedCard = null;
// Unhighlight slots
unhighlightBoardPositions();
};
// Select a card on the board
game.selectCardOnBoard = function (card) {
// If already had a selected card, deselect it
if (game.selectedCardOnBoard) {
unhighlightBoardPositions();
}
game.selectedCardOnBoard = card;
// Highlight valid targets
highlightValidTargets();
};
// Highlight valid attack targets
function highlightValidTargets() {
// Highlight enemy cards
for (var i = 0; i < game.boardSlots.length; i++) {
var slotInfo = game.boardSlots[i];
if (slotInfo.slot.card && slotInfo.y >= 1.5) {
// Enemy side
slotInfo.slot.highlight(true);
}
}
}
// Attack an enemy card
game.attackCard = function (attackerCard, targetCard) {
if (!attackerCard || !targetCard) {
return;
}
// Perform attack
attackerCard.attack(targetCard);
// Deselect
game.selectedCardOnBoard = null;
unhighlightBoardPositions();
// Check for win condition
checkBattleEnd();
};
// Move a card on board to new position
game.moveCardOnBoard = function (card, newSlot) {
if (!card || !newSlot) {
return;
}
// Find current slot
var currentSlot = null;
for (var i = 0; i < game.boardSlots.length; i++) {
if (game.boardSlots[i].slot.card === card) {
currentSlot = game.boardSlots[i].slot;
break;
}
}
if (currentSlot) {
// Remove from current slot
currentSlot.setCard(null);
// Move to new slot
tween(card, {
x: newSlot.x,
y: newSlot.y
}, {
duration: 300,
onFinish: function onFinish() {
newSlot.setCard(card);
LK.getSound('card_place').play();
}
});
// Deselect
game.selectedCardOnBoard = null;
unhighlightBoardPositions();
}
};
// End player turn
function endPlayerTurn() {
game.currentTurn = "enemy";
game.turnText.setText("OPPONENT'S TURN");
// Deselect any cards
game.selectedCard = null;
game.selectedCardOnBoard = null;
unhighlightBoardPositions();
// Schedule enemy turn
LK.setTimeout(doEnemyTurn, 1000);
}
// Enemy AI turn
function doEnemyTurn() {
// Play cards from enemy deck
playEnemyCards();
// Enemy attacks with all cards
LK.setTimeout(function () {
enemyAttack();
// End enemy turn
LK.setTimeout(startPlayerTurn, 1000);
}, 1000);
}
// Enemy plays cards
function playEnemyCards() {
// Simplified AI - place up to 2 cards if possible
var cardsPlayed = 0;
while (game.enemyDeck.length > 0 && cardsPlayed < 2) {
// Find empty slots on enemy side
var emptySlots = [];
for (var i = 0; i < game.boardSlots.length; i++) {
var slotInfo = game.boardSlots[i];
if (slotInfo.y >= 1.5 && !slotInfo.slot.card) {
// Enemy side
emptySlots.push(slotInfo.slot);
}
}
if (emptySlots.length === 0) {
break;
}
// Place an enemy card
var monster = game.enemyDeck.shift();
var card = new MonsterCard(monster, false);
game.addChild(card);
// Choose a random empty slot
var slot = emptySlots[Math.floor(Math.random() * emptySlots.length)];
// Place card
card.x = 1750;
card.y = 250;
tween(card, {
x: slot.x,
y: slot.y,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
onFinish: function onFinish() {
slot.setCard(card);
LK.getSound('card_place').play();
}
});
cardsPlayed++;
}
}
// Enemy attacks
function enemyAttack() {
// Find all enemy cards
var enemyCards = [];
var playerCards = [];
for (var i = 0; i < game.boardSlots.length; i++) {
var slotInfo = game.boardSlots[i];
if (slotInfo.slot.card) {
if (slotInfo.y >= 1.5) {
// Enemy side
enemyCards.push(slotInfo.slot.card);
} else {
playerCards.push(slotInfo.slot.card);
}
}
}
// Each enemy card attacks a random player card if available
for (var j = 0; j < enemyCards.length; j++) {
if (playerCards.length > 0) {
var target = playerCards[Math.floor(Math.random() * playerCards.length)];
enemyCards[j].attack(target);
// If target was destroyed, remove from player cards
if (target.currentHealth <= 0) {
var targetIndex = playerCards.indexOf(target);
if (targetIndex !== -1) {
playerCards.splice(targetIndex, 1);
}
}
}
}
// Check for loss condition
checkBattleEnd();
}
// Start player turn
function startPlayerTurn() {
game.currentTurn = "player";
game.turnText.setText("YOUR TURN");
// Increase max energy if less than 10
if (game.maxPlayerEnergy < 10) {
game.maxPlayerEnergy++;
}
// Replenish energy
game.playerEnergy = game.maxPlayerEnergy;
game.energyText.setText("Energy: " + game.playerEnergy + "/" + game.maxPlayerEnergy);
// Draw a card
dealCard();
}
// Check if battle is over
function checkBattleEnd() {
// Count cards for each side
var enemyCardCount = 0;
var playerCardCount = 0;
for (var i = 0; i < game.boardSlots.length; i++) {
var slotInfo = game.boardSlots[i];
if (slotInfo.slot.card) {
if (slotInfo.y >= 1.5) {
// Enemy side
enemyCardCount++;
} else {
playerCardCount++;
}
}
}
// Check win/loss conditions
if (enemyCardCount === 0 && game.enemyDeck.length === 0) {
// Player wins
game.battleWon = true;
showBattleResult("YOU WIN!");
} else if (playerCardCount === 0 && game.playerDeck.length === 0 && game.playerHand.length === 0) {
// Player loses
showBattleResult("YOU LOSE!");
}
}
// Show battle result and return to main menu
function showBattleResult(message) {
// Create result overlay
var resultText = new Text2(message, {
size: 100,
fill: 0xFFFFFF
});
resultText.anchor.set(0.5, 0.5);
resultText.x = 1024;
resultText.y = 1366;
game.addChild(resultText);
// If won, update opponent and add a new card
if (game.battleWon) {
// Move to next opponent
if (game.currentOpponent < opponents.length) {
storage.currentOpponent = game.currentOpponent + 1;
}
// Add a new card to collection if not all collected
if (game.availableCards.length < monsterData.length) {
// Find uncollected cards
var uncollectedCards = monsterData.filter(function (m) {
return !game.availableCards.includes(m.id);
}).map(function (m) {
return m.id;
});
if (uncollectedCards.length > 0) {
// Add random new card
var newCardId = uncollectedCards[Math.floor(Math.random() * uncollectedCards.length)];
storage.collectedCards.push(newCardId);
var newCardText = new Text2("NEW CARD UNLOCKED!", {
size: 60,
fill: 0xFFFF00
});
newCardText.anchor.set(0.5, 0.5);
newCardText.x = 1024;
newCardText.y = 1500;
game.addChild(newCardText);
}
}
}
// Return to main menu button
var menuButton = new Button("MAIN MENU");
menuButton.x = 1024;
menuButton.y = 1800;
menuButton.down = function () {
LK.getSound('button_click').play();
showMainMenu();
};
game.addChild(menuButton);
}
// Utility: Clear all children from screen
function clearScreen() {
while (game.children.length > 0) {
game.children[0].destroy();
}
}
// Utility: Shuffle array
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
// Add to deck in deck builder
game.addToDeck = function (monster) {
// Check if we already have 5 cards
if (game.selectedDeck.length >= 5) {
// Remove another card to make room
var lastCard = game.selectedDeck.pop();
}
game.selectedDeck.push(monster.id);
game.selectedCountText.setText("Selected: " + game.selectedDeck.length + " / 5");
};
// Remove from deck in deck builder
game.removeFromDeck = function (monster) {
var index = game.selectedDeck.indexOf(monster.id);
if (index !== -1) {
game.selectedDeck.splice(index, 1);
game.selectedCountText.setText("Selected: " + game.selectedDeck.length + " / 5");
}
};
// Update game logic
game.update = function () {
if (game.currentScreen === "battle") {
// Any per-frame updates for battle screen
}
};
// Initialize game on start
initGame(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,1056 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ playerLevel: 1,
+ playerDeck: undefined,
+ collectedCards: undefined,
+ currentOpponent: 1
+});
+
+/****
+* Classes
+****/
+var Button = Container.expand(function (text) {
+ var self = Container.call(this);
+ var buttonBg = self.attachAsset('button', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.buttonText = new Text2(text, {
+ size: 50,
+ fill: 0xFFFFFF
+ });
+ self.buttonText.anchor.set(0.5, 0.5);
+ self.addChild(self.buttonText);
+ self.setText = function (newText) {
+ self.buttonText.setText(newText);
+ };
+ self.down = function (x, y, obj) {
+ // Button press effect
+ tween(self, {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ tween(self, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 100
+ });
+ }
+ });
+ LK.getSound('button_click').play();
+ };
+ return self;
+});
+var DeckCard = Container.expand(function (monster, isSelected) {
+ var self = Container.call(this);
+ self.monster = monster;
+ self.isSelected = isSelected || false;
+ // Card background
+ var cardBg = self.attachAsset('deck_select_bg', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Highlight if selected
+ if (self.isSelected) {
+ cardBg.tint = 0x00AAFF;
+ }
+ // Monster name
+ self.nameText = new Text2(monster.name, {
+ size: 36,
+ fill: 0xFFFFFF
+ });
+ self.nameText.anchor.set(0.5, 0);
+ self.nameText.y = -150;
+ self.addChild(self.nameText);
+ // Monster stats
+ self.statsText = new Text2("ATK: " + monster.attack + " | HP: " + monster.health, {
+ size: 32,
+ fill: 0xFFFFFF
+ });
+ self.statsText.anchor.set(0.5, 0);
+ self.statsText.y = -100;
+ self.addChild(self.statsText);
+ // Energy cost
+ self.costText = new Text2("Cost: " + monster.cost, {
+ size: 32,
+ fill: 0xFFFFFF
+ });
+ self.costText.anchor.set(0.5, 0);
+ self.costText.y = -50;
+ self.addChild(self.costText);
+ self.toggleSelected = function () {
+ self.isSelected = !self.isSelected;
+ if (self.isSelected) {
+ cardBg.tint = 0x00AAFF;
+ } else {
+ cardBg.tint = 0xFFFFFF;
+ }
+ return self.isSelected;
+ };
+ self.setSelected = function (selected) {
+ self.isSelected = selected;
+ if (self.isSelected) {
+ cardBg.tint = 0x00AAFF;
+ } else {
+ cardBg.tint = 0xFFFFFF;
+ }
+ };
+ self.down = function (x, y, obj) {
+ var result = self.toggleSelected();
+ if (result) {
+ game.addToDeck(self.monster);
+ } else {
+ game.removeFromDeck(self.monster);
+ }
+ };
+ return self;
+});
+var GridSlot = Container.expand(function (gridX, gridY) {
+ var self = Container.call(this);
+ self.gridX = gridX;
+ self.gridY = gridY;
+ self.card = null;
+ var slotBg = self.attachAsset('monster_bg_slot', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Make it slightly transparent
+ slotBg.alpha = 0.5;
+ self.highlight = function (active) {
+ if (active) {
+ slotBg.alpha = 0.8;
+ } else {
+ slotBg.alpha = 0.5;
+ }
+ };
+ self.setCard = function (card) {
+ self.card = card;
+ if (card) {
+ card.inHand = false;
+ card.gridPosition = {
+ x: self.gridX,
+ y: self.gridY
+ };
+ }
+ };
+ self.down = function (x, y, obj) {
+ if (game.selectedCard && !self.card && game.currentTurn === "player") {
+ // If we have a selected card from hand and this slot is empty
+ game.placeCard(game.selectedCard, self);
+ } else if (game.selectedCardOnBoard && !self.card) {
+ // Move card on board to new position
+ game.moveCardOnBoard(game.selectedCardOnBoard, self);
+ }
+ };
+ return self;
+});
+var MonsterCard = Container.expand(function (monster, isPlayerCard) {
+ var self = Container.call(this);
+ self.monster = monster;
+ self.isPlayerCard = isPlayerCard || false;
+ self.inHand = true;
+ self.gridPosition = null;
+ self.currentHealth = monster.health;
+ // Card background
+ var cardBg = self.attachAsset('monster_card', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Monster name
+ self.nameText = new Text2(monster.name, {
+ size: 40,
+ fill: 0x000000
+ });
+ self.nameText.anchor.set(0.5, 0);
+ self.nameText.y = -160;
+ self.addChild(self.nameText);
+ // Monster type
+ self.typeText = new Text2(monster.type, {
+ size: 30,
+ fill: 0x555555
+ });
+ self.typeText.anchor.set(0.5, 0);
+ self.typeText.y = -120;
+ self.addChild(self.typeText);
+ // Attack icon and value
+ var attackIcon = self.attachAsset('attack_icon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: -80,
+ y: 120
+ });
+ self.attackText = new Text2(monster.attack.toString(), {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ self.attackText.anchor.set(0.5, 0.5);
+ self.attackText.x = -80;
+ self.attackText.y = 120;
+ self.addChild(self.attackText);
+ // Health icon and value
+ var healthIcon = self.attachAsset('health_icon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 80,
+ y: 120
+ });
+ self.healthText = new Text2(self.currentHealth.toString(), {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ self.healthText.anchor.set(0.5, 0.5);
+ self.healthText.x = 80;
+ self.healthText.y = 120;
+ self.addChild(self.healthText);
+ // Energy cost
+ var energyIcon = self.attachAsset('energy_icon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 0,
+ y: -80
+ });
+ self.energyText = new Text2(monster.cost.toString(), {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ self.energyText.anchor.set(0.5, 0.5);
+ self.energyText.x = 0;
+ self.energyText.y = -80;
+ self.addChild(self.energyText);
+ // Ability text
+ self.abilityText = new Text2(monster.ability, {
+ size: 26,
+ fill: 0x000000
+ });
+ self.abilityText.anchor.set(0.5, 0.5);
+ self.abilityText.y = 40;
+ self.abilityText.width = 230;
+ self.addChild(self.abilityText);
+ self.updateHealth = function (newHealth) {
+ self.currentHealth = newHealth;
+ self.healthText.setText(self.currentHealth.toString());
+ if (self.currentHealth <= 0) {
+ tween(self, {
+ alpha: 0
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ self.destroy();
+ }
+ });
+ LK.getSound('card_destroyed').play();
+ } else {
+ // Flash the card when damaged
+ LK.effects.flashObject(self, 0xFF0000, 300);
+ }
+ };
+ self.attack = function (targetCard) {
+ if (!targetCard) {
+ return;
+ }
+ LK.getSound('card_attack').play();
+ // Apply damage
+ targetCard.updateHealth(targetCard.currentHealth - self.monster.attack);
+ // Flash the attacking card
+ LK.effects.flashObject(self, 0xFFFF00, 300);
+ };
+ self.down = function (x, y, obj) {
+ if (self.isPlayerCard && self.inHand && game.currentTurn === "player" && !game.selectedCard) {
+ game.selectCard(self);
+ } else if (self.isPlayerCard && !self.inHand && game.selectedCard === null && game.currentTurn === "player") {
+ // Select card on board
+ game.selectCardOnBoard(self);
+ } else if (!self.isPlayerCard && game.selectedCardOnBoard) {
+ // Attack this enemy card
+ game.attackCard(game.selectedCardOnBoard, self);
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x235789
+});
+
+/****
+* Game Code
+****/
+// Game state variables
+game.currentScreen = "menu"; // menu, deck, battle
+game.selectedCard = null;
+game.selectedCardOnBoard = null;
+game.playerHand = [];
+game.playerEnergy = 0;
+game.maxPlayerEnergy = 0;
+game.playerDeck = [];
+game.playerBoard = []; // 3x3 grid for player
+game.enemyBoard = []; // 3x3 grid for enemy
+game.currentTurn = "player";
+game.boardSlots = [];
+game.enemyCards = [];
+game.selectedDeck = [];
+game.availableCards = [];
+game.currentOpponent = 1;
+game.battleWon = false;
+// Define all monster cards data
+var monsterData = [{
+ id: 1,
+ name: "Fire Wolf",
+ type: "Fire",
+ attack: 3,
+ health: 4,
+ cost: 3,
+ ability: "Deals +1 damage to Plant types"
+}, {
+ id: 2,
+ name: "Water Sprite",
+ type: "Water",
+ attack: 2,
+ health: 5,
+ cost: 3,
+ ability: "Heals 1 HP each turn"
+}, {
+ id: 3,
+ name: "Stone Golem",
+ type: "Earth",
+ attack: 2,
+ health: 7,
+ cost: 4,
+ ability: "Takes 1 less damage from attacks"
+}, {
+ id: 4,
+ name: "Wind Eagle",
+ type: "Air",
+ attack: 4,
+ health: 2,
+ cost: 3,
+ ability: "Can attack any position"
+}, {
+ id: 5,
+ name: "Leaf Guardian",
+ type: "Plant",
+ attack: 2,
+ health: 6,
+ cost: 3,
+ ability: "Heals adjacent allies 1 HP per turn"
+}, {
+ id: 6,
+ name: "Shadow Thief",
+ type: "Dark",
+ attack: 5,
+ health: 2,
+ cost: 4,
+ ability: "50% chance to dodge attacks"
+}, {
+ id: 7,
+ name: "Light Fairy",
+ type: "Light",
+ attack: 1,
+ health: 3,
+ cost: 1,
+ ability: "Generates +1 energy per turn"
+}, {
+ id: 8,
+ name: "Thunder Drake",
+ type: "Electric",
+ attack: 4,
+ health: 3,
+ cost: 4,
+ ability: "Can attack all enemies in a row"
+}, {
+ id: 9,
+ name: "Ice Bear",
+ type: "Ice",
+ attack: 3,
+ health: 5,
+ cost: 4,
+ ability: "Freezes enemy for 1 turn on attack"
+}, {
+ id: 10,
+ name: "Lava Giant",
+ type: "Fire",
+ attack: 5,
+ health: 5,
+ cost: 6,
+ ability: "Deals 1 damage to all adjacent enemies"
+}];
+// Define opponent data
+var opponents = [{
+ id: 1,
+ name: "Novice Trainer",
+ level: 1,
+ deck: [1, 2, 5, 7]
+}, {
+ id: 2,
+ name: "Forest Guardian",
+ level: 2,
+ deck: [4, 5, 5, 7, 8]
+}, {
+ id: 3,
+ name: "Flame Master",
+ level: 3,
+ deck: [1, 1, 6, 10, 10]
+}, {
+ id: 4,
+ name: "Guild Champion",
+ level: 4,
+ deck: [3, 6, 8, 9, 10]
+}];
+// Initialize game state
+function initGame() {
+ // Initialize default storage if not set
+ if (!storage.collectedCards) {
+ // Start with 6 basic cards
+ storage.collectedCards = [1, 2, 3, 4, 5, 7];
+ }
+ if (!storage.playerDeck) {
+ // Default deck
+ storage.playerDeck = [1, 2, 3, 4];
+ }
+ // Load player data
+ game.availableCards = storage.collectedCards;
+ game.selectedDeck = storage.playerDeck;
+ game.currentOpponent = storage.currentOpponent || 1;
+ // Show main menu
+ showMainMenu();
+}
+// Create main menu
+function showMainMenu() {
+ game.currentScreen = "menu";
+ clearScreen();
+ // Game title
+ var titleText = new Text2("MONSTER GUILD", {
+ size: 120,
+ fill: 0xFFFFFF
+ });
+ titleText.anchor.set(0.5, 0.5);
+ titleText.x = 1024;
+ titleText.y = 500;
+ game.addChild(titleText);
+ // Battle button
+ var battleButton = new Button("BATTLE");
+ battleButton.x = 1024;
+ battleButton.y = 1200;
+ battleButton.down = function () {
+ LK.getSound('button_click').play();
+ showBattleScreen();
+ };
+ game.addChild(battleButton);
+ // Deck button
+ var deckButton = new Button("DECK BUILDER");
+ deckButton.x = 1024;
+ deckButton.y = 1400;
+ deckButton.down = function () {
+ LK.getSound('button_click').play();
+ showDeckBuilder();
+ };
+ game.addChild(deckButton);
+ // Opponent info
+ var currentOpponent = opponents.find(function (o) {
+ return o.id === game.currentOpponent;
+ });
+ var opponentText = new Text2("Next Opponent: " + currentOpponent.name + " (Lvl " + currentOpponent.level + ")", {
+ size: 50,
+ fill: 0xFFFFFF
+ });
+ opponentText.anchor.set(0.5, 0.5);
+ opponentText.x = 1024;
+ opponentText.y = 900;
+ game.addChild(opponentText);
+}
+// Create deck builder screen
+function showDeckBuilder() {
+ game.currentScreen = "deck";
+ clearScreen();
+ // Title
+ var titleText = new Text2("DECK BUILDER", {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ titleText.anchor.set(0.5, 0.5);
+ titleText.x = 1024;
+ titleText.y = 200;
+ game.addChild(titleText);
+ // Instructions
+ var instructionText = new Text2("Select 5 cards for your deck:", {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ instructionText.anchor.set(0.5, 0.5);
+ instructionText.x = 1024;
+ instructionText.y = 300;
+ game.addChild(instructionText);
+ // Display available cards
+ var cards = [];
+ game.selectedDeck = [];
+ for (var i = 0; i < game.availableCards.length; i++) {
+ var cardId = game.availableCards[i];
+ var monster = monsterData.find(function (m) {
+ return m.id === cardId;
+ });
+ var isSelected = storage.playerDeck.includes(cardId);
+ if (isSelected) {
+ game.selectedDeck.push(cardId);
+ }
+ var deckCard = new DeckCard(monster, isSelected);
+ deckCard.x = 400 + i % 3 * 600;
+ deckCard.y = 600 + Math.floor(i / 3) * 450;
+ deckCard.scale.set(0.8);
+ game.addChild(deckCard);
+ cards.push(deckCard);
+ }
+ // Save button
+ var saveButton = new Button("SAVE DECK");
+ saveButton.x = 1024;
+ saveButton.y = 2400;
+ saveButton.down = function () {
+ LK.getSound('button_click').play();
+ if (game.selectedDeck.length === 0) {
+ // Can't save empty deck
+ return;
+ }
+ storage.playerDeck = game.selectedDeck;
+ showMainMenu();
+ };
+ game.addChild(saveButton);
+ // Back button
+ var backButton = new Button("BACK");
+ backButton.x = 1024;
+ backButton.y = 2600;
+ backButton.down = function () {
+ LK.getSound('button_click').play();
+ showMainMenu();
+ };
+ game.addChild(backButton);
+ // Selected count
+ game.selectedCountText = new Text2("Selected: " + game.selectedDeck.length + " / 5", {
+ size: 50,
+ fill: 0xFFFFFF
+ });
+ game.selectedCountText.anchor.set(0.5, 0.5);
+ game.selectedCountText.x = 1024;
+ game.selectedCountText.y = 2200;
+ game.addChild(game.selectedCountText);
+}
+// Create battle screen
+function showBattleScreen() {
+ game.currentScreen = "battle";
+ clearScreen();
+ // Play battle music
+ LK.playMusic('battle_music');
+ // Initialize battle state
+ game.playerEnergy = 3;
+ game.maxPlayerEnergy = 3;
+ game.currentTurn = "player";
+ game.playerHand = [];
+ game.battleWon = false;
+ // Create player deck for this battle
+ game.playerDeck = [];
+ for (var i = 0; i < storage.playerDeck.length; i++) {
+ var cardId = storage.playerDeck[i];
+ var monster = monsterData.find(function (m) {
+ return m.id === cardId;
+ });
+ game.playerDeck.push(monster);
+ }
+ // Shuffle deck
+ shuffleArray(game.playerDeck);
+ // Create grid board
+ createGameBoard();
+ // Deal initial hand
+ for (var j = 0; j < 3; j++) {
+ if (game.playerDeck.length > 0) {
+ dealCard();
+ }
+ }
+ // Create enemy deck
+ var opponent = opponents.find(function (o) {
+ return o.id === game.currentOpponent;
+ });
+ game.enemyDeck = [];
+ for (var k = 0; k < opponent.deck.length; k++) {
+ var enemyCardId = opponent.deck[k];
+ var enemyMonster = monsterData.find(function (m) {
+ return m.id === enemyCardId;
+ });
+ game.enemyDeck.push(enemyMonster);
+ }
+ // Shuffle enemy deck
+ shuffleArray(game.enemyDeck);
+ // Add opponent info
+ var opponentAvatar = game.addChild(LK.getAsset('opponent_avatar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 1750,
+ y: 250
+ }));
+ var opponentNameText = new Text2(opponent.name, {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ opponentNameText.anchor.set(0.5, 0.5);
+ opponentNameText.x = 1750;
+ opponentNameText.y = 350;
+ game.addChild(opponentNameText);
+ // Add player avatar
+ var playerAvatar = game.addChild(LK.getAsset('player_avatar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 300,
+ y: 2400
+ }));
+ // Add player energy display
+ game.energyText = new Text2("Energy: " + game.playerEnergy + "/" + game.maxPlayerEnergy, {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ game.energyText.anchor.set(0, 0.5);
+ game.energyText.x = 400;
+ game.energyText.y = 2400;
+ game.addChild(game.energyText);
+ // Add end turn button
+ game.endTurnButton = new Button("END TURN");
+ game.endTurnButton.x = 1750;
+ game.endTurnButton.y = 2400;
+ game.endTurnButton.down = function () {
+ if (game.currentTurn === "player") {
+ LK.getSound('button_click').play();
+ endPlayerTurn();
+ }
+ };
+ game.addChild(game.endTurnButton);
+ // Add turn indicator
+ game.turnText = new Text2("YOUR TURN", {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ game.turnText.anchor.set(0.5, 0.5);
+ game.turnText.x = 1024;
+ game.turnText.y = 250;
+ game.addChild(game.turnText);
+}
+// Create the 3x3 game board
+function createGameBoard() {
+ game.boardSlots = [];
+ // Calculate board position
+ var boardCenterX = 1024;
+ var boardCenterY = 1366;
+ var slotSpacing = 350;
+ // Create 3x3 grid for player
+ for (var y = 0; y < 3; y++) {
+ for (var x = 0; x < 3; x++) {
+ var slotX = boardCenterX + (x - 1) * slotSpacing;
+ var slotY = boardCenterY + (1 - y) * slotSpacing; // Invert y so 0 is at the bottom
+ var slot = new GridSlot(x, y);
+ slot.x = slotX;
+ slot.y = slotY;
+ game.addChild(slot);
+ game.boardSlots.push({
+ slot: slot,
+ x: x,
+ y: y,
+ playerSide: y < 3 // First 3 rows are player side
+ });
+ }
+ }
+}
+// Deal a card to player's hand
+function dealCard() {
+ if (game.playerDeck.length === 0 || game.playerHand.length >= 5) {
+ return;
+ }
+ var monster = game.playerDeck.shift();
+ var card = new MonsterCard(monster, true);
+ // Position in hand
+ updateHandPositions(card);
+ game.playerHand.push(card);
+ game.addChild(card);
+}
+// Update positions of cards in hand
+function updateHandPositions(newCard) {
+ var handWidth = Math.min(game.playerHand.length + 1, 5) * 280;
+ var startX = 1024 - handWidth / 2 + 140;
+ for (var i = 0; i < game.playerHand.length; i++) {
+ var card = game.playerHand[i];
+ tween(card, {
+ x: startX + i * 280,
+ y: 2150,
+ rotation: 0
+ }, {
+ duration: 300
+ });
+ }
+ if (newCard) {
+ newCard.x = startX + game.playerHand.length * 280;
+ newCard.y = 2150;
+ }
+}
+// Select a card from hand
+game.selectCard = function (card) {
+ // Check if player has enough energy
+ if (game.playerEnergy < card.monster.cost) {
+ // Flash red to indicate not enough energy
+ LK.effects.flashObject(card, 0xFF0000, 300);
+ return;
+ }
+ game.selectedCard = card;
+ // Highlight card
+ tween(card, {
+ y: 2050
+ }, {
+ duration: 200
+ });
+ // Highlight valid board positions
+ highlightValidBoardPositions();
+};
+// Highlight valid positions on board
+function highlightValidBoardPositions() {
+ // For simplicity, any empty slot is valid
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ var slotInfo = game.boardSlots[i];
+ if (!slotInfo.slot.card) {
+ slotInfo.slot.highlight(true);
+ }
+ }
+}
+// Unhighlight all board positions
+function unhighlightBoardPositions() {
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ game.boardSlots[i].slot.highlight(false);
+ }
+}
+// Place card on board
+game.placeCard = function (card, slot) {
+ if (!card || !slot || game.playerEnergy < card.monster.cost) {
+ return;
+ }
+ // Remove from hand
+ var index = game.playerHand.indexOf(card);
+ if (index !== -1) {
+ game.playerHand.splice(index, 1);
+ }
+ // Use energy
+ game.playerEnergy -= card.monster.cost;
+ game.energyText.setText("Energy: " + game.playerEnergy + "/" + game.maxPlayerEnergy);
+ // Place on board
+ tween(card, {
+ x: slot.x,
+ y: slot.y,
+ scaleX: 0.8,
+ scaleY: 0.8
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ slot.setCard(card);
+ LK.getSound('card_place').play();
+ }
+ });
+ // Update other cards in hand
+ updateHandPositions();
+ // Clear selection
+ game.selectedCard = null;
+ // Unhighlight slots
+ unhighlightBoardPositions();
+};
+// Select a card on the board
+game.selectCardOnBoard = function (card) {
+ // If already had a selected card, deselect it
+ if (game.selectedCardOnBoard) {
+ unhighlightBoardPositions();
+ }
+ game.selectedCardOnBoard = card;
+ // Highlight valid targets
+ highlightValidTargets();
+};
+// Highlight valid attack targets
+function highlightValidTargets() {
+ // Highlight enemy cards
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ var slotInfo = game.boardSlots[i];
+ if (slotInfo.slot.card && slotInfo.y >= 1.5) {
+ // Enemy side
+ slotInfo.slot.highlight(true);
+ }
+ }
+}
+// Attack an enemy card
+game.attackCard = function (attackerCard, targetCard) {
+ if (!attackerCard || !targetCard) {
+ return;
+ }
+ // Perform attack
+ attackerCard.attack(targetCard);
+ // Deselect
+ game.selectedCardOnBoard = null;
+ unhighlightBoardPositions();
+ // Check for win condition
+ checkBattleEnd();
+};
+// Move a card on board to new position
+game.moveCardOnBoard = function (card, newSlot) {
+ if (!card || !newSlot) {
+ return;
+ }
+ // Find current slot
+ var currentSlot = null;
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ if (game.boardSlots[i].slot.card === card) {
+ currentSlot = game.boardSlots[i].slot;
+ break;
+ }
+ }
+ if (currentSlot) {
+ // Remove from current slot
+ currentSlot.setCard(null);
+ // Move to new slot
+ tween(card, {
+ x: newSlot.x,
+ y: newSlot.y
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ newSlot.setCard(card);
+ LK.getSound('card_place').play();
+ }
+ });
+ // Deselect
+ game.selectedCardOnBoard = null;
+ unhighlightBoardPositions();
+ }
+};
+// End player turn
+function endPlayerTurn() {
+ game.currentTurn = "enemy";
+ game.turnText.setText("OPPONENT'S TURN");
+ // Deselect any cards
+ game.selectedCard = null;
+ game.selectedCardOnBoard = null;
+ unhighlightBoardPositions();
+ // Schedule enemy turn
+ LK.setTimeout(doEnemyTurn, 1000);
+}
+// Enemy AI turn
+function doEnemyTurn() {
+ // Play cards from enemy deck
+ playEnemyCards();
+ // Enemy attacks with all cards
+ LK.setTimeout(function () {
+ enemyAttack();
+ // End enemy turn
+ LK.setTimeout(startPlayerTurn, 1000);
+ }, 1000);
+}
+// Enemy plays cards
+function playEnemyCards() {
+ // Simplified AI - place up to 2 cards if possible
+ var cardsPlayed = 0;
+ while (game.enemyDeck.length > 0 && cardsPlayed < 2) {
+ // Find empty slots on enemy side
+ var emptySlots = [];
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ var slotInfo = game.boardSlots[i];
+ if (slotInfo.y >= 1.5 && !slotInfo.slot.card) {
+ // Enemy side
+ emptySlots.push(slotInfo.slot);
+ }
+ }
+ if (emptySlots.length === 0) {
+ break;
+ }
+ // Place an enemy card
+ var monster = game.enemyDeck.shift();
+ var card = new MonsterCard(monster, false);
+ game.addChild(card);
+ // Choose a random empty slot
+ var slot = emptySlots[Math.floor(Math.random() * emptySlots.length)];
+ // Place card
+ card.x = 1750;
+ card.y = 250;
+ tween(card, {
+ x: slot.x,
+ y: slot.y,
+ scaleX: 0.8,
+ scaleY: 0.8
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ slot.setCard(card);
+ LK.getSound('card_place').play();
+ }
+ });
+ cardsPlayed++;
+ }
+}
+// Enemy attacks
+function enemyAttack() {
+ // Find all enemy cards
+ var enemyCards = [];
+ var playerCards = [];
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ var slotInfo = game.boardSlots[i];
+ if (slotInfo.slot.card) {
+ if (slotInfo.y >= 1.5) {
+ // Enemy side
+ enemyCards.push(slotInfo.slot.card);
+ } else {
+ playerCards.push(slotInfo.slot.card);
+ }
+ }
+ }
+ // Each enemy card attacks a random player card if available
+ for (var j = 0; j < enemyCards.length; j++) {
+ if (playerCards.length > 0) {
+ var target = playerCards[Math.floor(Math.random() * playerCards.length)];
+ enemyCards[j].attack(target);
+ // If target was destroyed, remove from player cards
+ if (target.currentHealth <= 0) {
+ var targetIndex = playerCards.indexOf(target);
+ if (targetIndex !== -1) {
+ playerCards.splice(targetIndex, 1);
+ }
+ }
+ }
+ }
+ // Check for loss condition
+ checkBattleEnd();
+}
+// Start player turn
+function startPlayerTurn() {
+ game.currentTurn = "player";
+ game.turnText.setText("YOUR TURN");
+ // Increase max energy if less than 10
+ if (game.maxPlayerEnergy < 10) {
+ game.maxPlayerEnergy++;
+ }
+ // Replenish energy
+ game.playerEnergy = game.maxPlayerEnergy;
+ game.energyText.setText("Energy: " + game.playerEnergy + "/" + game.maxPlayerEnergy);
+ // Draw a card
+ dealCard();
+}
+// Check if battle is over
+function checkBattleEnd() {
+ // Count cards for each side
+ var enemyCardCount = 0;
+ var playerCardCount = 0;
+ for (var i = 0; i < game.boardSlots.length; i++) {
+ var slotInfo = game.boardSlots[i];
+ if (slotInfo.slot.card) {
+ if (slotInfo.y >= 1.5) {
+ // Enemy side
+ enemyCardCount++;
+ } else {
+ playerCardCount++;
+ }
+ }
+ }
+ // Check win/loss conditions
+ if (enemyCardCount === 0 && game.enemyDeck.length === 0) {
+ // Player wins
+ game.battleWon = true;
+ showBattleResult("YOU WIN!");
+ } else if (playerCardCount === 0 && game.playerDeck.length === 0 && game.playerHand.length === 0) {
+ // Player loses
+ showBattleResult("YOU LOSE!");
+ }
+}
+// Show battle result and return to main menu
+function showBattleResult(message) {
+ // Create result overlay
+ var resultText = new Text2(message, {
+ size: 100,
+ fill: 0xFFFFFF
+ });
+ resultText.anchor.set(0.5, 0.5);
+ resultText.x = 1024;
+ resultText.y = 1366;
+ game.addChild(resultText);
+ // If won, update opponent and add a new card
+ if (game.battleWon) {
+ // Move to next opponent
+ if (game.currentOpponent < opponents.length) {
+ storage.currentOpponent = game.currentOpponent + 1;
+ }
+ // Add a new card to collection if not all collected
+ if (game.availableCards.length < monsterData.length) {
+ // Find uncollected cards
+ var uncollectedCards = monsterData.filter(function (m) {
+ return !game.availableCards.includes(m.id);
+ }).map(function (m) {
+ return m.id;
+ });
+ if (uncollectedCards.length > 0) {
+ // Add random new card
+ var newCardId = uncollectedCards[Math.floor(Math.random() * uncollectedCards.length)];
+ storage.collectedCards.push(newCardId);
+ var newCardText = new Text2("NEW CARD UNLOCKED!", {
+ size: 60,
+ fill: 0xFFFF00
+ });
+ newCardText.anchor.set(0.5, 0.5);
+ newCardText.x = 1024;
+ newCardText.y = 1500;
+ game.addChild(newCardText);
+ }
+ }
+ }
+ // Return to main menu button
+ var menuButton = new Button("MAIN MENU");
+ menuButton.x = 1024;
+ menuButton.y = 1800;
+ menuButton.down = function () {
+ LK.getSound('button_click').play();
+ showMainMenu();
+ };
+ game.addChild(menuButton);
+}
+// Utility: Clear all children from screen
+function clearScreen() {
+ while (game.children.length > 0) {
+ game.children[0].destroy();
+ }
+}
+// Utility: Shuffle array
+function shuffleArray(array) {
+ for (var i = array.length - 1; i > 0; i--) {
+ var j = Math.floor(Math.random() * (i + 1));
+ var temp = array[i];
+ array[i] = array[j];
+ array[j] = temp;
+ }
+}
+// Add to deck in deck builder
+game.addToDeck = function (monster) {
+ // Check if we already have 5 cards
+ if (game.selectedDeck.length >= 5) {
+ // Remove another card to make room
+ var lastCard = game.selectedDeck.pop();
+ }
+ game.selectedDeck.push(monster.id);
+ game.selectedCountText.setText("Selected: " + game.selectedDeck.length + " / 5");
+};
+// Remove from deck in deck builder
+game.removeFromDeck = function (monster) {
+ var index = game.selectedDeck.indexOf(monster.id);
+ if (index !== -1) {
+ game.selectedDeck.splice(index, 1);
+ game.selectedCountText.setText("Selected: " + game.selectedDeck.length + " / 5");
+ }
+};
+// Update game logic
+game.update = function () {
+ if (game.currentScreen === "battle") {
+ // Any per-frame updates for battle screen
+ }
+};
+// Initialize game on start
+initGame();
\ No newline at end of file