/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AttackButton = Container.expand(function (text) { var self = Container.call(this); var buttonBg = self.attachAsset('attackButton', { anchorX: 0.5, anchorY: 0.5 }); buttonBg.tint = 0xff4444; var buttonText = new Text2(text, { size: 70, fill: '#ffffff' }); buttonText.anchor.set(0.5, 0.5); buttonText.x = 0; buttonText.y = 0; self.addChild(buttonText); self.setText = function (newText) { buttonText.setText(newText); }; self.down = function (x, y, obj) { if (gameState === 'ready') { // Add press effect tween(buttonBg, { scaleX: 0.95, scaleY: 0.95, tint: 0xcc3333 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(buttonBg, { scaleX: 1.0, scaleY: 1.0, tint: 0xff4444 }, { duration: 150, easing: tween.bounceOut }); } }); performBattle(); } }; return self; }); var ClassButton = Container.expand(function (className, description, skills) { var self = Container.call(this); var buttonBg = self.attachAsset('classButton', { anchorX: 0.5, anchorY: 0.5 }); var classText = new Text2(className, { size: 50, fill: '#000000' }); classText.anchor.set(0.5, 0.5); classText.x = 0; classText.y = -30; self.addChild(classText); var descText = new Text2(description, { size: 30, fill: '#000000' }); descText.anchor.set(0.5, 0.5); descText.x = 0; descText.y = 30; self.addChild(descText); self.className = className; self.skills = skills; self.down = function (x, y, obj) { if (gameState === 'selectClass') { selectedClass = self; startGame(); } }; return self; }); var CoinButton = Container.expand(function (coinCount) { var self = Container.call(this); var buttonBg = self.attachAsset('coinButton', { anchorX: 0.5, anchorY: 0.5 }); var coinText = new Text2(coinCount.toString(), { size: 80, fill: '#000000' }); coinText.anchor.set(0.5, 0.5); coinText.x = 0; coinText.y = 0; self.addChild(coinText); self.coinCount = coinCount; self.down = function (x, y, obj) { if (gameState === 'selectCoins') { selectedCoins = self.coinCount; gameState = 'ready'; readyButton.alpha = 1; } }; return self; }); var EnemyCard = Container.expand(function () { var self = Container.call(this); var cardBg = self.attachAsset('enemyCard', { anchorX: 0.5, anchorY: 0.5 }); var nameText = new Text2('ENEMY', { size: 60, fill: '#000000' }); nameText.anchor.set(0.5, 0.5); nameText.x = 0; nameText.y = -140; self.addChild(nameText); self.setEnemyName = function (name) { nameText.setText(name); }; var healthBorder = self.attachAsset('healthBarBorder', { anchorX: 0.5, anchorY: 0.5 }); healthBorder.x = 0; healthBorder.y = -60; var healthBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBg.x = 0; healthBg.y = -60; var healthBar = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0.5 }); healthBar.x = 0; healthBar.y = -60; var healthText = new Text2('100/100', { size: 48, fill: '#000000' }); healthText.anchor.set(0.5, 0.5); healthText.x = 0; healthText.y = -60; self.addChild(healthText); self.updateHealth = function (current, max) { healthText.setText(current + '/' + max); var healthPercent = current / max; healthBar.scaleX = healthPercent; healthBar.x = -250 + 250 * healthPercent; }; return self; }); var FlippingCoin = Container.expand(function () { var self = Container.call(this); var coinGraphic = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.isFlipping = false; self.result = null; self.flip = function (callback, isPlayer) { self.isFlipping = true; self.result = Math.random() < 0.5 ? 'heads' : 'tails'; // Play different sound based on player/enemy if (isPlayer === true) { LK.getSound('playerCoinFlip').play(); } else if (isPlayer === false) { LK.getSound('enemyCoinFlip').play(); } else { LK.getSound('coinFlip').play(); } // Add initial scale and brightness effect tween(coinGraphic, { scaleX: 1.3, scaleY: 1.3, tint: 0xffffff }, { duration: 100, easing: tween.easeOut }); tween(coinGraphic, { rotation: Math.PI * 6, scaleX: 1.0, scaleY: 1.0 }, { duration: 1800, easing: tween.easeOut, onFinish: function onFinish() { self.isFlipping = false; if (self.result === 'heads') { coinGraphic.tint = 0x00ff66; // Success sparkle effect tween(coinGraphic, { scaleX: 1.4, scaleY: 1.4 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(coinGraphic, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.bounceOut }); } }); } else { coinGraphic.tint = 0xff3366; // Failure shake effect tween(coinGraphic, { x: coinGraphic.x + 10 }, { duration: 100, easing: tween.easeInOut, onFinish: function onFinish() { tween(coinGraphic, { x: coinGraphic.x - 10 }, { duration: 100, easing: tween.easeInOut }); } }); } if (callback) callback(self.result); } }); }; return self; }); var PlayerCard = Container.expand(function () { var self = Container.call(this); var cardBg = self.attachAsset('playerCard', { anchorX: 0.5, anchorY: 0.5 }); var nameText = new Text2('PLAYER', { size: 60, fill: '#000000' }); nameText.anchor.set(0.5, 0.5); nameText.x = 0; nameText.y = -140; self.addChild(nameText); var healthBorder = self.attachAsset('healthBarBorder', { anchorX: 0.5, anchorY: 0.5 }); healthBorder.x = 0; healthBorder.y = -60; var healthBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBg.x = 0; healthBg.y = -60; var healthBar = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0.5 }); healthBar.x = 0; healthBar.y = -60; var healthText = new Text2('100/100', { size: 48, fill: '#000000' }); healthText.anchor.set(0.5, 0.5); healthText.x = 0; healthText.y = -60; self.addChild(healthText); self.updateHealth = function (current, max) { healthText.setText(current + '/' + max); var healthPercent = current / max; healthBar.scaleX = healthPercent; healthBar.x = -250 + 250 * healthPercent; }; return self; }); var SkillButton = Container.expand(function (skillName, basePower, coinCount) { var self = Container.call(this); var buttonBorder = self.attachAsset('skillButtonBorder', { anchorX: 0.5, anchorY: 0.5 }); var buttonBg = self.attachAsset('skillButton', { anchorX: 0.5, anchorY: 0.5 }); // Calculate power range based on new balanced formula var minPower = Math.max(1, Math.floor(basePower * 0.3)); var bonusPerSuccess = Math.max(2, Math.floor(basePower * 0.8)); var maxPower = minPower + coinCount * bonusPerSuccess; var skillText = new Text2(skillName + ' (Power: ' + minPower + '-' + maxPower + ', Coins: ' + coinCount + ')', { size: 50, fill: '#000000' }); skillText.anchor.set(0.5, 0.5); skillText.x = 0; skillText.y = 0; self.addChild(skillText); self.skillName = skillName; self.basePower = basePower; self.coinCount = coinCount; self.minPower = minPower; self.maxPower = maxPower; self.selected = false; self.setSelected = function (selected) { self.selected = selected; if (selected) { buttonBg.tint = 0x00ff88; buttonBorder.tint = 0xff8800; tween(buttonBorder, { scaleX: 1.08, scaleY: 1.08 }, { duration: 200, easing: tween.easeOut }); // Add pulsing glow effect tween(buttonBg, { alpha: 0.7 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(buttonBg, { alpha: 1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (self.selected) { self.setSelected(true); // Continue pulsing } } }); } }); } else { buttonBg.tint = 0x27ae60; buttonBorder.tint = 0x1e8449; buttonBg.alpha = 1; tween(buttonBorder, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeOut }); } }; self.down = function (x, y, obj) { if (gameState === 'selectSkill') { selectedSkill = self; skill1Button.setSelected(false); skill2Button.setSelected(false); self.setSelected(true); gameState = 'ready'; readyButton.alpha = 1; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x34495e }); /**** * Game Code ****/ // Game state variables var gameState = 'selectClass'; var playerMaxHealth = 80 + Math.floor(Math.random() * 21); // 80-100 HP var enemyMaxHealth = 80 + Math.floor(Math.random() * 21); // 80-100 HP var playerHealth = playerMaxHealth; var enemyHealth = enemyMaxHealth; // Class definitions with their specific skills var playerClasses = [{ name: 'Spearman', description: 'Balanced fighter with reliable attacks', skills: [{ name: 'Piercing Strike', power: 6, coins: 2 }, { name: 'Whirlwind Assault', power: 3, coins: 5 }] }, { name: 'Samurai', description: 'High-risk, high-reward warrior', skills: [{ name: 'Perfect Cut', power: 18, coins: 1 }, { name: 'Flurry Combo', power: 2, coins: 6 }] }, { name: 'Berserker', description: 'Chaotic fighter with extreme variance', skills: [{ name: 'Reckless Charge', power: 5, coins: 3 }, { name: 'Fury Unleashed', power: 1, coins: 8 }] }]; // Player skills will be assigned after class selection var playerSkills = []; var selectedClass = null; // Enemy types with specialized skill sets var enemyTypes = [{ name: 'Shadow Assassin', description: 'Fast and precise attacks', skills: [{ name: 'Shadow Strike', power: 14, coins: 1 }, { name: 'Poison Dart Volley', power: 3, coins: 4 }] }, { name: 'Bone Golem', description: 'Slow but devastating attacks', skills: [{ name: 'Bone Crush', power: 8, coins: 2 }, { name: 'Skeletal Rampage', power: 2, coins: 7 }] }, { name: 'Fire Demon', description: 'Chaotic flame attacks', skills: [{ name: 'Hellfire Blast', power: 11, coins: 1 }, { name: 'Inferno Storm', power: 4, coins: 5 }] }, { name: 'Void Wraith', description: 'Energy-based attacks', skills: [{ name: 'Void Pulse', power: 6, coins: 3 }, { name: 'Soul Drain', power: 16, coins: 1 }] }, { name: 'Frost Giant', description: 'Ice-based powerful attacks', skills: [{ name: 'Glacial Slam', power: 9, coins: 2 }, { name: 'Blizzard Fury', power: 3, coins: 6 }] }]; // Current enemy (will be randomly selected) var currentEnemy = null; var enemySkills = []; // Current selection var selectedSkill = null; // Create class selection UI var classSelectionTitle = new Text2('Choose Your Class', { size: 80, fill: '#000000' }); classSelectionTitle.anchor.set(0.5, 0.5); classSelectionTitle.x = 1024; classSelectionTitle.y = 400; game.addChild(classSelectionTitle); var classButtons = []; for (var i = 0; i < playerClasses.length; i++) { var classButton = new ClassButton(playerClasses[i].name, playerClasses[i].description, playerClasses[i].skills); classButton.x = 1024; classButton.y = 700 + i * 300; classButtons.push(classButton); game.addChild(classButton); } // Game UI elements (will be created after class selection) var playerCard = null; var enemyCard = null; var skill1Button = null; var skill2Button = null; var readyButton = null; var statusText = null; var enemySkillText = null; // Battle result area var battleResultText = new Text2('', { size: 60, fill: '#000000' }); battleResultText.anchor.set(0.5, 0.5); battleResultText.x = 1024; battleResultText.y = 1750; game.addChild(battleResultText); // Coin flip display area var coinFlipContainer = new Container(); coinFlipContainer.x = 1024; coinFlipContainer.y = 1550; game.addChild(coinFlipContainer); // Live damage numbers container var liveNumbersContainer = new Container(); liveNumbersContainer.x = 1024; liveNumbersContainer.y = 1800; game.addChild(liveNumbersContainer); function showLiveDamageNumber(damage, x, y, isPlayer) { var damageText = new Text2('-' + damage, { size: 100, fill: isPlayer ? '#ff0066' : '#ff6600' }); damageText.anchor.set(0.5, 0.5); damageText.x = x; damageText.y = y; damageText.alpha = 0; damageText.scaleX = 0.5; damageText.scaleY = 0.5; liveNumbersContainer.addChild(damageText); // Pop in effect tween(damageText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.bounceOut, onFinish: function onFinish() { // Scale back and float up tween(damageText, { scaleX: 1.0, scaleY: 1.0, y: y - 120, alpha: 0 }, { duration: 1200, easing: tween.easeOut, onFinish: function onFinish() { liveNumbersContainer.removeChild(damageText); } }); } }); } function startGame() { // Assign skills based on selected class playerSkills = selectedClass.skills; // Adjust health based on class - balanced fighters get more health if (selectedClass.name === 'Spearman') { playerMaxHealth += 20; // Balanced fighter gets extra durability } else if (selectedClass.name === 'Samurai') { playerMaxHealth -= 10; // High-risk fighter gets less health } else if (selectedClass.name === 'Berserker') { playerMaxHealth += 10; // Chaotic fighter gets moderate health boost } playerHealth = playerMaxHealth; // Select random enemy type var enemyIndex = Math.floor(Math.random() * enemyTypes.length); currentEnemy = enemyTypes[enemyIndex]; enemySkills = currentEnemy.skills; // Hide class selection UI classSelectionTitle.alpha = 0; for (var i = 0; i < classButtons.length; i++) { classButtons[i].alpha = 0; } // Create game UI elements playerCard = game.addChild(new PlayerCard()); playerCard.x = 1024; playerCard.y = 600; enemyCard = game.addChild(new EnemyCard()); enemyCard.x = 1024; enemyCard.y = 300; // Skills selection - positioned below player card with more spacing skill1Button = game.addChild(new SkillButton(playerSkills[0].name, playerSkills[0].power, playerSkills[0].coins)); skill1Button.x = 1024; skill1Button.y = 950; skill2Button = game.addChild(new SkillButton(playerSkills[1].name, playerSkills[1].power, playerSkills[1].coins)); skill2Button.x = 1024; skill2Button.y = 1130; // Attack button readyButton = game.addChild(new AttackButton('BATTLE!')); readyButton.x = 1024; readyButton.y = 1350; readyButton.alpha = 0.5; // Status text - positioned between player card and skill buttons statusText = new Text2('Choose your skill', { size: 70, fill: '#000000' }); statusText.anchor.set(0.5, 0.5); statusText.x = 1024; statusText.y = 850; game.addChild(statusText); // Enemy description text var enemyDescText = new Text2(currentEnemy.description, { size: 40, fill: '#666666' }); enemyDescText.anchor.set(0.5, 0.5); enemyDescText.x = 1024; enemyDescText.y = 120; game.addChild(enemyDescText); // Enemy skill display text - positioned higher to avoid blocking enemySkillText = new Text2('', { size: 50, fill: '#000000' }); enemySkillText.anchor.set(0.5, 0.5); enemySkillText.x = 1024; enemySkillText.y = 150; game.addChild(enemySkillText); // Initialize health displays playerCard.updateHealth(playerHealth, playerMaxHealth); enemyCard.updateHealth(enemyHealth, enemyMaxHealth); enemyCard.setEnemyName(currentEnemy.name); // Change game state gameState = 'selectSkill'; } // Battle logic function performBattle() { if (!selectedSkill) return; gameState = 'battle'; statusText.setText('Battle in progress...'); readyButton.alpha = 0.5; // Player's turn var playerBasePower = selectedSkill.basePower; var playerCoins = selectedSkill.coinCount; // Enemy's turn (AI) var enemySkillIndex = Math.floor(Math.random() * enemySkills.length); var enemySkill = enemySkills[enemySkillIndex]; var enemyBasePower = enemySkill.power; var enemyCoins = enemySkill.coins; var enemyMinPower = Math.max(1, Math.floor(enemyBasePower * 0.3)); var enemyBonusPerSuccess = Math.max(2, Math.floor(enemyBasePower * 0.8)); var enemyMaxPower = enemyMinPower + enemyCoins * enemyBonusPerSuccess; // Display enemy's planned skill enemySkillText.setText('Enemy plans: ' + enemySkill.name + ' (Power: ' + enemyMinPower + '-' + enemyMaxPower + ', ' + enemyCoins + ' coins)'); // Clear previous coins coinFlipContainer.removeChildren(); // Flip player coins var playerSuccessfulFlips = 0; var playerCoinsFlipped = 0; for (var i = 0; i < playerCoins; i++) { var coin = new FlippingCoin(); coin.x = (i - (playerCoins - 1) / 2) * 100; coin.y = -50; coinFlipContainer.addChild(coin); // Set player coin color var coinGraphic = coin.getChildAt(0); coinGraphic.tint = 0x4CAF50; // Green for player coins // Add P text label for player coins var playerLabel = new Text2('P', { size: 40, fill: '#ffffff' }); playerLabel.anchor.set(0.5, 0.5); playerLabel.x = 0; playerLabel.y = 0; coin.addChild(playerLabel); LK.setTimeout(function (coinRef) { return function () { coinRef.flip(function (result) { if (result === 'heads') { playerSuccessfulFlips++; } playerCoinsFlipped++; if (playerCoinsFlipped === playerCoins) { // All player coins flipped, now flip enemy coins flipEnemyCoins(); } }, true); }; }(coin), i * 800); } function flipEnemyCoins() { var enemySuccessfulFlips = 0; var enemyCoinsFlipped = 0; for (var i = 0; i < enemyCoins; i++) { var coin = new FlippingCoin(); coin.x = (i - (enemyCoins - 1) / 2) * 100; coin.y = 50; coinFlipContainer.addChild(coin); // Set enemy coin color var coinGraphic = coin.getChildAt(0); coinGraphic.tint = 0xF44336; // Red for enemy coins // Add E text label for enemy coins var enemyLabel = new Text2('E', { size: 40, fill: '#ffffff' }); enemyLabel.anchor.set(0.5, 0.5); enemyLabel.x = 0; enemyLabel.y = 0; coin.addChild(enemyLabel); LK.setTimeout(function (coinRef) { return function () { coinRef.flip(function (result) { if (result === 'heads') { enemySuccessfulFlips++; } enemyCoinsFlipped++; if (enemyCoinsFlipped === enemyCoins) { // All coins flipped, resolve battle resolveBattle(playerBasePower, playerSuccessfulFlips, playerCoins, enemyBasePower, enemySuccessfulFlips, enemyCoins, enemySkill.name); } }, false); }; }(coin), i * 800 + 3000); } } } function resolveBattle(playerBasePower, playerSuccessfulFlips, playerCoins, enemyBasePower, enemySuccessfulFlips, enemyCoins, enemySkillName) { var playerTotalPower = playerBasePower + playerSuccessfulFlips * 2; var enemyTotalPower = enemyBasePower + enemySuccessfulFlips * 2; var resultText = 'CLASH RESULTS:\n'; resultText += 'Player: ' + playerBasePower + ' base + ' + playerSuccessfulFlips + '/' + playerCoins + ' heads = ' + playerTotalPower + '\n'; resultText += 'Enemy: ' + enemyBasePower + ' base + ' + enemySuccessfulFlips + '/' + enemyCoins + ' heads = ' + enemyTotalPower + '\n'; if (playerTotalPower > enemyTotalPower) { // Player wins - roll attack coins resultText += 'Player wins! Rolling ' + playerCoins + ' attack coins...\n'; rollAttackCoins(playerCoins, true, function (successfulAttacks) { var playerMinPower = Math.max(1, Math.floor(playerBasePower * 0.3)); var bonusPerSuccess = Math.max(2, Math.floor(playerBasePower * 0.8)); var totalDamage = playerMinPower + successfulAttacks * bonusPerSuccess; if (successfulAttacks === playerCoins) { totalDamage = Math.floor(totalDamage * 1.5); // 50% damage bonus for perfect flips resultText += 'CRITICAL HIT! Perfect flip grants 50% bonus damage!\n'; } enemyHealth -= totalDamage; resultText += 'Enemy takes ' + totalDamage + ' damage (' + successfulAttacks + '/' + playerCoins + ' successful attacks)!'; // Show live damage number showLiveDamageNumber(totalDamage, 0, -100, false); LK.getSound('attack').play(); LK.getSound('victory').play(); // Flash enemy red tween(enemyCard, { tint: 0xff0000 }, { duration: 800, onFinish: function onFinish() { tween(enemyCard, { tint: 0xffffff }, { duration: 800 }); } }); battleResultText.setText(resultText); finalizeBattle(); }); } else if (enemyTotalPower > playerTotalPower) { // Enemy wins - roll attack coins resultText += 'Enemy wins with ' + enemySkillName + '! Rolling ' + enemyCoins + ' attack coins...\n'; rollAttackCoins(enemyCoins, false, function (successfulAttacks) { var enemyMinPower = Math.max(1, Math.floor(enemyBasePower * 0.3)); var bonusPerSuccess = Math.max(2, Math.floor(enemyBasePower * 0.8)); var totalDamage = enemyMinPower + successfulAttacks * bonusPerSuccess; if (successfulAttacks === enemyCoins) { totalDamage = Math.floor(totalDamage * 1.5); // 50% damage bonus for perfect flips resultText += 'ENEMY CRITICAL HIT! Perfect flip grants 50% bonus damage!\n'; } playerHealth -= totalDamage; resultText += 'Player takes ' + totalDamage + ' damage (' + successfulAttacks + '/' + enemyCoins + ' successful attacks)!'; // Show live damage number showLiveDamageNumber(totalDamage, 0, 100, true); LK.getSound('damage').play(); LK.getSound('defeat').play(); // Flash player red tween(playerCard, { tint: 0xff0000 }, { duration: 800, onFinish: function onFinish() { tween(playerCard, { tint: 0xffffff }, { duration: 800 }); } }); battleResultText.setText(resultText); finalizeBattle(); }); } else { // Tie resultText += 'It\'s a tie! No damage dealt.'; battleResultText.setText(resultText); finalizeBattle(); } function rollAttackCoins(coinCount, isPlayer, callback) { // Clear previous attack coins var attackCoinsContainer = new Container(); attackCoinsContainer.x = 0; attackCoinsContainer.y = isPlayer ? 150 : -150; coinFlipContainer.addChild(attackCoinsContainer); var successfulAttacks = 0; var coinsFlipped = 0; for (var i = 0; i < coinCount; i++) { var coin = new FlippingCoin(); coin.x = (i - (coinCount - 1) / 2) * 80; coin.y = 0; attackCoinsContainer.addChild(coin); // Set attack coin color based on player/enemy var coinGraphic = coin.getChildAt(0); coinGraphic.tint = isPlayer ? 0x2196F3 : 0xFF5722; // Blue for player attack, orange for enemy attack // Add P/E text label for attack coins var attackLabel = new Text2(isPlayer ? 'P' : 'E', { size: 40, fill: '#ffffff' }); attackLabel.anchor.set(0.5, 0.5); attackLabel.x = 0; attackLabel.y = 0; coin.addChild(attackLabel); LK.setTimeout(function (coinRef) { return function () { coinRef.flip(function (result) { if (result === 'heads') { successfulAttacks++; } coinsFlipped++; if (coinsFlipped === coinCount) { callback(successfulAttacks); } }, isPlayer); }; }(coin), i * 400); } } function finalizeBattle() { // Update health displays playerCard.updateHealth(Math.max(0, playerHealth), playerMaxHealth); enemyCard.updateHealth(Math.max(0, enemyHealth), enemyMaxHealth); // Check for game over LK.setTimeout(function () { if (playerHealth <= 0) { LK.showGameOver(); } else if (enemyHealth <= 0) { LK.showYouWin(); } else { // Reset for next turn resetTurn(); } }, 4000); } } function resetTurn() { gameState = 'selectSkill'; selectedSkill = null; skill1Button.setSelected(false); skill2Button.setSelected(false); readyButton.alpha = 0.5; statusText.setText('Choose your skill'); enemySkillText.setText(''); // Clear coin flips LK.setTimeout(function () { coinFlipContainer.removeChildren(); }, 2000); } // Game update loop game.update = function () { // Update status text based on game state if (gameState === 'selectClass') { // Class selection phase - no status updates needed } else if (gameState === 'selectSkill') { if (statusText) statusText.setText('Choose your skill'); if (enemySkillText) enemySkillText.setText(''); } else if (gameState === 'ready') { if (statusText) statusText.setText('Ready to battle with ' + selectedSkill.skillName + ' (Power: ' + selectedSkill.minPower + '-' + selectedSkill.maxPower + ', ' + selectedSkill.coinCount + ' coins)!'); // Show enemy's planned skill when player is ready var enemySkillIndex = Math.floor(Math.random() * enemySkills.length); var enemySkill = enemySkills[enemySkillIndex]; var enemyMinPower = Math.max(1, Math.floor(enemySkill.power * 0.3)); var enemyBonusPerSuccess = Math.max(2, Math.floor(enemySkill.power * 0.8)); var enemyMaxPower = enemyMinPower + enemySkill.coins * enemyBonusPerSuccess; if (enemySkillText) enemySkillText.setText('Enemy plans: ' + enemySkill.name + ' (Power: ' + enemyMinPower + '-' + enemyMaxPower + ', ' + enemySkill.coins + ' coins)'); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AttackButton = Container.expand(function (text) {
var self = Container.call(this);
var buttonBg = self.attachAsset('attackButton', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0xff4444;
var buttonText = new Text2(text, {
size: 70,
fill: '#ffffff'
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 0;
buttonText.y = 0;
self.addChild(buttonText);
self.setText = function (newText) {
buttonText.setText(newText);
};
self.down = function (x, y, obj) {
if (gameState === 'ready') {
// Add press effect
tween(buttonBg, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0xcc3333
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(buttonBg, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xff4444
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
performBattle();
}
};
return self;
});
var ClassButton = Container.expand(function (className, description, skills) {
var self = Container.call(this);
var buttonBg = self.attachAsset('classButton', {
anchorX: 0.5,
anchorY: 0.5
});
var classText = new Text2(className, {
size: 50,
fill: '#000000'
});
classText.anchor.set(0.5, 0.5);
classText.x = 0;
classText.y = -30;
self.addChild(classText);
var descText = new Text2(description, {
size: 30,
fill: '#000000'
});
descText.anchor.set(0.5, 0.5);
descText.x = 0;
descText.y = 30;
self.addChild(descText);
self.className = className;
self.skills = skills;
self.down = function (x, y, obj) {
if (gameState === 'selectClass') {
selectedClass = self;
startGame();
}
};
return self;
});
var CoinButton = Container.expand(function (coinCount) {
var self = Container.call(this);
var buttonBg = self.attachAsset('coinButton', {
anchorX: 0.5,
anchorY: 0.5
});
var coinText = new Text2(coinCount.toString(), {
size: 80,
fill: '#000000'
});
coinText.anchor.set(0.5, 0.5);
coinText.x = 0;
coinText.y = 0;
self.addChild(coinText);
self.coinCount = coinCount;
self.down = function (x, y, obj) {
if (gameState === 'selectCoins') {
selectedCoins = self.coinCount;
gameState = 'ready';
readyButton.alpha = 1;
}
};
return self;
});
var EnemyCard = Container.expand(function () {
var self = Container.call(this);
var cardBg = self.attachAsset('enemyCard', {
anchorX: 0.5,
anchorY: 0.5
});
var nameText = new Text2('ENEMY', {
size: 60,
fill: '#000000'
});
nameText.anchor.set(0.5, 0.5);
nameText.x = 0;
nameText.y = -140;
self.addChild(nameText);
self.setEnemyName = function (name) {
nameText.setText(name);
};
var healthBorder = self.attachAsset('healthBarBorder', {
anchorX: 0.5,
anchorY: 0.5
});
healthBorder.x = 0;
healthBorder.y = -60;
var healthBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBg.x = 0;
healthBg.y = -60;
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -60;
var healthText = new Text2('100/100', {
size: 48,
fill: '#000000'
});
healthText.anchor.set(0.5, 0.5);
healthText.x = 0;
healthText.y = -60;
self.addChild(healthText);
self.updateHealth = function (current, max) {
healthText.setText(current + '/' + max);
var healthPercent = current / max;
healthBar.scaleX = healthPercent;
healthBar.x = -250 + 250 * healthPercent;
};
return self;
});
var FlippingCoin = Container.expand(function () {
var self = Container.call(this);
var coinGraphic = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.isFlipping = false;
self.result = null;
self.flip = function (callback, isPlayer) {
self.isFlipping = true;
self.result = Math.random() < 0.5 ? 'heads' : 'tails';
// Play different sound based on player/enemy
if (isPlayer === true) {
LK.getSound('playerCoinFlip').play();
} else if (isPlayer === false) {
LK.getSound('enemyCoinFlip').play();
} else {
LK.getSound('coinFlip').play();
}
// Add initial scale and brightness effect
tween(coinGraphic, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xffffff
}, {
duration: 100,
easing: tween.easeOut
});
tween(coinGraphic, {
rotation: Math.PI * 6,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1800,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isFlipping = false;
if (self.result === 'heads') {
coinGraphic.tint = 0x00ff66;
// Success sparkle effect
tween(coinGraphic, {
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(coinGraphic, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.bounceOut
});
}
});
} else {
coinGraphic.tint = 0xff3366;
// Failure shake effect
tween(coinGraphic, {
x: coinGraphic.x + 10
}, {
duration: 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinGraphic, {
x: coinGraphic.x - 10
}, {
duration: 100,
easing: tween.easeInOut
});
}
});
}
if (callback) callback(self.result);
}
});
};
return self;
});
var PlayerCard = Container.expand(function () {
var self = Container.call(this);
var cardBg = self.attachAsset('playerCard', {
anchorX: 0.5,
anchorY: 0.5
});
var nameText = new Text2('PLAYER', {
size: 60,
fill: '#000000'
});
nameText.anchor.set(0.5, 0.5);
nameText.x = 0;
nameText.y = -140;
self.addChild(nameText);
var healthBorder = self.attachAsset('healthBarBorder', {
anchorX: 0.5,
anchorY: 0.5
});
healthBorder.x = 0;
healthBorder.y = -60;
var healthBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBg.x = 0;
healthBg.y = -60;
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -60;
var healthText = new Text2('100/100', {
size: 48,
fill: '#000000'
});
healthText.anchor.set(0.5, 0.5);
healthText.x = 0;
healthText.y = -60;
self.addChild(healthText);
self.updateHealth = function (current, max) {
healthText.setText(current + '/' + max);
var healthPercent = current / max;
healthBar.scaleX = healthPercent;
healthBar.x = -250 + 250 * healthPercent;
};
return self;
});
var SkillButton = Container.expand(function (skillName, basePower, coinCount) {
var self = Container.call(this);
var buttonBorder = self.attachAsset('skillButtonBorder', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonBg = self.attachAsset('skillButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Calculate power range based on new balanced formula
var minPower = Math.max(1, Math.floor(basePower * 0.3));
var bonusPerSuccess = Math.max(2, Math.floor(basePower * 0.8));
var maxPower = minPower + coinCount * bonusPerSuccess;
var skillText = new Text2(skillName + ' (Power: ' + minPower + '-' + maxPower + ', Coins: ' + coinCount + ')', {
size: 50,
fill: '#000000'
});
skillText.anchor.set(0.5, 0.5);
skillText.x = 0;
skillText.y = 0;
self.addChild(skillText);
self.skillName = skillName;
self.basePower = basePower;
self.coinCount = coinCount;
self.minPower = minPower;
self.maxPower = maxPower;
self.selected = false;
self.setSelected = function (selected) {
self.selected = selected;
if (selected) {
buttonBg.tint = 0x00ff88;
buttonBorder.tint = 0xff8800;
tween(buttonBorder, {
scaleX: 1.08,
scaleY: 1.08
}, {
duration: 200,
easing: tween.easeOut
});
// Add pulsing glow effect
tween(buttonBg, {
alpha: 0.7
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonBg, {
alpha: 1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.selected) {
self.setSelected(true); // Continue pulsing
}
}
});
}
});
} else {
buttonBg.tint = 0x27ae60;
buttonBorder.tint = 0x1e8449;
buttonBg.alpha = 1;
tween(buttonBorder, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.down = function (x, y, obj) {
if (gameState === 'selectSkill') {
selectedSkill = self;
skill1Button.setSelected(false);
skill2Button.setSelected(false);
self.setSelected(true);
gameState = 'ready';
readyButton.alpha = 1;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Game state variables
var gameState = 'selectClass';
var playerMaxHealth = 80 + Math.floor(Math.random() * 21); // 80-100 HP
var enemyMaxHealth = 80 + Math.floor(Math.random() * 21); // 80-100 HP
var playerHealth = playerMaxHealth;
var enemyHealth = enemyMaxHealth;
// Class definitions with their specific skills
var playerClasses = [{
name: 'Spearman',
description: 'Balanced fighter with reliable attacks',
skills: [{
name: 'Piercing Strike',
power: 6,
coins: 2
}, {
name: 'Whirlwind Assault',
power: 3,
coins: 5
}]
}, {
name: 'Samurai',
description: 'High-risk, high-reward warrior',
skills: [{
name: 'Perfect Cut',
power: 18,
coins: 1
}, {
name: 'Flurry Combo',
power: 2,
coins: 6
}]
}, {
name: 'Berserker',
description: 'Chaotic fighter with extreme variance',
skills: [{
name: 'Reckless Charge',
power: 5,
coins: 3
}, {
name: 'Fury Unleashed',
power: 1,
coins: 8
}]
}];
// Player skills will be assigned after class selection
var playerSkills = [];
var selectedClass = null;
// Enemy types with specialized skill sets
var enemyTypes = [{
name: 'Shadow Assassin',
description: 'Fast and precise attacks',
skills: [{
name: 'Shadow Strike',
power: 14,
coins: 1
}, {
name: 'Poison Dart Volley',
power: 3,
coins: 4
}]
}, {
name: 'Bone Golem',
description: 'Slow but devastating attacks',
skills: [{
name: 'Bone Crush',
power: 8,
coins: 2
}, {
name: 'Skeletal Rampage',
power: 2,
coins: 7
}]
}, {
name: 'Fire Demon',
description: 'Chaotic flame attacks',
skills: [{
name: 'Hellfire Blast',
power: 11,
coins: 1
}, {
name: 'Inferno Storm',
power: 4,
coins: 5
}]
}, {
name: 'Void Wraith',
description: 'Energy-based attacks',
skills: [{
name: 'Void Pulse',
power: 6,
coins: 3
}, {
name: 'Soul Drain',
power: 16,
coins: 1
}]
}, {
name: 'Frost Giant',
description: 'Ice-based powerful attacks',
skills: [{
name: 'Glacial Slam',
power: 9,
coins: 2
}, {
name: 'Blizzard Fury',
power: 3,
coins: 6
}]
}];
// Current enemy (will be randomly selected)
var currentEnemy = null;
var enemySkills = [];
// Current selection
var selectedSkill = null;
// Create class selection UI
var classSelectionTitle = new Text2('Choose Your Class', {
size: 80,
fill: '#000000'
});
classSelectionTitle.anchor.set(0.5, 0.5);
classSelectionTitle.x = 1024;
classSelectionTitle.y = 400;
game.addChild(classSelectionTitle);
var classButtons = [];
for (var i = 0; i < playerClasses.length; i++) {
var classButton = new ClassButton(playerClasses[i].name, playerClasses[i].description, playerClasses[i].skills);
classButton.x = 1024;
classButton.y = 700 + i * 300;
classButtons.push(classButton);
game.addChild(classButton);
}
// Game UI elements (will be created after class selection)
var playerCard = null;
var enemyCard = null;
var skill1Button = null;
var skill2Button = null;
var readyButton = null;
var statusText = null;
var enemySkillText = null;
// Battle result area
var battleResultText = new Text2('', {
size: 60,
fill: '#000000'
});
battleResultText.anchor.set(0.5, 0.5);
battleResultText.x = 1024;
battleResultText.y = 1750;
game.addChild(battleResultText);
// Coin flip display area
var coinFlipContainer = new Container();
coinFlipContainer.x = 1024;
coinFlipContainer.y = 1550;
game.addChild(coinFlipContainer);
// Live damage numbers container
var liveNumbersContainer = new Container();
liveNumbersContainer.x = 1024;
liveNumbersContainer.y = 1800;
game.addChild(liveNumbersContainer);
function showLiveDamageNumber(damage, x, y, isPlayer) {
var damageText = new Text2('-' + damage, {
size: 100,
fill: isPlayer ? '#ff0066' : '#ff6600'
});
damageText.anchor.set(0.5, 0.5);
damageText.x = x;
damageText.y = y;
damageText.alpha = 0;
damageText.scaleX = 0.5;
damageText.scaleY = 0.5;
liveNumbersContainer.addChild(damageText);
// Pop in effect
tween(damageText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Scale back and float up
tween(damageText, {
scaleX: 1.0,
scaleY: 1.0,
y: y - 120,
alpha: 0
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
liveNumbersContainer.removeChild(damageText);
}
});
}
});
}
function startGame() {
// Assign skills based on selected class
playerSkills = selectedClass.skills;
// Adjust health based on class - balanced fighters get more health
if (selectedClass.name === 'Spearman') {
playerMaxHealth += 20; // Balanced fighter gets extra durability
} else if (selectedClass.name === 'Samurai') {
playerMaxHealth -= 10; // High-risk fighter gets less health
} else if (selectedClass.name === 'Berserker') {
playerMaxHealth += 10; // Chaotic fighter gets moderate health boost
}
playerHealth = playerMaxHealth;
// Select random enemy type
var enemyIndex = Math.floor(Math.random() * enemyTypes.length);
currentEnemy = enemyTypes[enemyIndex];
enemySkills = currentEnemy.skills;
// Hide class selection UI
classSelectionTitle.alpha = 0;
for (var i = 0; i < classButtons.length; i++) {
classButtons[i].alpha = 0;
}
// Create game UI elements
playerCard = game.addChild(new PlayerCard());
playerCard.x = 1024;
playerCard.y = 600;
enemyCard = game.addChild(new EnemyCard());
enemyCard.x = 1024;
enemyCard.y = 300;
// Skills selection - positioned below player card with more spacing
skill1Button = game.addChild(new SkillButton(playerSkills[0].name, playerSkills[0].power, playerSkills[0].coins));
skill1Button.x = 1024;
skill1Button.y = 950;
skill2Button = game.addChild(new SkillButton(playerSkills[1].name, playerSkills[1].power, playerSkills[1].coins));
skill2Button.x = 1024;
skill2Button.y = 1130;
// Attack button
readyButton = game.addChild(new AttackButton('BATTLE!'));
readyButton.x = 1024;
readyButton.y = 1350;
readyButton.alpha = 0.5;
// Status text - positioned between player card and skill buttons
statusText = new Text2('Choose your skill', {
size: 70,
fill: '#000000'
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 1024;
statusText.y = 850;
game.addChild(statusText);
// Enemy description text
var enemyDescText = new Text2(currentEnemy.description, {
size: 40,
fill: '#666666'
});
enemyDescText.anchor.set(0.5, 0.5);
enemyDescText.x = 1024;
enemyDescText.y = 120;
game.addChild(enemyDescText);
// Enemy skill display text - positioned higher to avoid blocking
enemySkillText = new Text2('', {
size: 50,
fill: '#000000'
});
enemySkillText.anchor.set(0.5, 0.5);
enemySkillText.x = 1024;
enemySkillText.y = 150;
game.addChild(enemySkillText);
// Initialize health displays
playerCard.updateHealth(playerHealth, playerMaxHealth);
enemyCard.updateHealth(enemyHealth, enemyMaxHealth);
enemyCard.setEnemyName(currentEnemy.name);
// Change game state
gameState = 'selectSkill';
}
// Battle logic
function performBattle() {
if (!selectedSkill) return;
gameState = 'battle';
statusText.setText('Battle in progress...');
readyButton.alpha = 0.5;
// Player's turn
var playerBasePower = selectedSkill.basePower;
var playerCoins = selectedSkill.coinCount;
// Enemy's turn (AI)
var enemySkillIndex = Math.floor(Math.random() * enemySkills.length);
var enemySkill = enemySkills[enemySkillIndex];
var enemyBasePower = enemySkill.power;
var enemyCoins = enemySkill.coins;
var enemyMinPower = Math.max(1, Math.floor(enemyBasePower * 0.3));
var enemyBonusPerSuccess = Math.max(2, Math.floor(enemyBasePower * 0.8));
var enemyMaxPower = enemyMinPower + enemyCoins * enemyBonusPerSuccess;
// Display enemy's planned skill
enemySkillText.setText('Enemy plans: ' + enemySkill.name + ' (Power: ' + enemyMinPower + '-' + enemyMaxPower + ', ' + enemyCoins + ' coins)');
// Clear previous coins
coinFlipContainer.removeChildren();
// Flip player coins
var playerSuccessfulFlips = 0;
var playerCoinsFlipped = 0;
for (var i = 0; i < playerCoins; i++) {
var coin = new FlippingCoin();
coin.x = (i - (playerCoins - 1) / 2) * 100;
coin.y = -50;
coinFlipContainer.addChild(coin);
// Set player coin color
var coinGraphic = coin.getChildAt(0);
coinGraphic.tint = 0x4CAF50; // Green for player coins
// Add P text label for player coins
var playerLabel = new Text2('P', {
size: 40,
fill: '#ffffff'
});
playerLabel.anchor.set(0.5, 0.5);
playerLabel.x = 0;
playerLabel.y = 0;
coin.addChild(playerLabel);
LK.setTimeout(function (coinRef) {
return function () {
coinRef.flip(function (result) {
if (result === 'heads') {
playerSuccessfulFlips++;
}
playerCoinsFlipped++;
if (playerCoinsFlipped === playerCoins) {
// All player coins flipped, now flip enemy coins
flipEnemyCoins();
}
}, true);
};
}(coin), i * 800);
}
function flipEnemyCoins() {
var enemySuccessfulFlips = 0;
var enemyCoinsFlipped = 0;
for (var i = 0; i < enemyCoins; i++) {
var coin = new FlippingCoin();
coin.x = (i - (enemyCoins - 1) / 2) * 100;
coin.y = 50;
coinFlipContainer.addChild(coin);
// Set enemy coin color
var coinGraphic = coin.getChildAt(0);
coinGraphic.tint = 0xF44336; // Red for enemy coins
// Add E text label for enemy coins
var enemyLabel = new Text2('E', {
size: 40,
fill: '#ffffff'
});
enemyLabel.anchor.set(0.5, 0.5);
enemyLabel.x = 0;
enemyLabel.y = 0;
coin.addChild(enemyLabel);
LK.setTimeout(function (coinRef) {
return function () {
coinRef.flip(function (result) {
if (result === 'heads') {
enemySuccessfulFlips++;
}
enemyCoinsFlipped++;
if (enemyCoinsFlipped === enemyCoins) {
// All coins flipped, resolve battle
resolveBattle(playerBasePower, playerSuccessfulFlips, playerCoins, enemyBasePower, enemySuccessfulFlips, enemyCoins, enemySkill.name);
}
}, false);
};
}(coin), i * 800 + 3000);
}
}
}
function resolveBattle(playerBasePower, playerSuccessfulFlips, playerCoins, enemyBasePower, enemySuccessfulFlips, enemyCoins, enemySkillName) {
var playerTotalPower = playerBasePower + playerSuccessfulFlips * 2;
var enemyTotalPower = enemyBasePower + enemySuccessfulFlips * 2;
var resultText = 'CLASH RESULTS:\n';
resultText += 'Player: ' + playerBasePower + ' base + ' + playerSuccessfulFlips + '/' + playerCoins + ' heads = ' + playerTotalPower + '\n';
resultText += 'Enemy: ' + enemyBasePower + ' base + ' + enemySuccessfulFlips + '/' + enemyCoins + ' heads = ' + enemyTotalPower + '\n';
if (playerTotalPower > enemyTotalPower) {
// Player wins - roll attack coins
resultText += 'Player wins! Rolling ' + playerCoins + ' attack coins...\n';
rollAttackCoins(playerCoins, true, function (successfulAttacks) {
var playerMinPower = Math.max(1, Math.floor(playerBasePower * 0.3));
var bonusPerSuccess = Math.max(2, Math.floor(playerBasePower * 0.8));
var totalDamage = playerMinPower + successfulAttacks * bonusPerSuccess;
if (successfulAttacks === playerCoins) {
totalDamage = Math.floor(totalDamage * 1.5); // 50% damage bonus for perfect flips
resultText += 'CRITICAL HIT! Perfect flip grants 50% bonus damage!\n';
}
enemyHealth -= totalDamage;
resultText += 'Enemy takes ' + totalDamage + ' damage (' + successfulAttacks + '/' + playerCoins + ' successful attacks)!';
// Show live damage number
showLiveDamageNumber(totalDamage, 0, -100, false);
LK.getSound('attack').play();
LK.getSound('victory').play();
// Flash enemy red
tween(enemyCard, {
tint: 0xff0000
}, {
duration: 800,
onFinish: function onFinish() {
tween(enemyCard, {
tint: 0xffffff
}, {
duration: 800
});
}
});
battleResultText.setText(resultText);
finalizeBattle();
});
} else if (enemyTotalPower > playerTotalPower) {
// Enemy wins - roll attack coins
resultText += 'Enemy wins with ' + enemySkillName + '! Rolling ' + enemyCoins + ' attack coins...\n';
rollAttackCoins(enemyCoins, false, function (successfulAttacks) {
var enemyMinPower = Math.max(1, Math.floor(enemyBasePower * 0.3));
var bonusPerSuccess = Math.max(2, Math.floor(enemyBasePower * 0.8));
var totalDamage = enemyMinPower + successfulAttacks * bonusPerSuccess;
if (successfulAttacks === enemyCoins) {
totalDamage = Math.floor(totalDamage * 1.5); // 50% damage bonus for perfect flips
resultText += 'ENEMY CRITICAL HIT! Perfect flip grants 50% bonus damage!\n';
}
playerHealth -= totalDamage;
resultText += 'Player takes ' + totalDamage + ' damage (' + successfulAttacks + '/' + enemyCoins + ' successful attacks)!';
// Show live damage number
showLiveDamageNumber(totalDamage, 0, 100, true);
LK.getSound('damage').play();
LK.getSound('defeat').play();
// Flash player red
tween(playerCard, {
tint: 0xff0000
}, {
duration: 800,
onFinish: function onFinish() {
tween(playerCard, {
tint: 0xffffff
}, {
duration: 800
});
}
});
battleResultText.setText(resultText);
finalizeBattle();
});
} else {
// Tie
resultText += 'It\'s a tie! No damage dealt.';
battleResultText.setText(resultText);
finalizeBattle();
}
function rollAttackCoins(coinCount, isPlayer, callback) {
// Clear previous attack coins
var attackCoinsContainer = new Container();
attackCoinsContainer.x = 0;
attackCoinsContainer.y = isPlayer ? 150 : -150;
coinFlipContainer.addChild(attackCoinsContainer);
var successfulAttacks = 0;
var coinsFlipped = 0;
for (var i = 0; i < coinCount; i++) {
var coin = new FlippingCoin();
coin.x = (i - (coinCount - 1) / 2) * 80;
coin.y = 0;
attackCoinsContainer.addChild(coin);
// Set attack coin color based on player/enemy
var coinGraphic = coin.getChildAt(0);
coinGraphic.tint = isPlayer ? 0x2196F3 : 0xFF5722; // Blue for player attack, orange for enemy attack
// Add P/E text label for attack coins
var attackLabel = new Text2(isPlayer ? 'P' : 'E', {
size: 40,
fill: '#ffffff'
});
attackLabel.anchor.set(0.5, 0.5);
attackLabel.x = 0;
attackLabel.y = 0;
coin.addChild(attackLabel);
LK.setTimeout(function (coinRef) {
return function () {
coinRef.flip(function (result) {
if (result === 'heads') {
successfulAttacks++;
}
coinsFlipped++;
if (coinsFlipped === coinCount) {
callback(successfulAttacks);
}
}, isPlayer);
};
}(coin), i * 400);
}
}
function finalizeBattle() {
// Update health displays
playerCard.updateHealth(Math.max(0, playerHealth), playerMaxHealth);
enemyCard.updateHealth(Math.max(0, enemyHealth), enemyMaxHealth);
// Check for game over
LK.setTimeout(function () {
if (playerHealth <= 0) {
LK.showGameOver();
} else if (enemyHealth <= 0) {
LK.showYouWin();
} else {
// Reset for next turn
resetTurn();
}
}, 4000);
}
}
function resetTurn() {
gameState = 'selectSkill';
selectedSkill = null;
skill1Button.setSelected(false);
skill2Button.setSelected(false);
readyButton.alpha = 0.5;
statusText.setText('Choose your skill');
enemySkillText.setText('');
// Clear coin flips
LK.setTimeout(function () {
coinFlipContainer.removeChildren();
}, 2000);
}
// Game update loop
game.update = function () {
// Update status text based on game state
if (gameState === 'selectClass') {
// Class selection phase - no status updates needed
} else if (gameState === 'selectSkill') {
if (statusText) statusText.setText('Choose your skill');
if (enemySkillText) enemySkillText.setText('');
} else if (gameState === 'ready') {
if (statusText) statusText.setText('Ready to battle with ' + selectedSkill.skillName + ' (Power: ' + selectedSkill.minPower + '-' + selectedSkill.maxPower + ', ' + selectedSkill.coinCount + ' coins)!');
// Show enemy's planned skill when player is ready
var enemySkillIndex = Math.floor(Math.random() * enemySkills.length);
var enemySkill = enemySkills[enemySkillIndex];
var enemyMinPower = Math.max(1, Math.floor(enemySkill.power * 0.3));
var enemyBonusPerSuccess = Math.max(2, Math.floor(enemySkill.power * 0.8));
var enemyMaxPower = enemyMinPower + enemySkill.coins * enemyBonusPerSuccess;
if (enemySkillText) enemySkillText.setText('Enemy plans: ' + enemySkill.name + ' (Power: ' + enemyMinPower + '-' + enemyMaxPower + ', ' + enemySkill.coins + ' coins)');
}
};