/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Button = Container.expand(function (assetName, text) { var self = Container.call(this); var buttonGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2(text, { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { tween(buttonGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(buttonGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); }; return self; }); var CharacterCard = Container.expand(function (characterType, name) { var self = Container.call(this); self.characterType = characterType; self.isSelected = false; var cardBg = self.attachAsset('characterCard', { anchorX: 0.5, anchorY: 0.5 }); var character = self.attachAsset(characterType + 'Fighter', { anchorX: 0.5, anchorY: 0.8, y: -20 }); var nameText = new Text2(name, { size: 30, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = 100; self.addChild(nameText); self.setSelected = function (selected) { self.isSelected = selected; if (selected) { cardBg.tint = 0xf39c12; tween(cardBg, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } else { cardBg.tint = 0xFFFFFF; tween(cardBg, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }; self.down = function (x, y, obj) { if (gameState === 'characterSelect') { selectedCharacter = self.characterType; for (var i = 0; i < characterCards.length; i++) { characterCards[i].setSelected(characterCards[i] === self); } console.log('Selected character:', selectedCharacter); } }; return self; }); var Fighter = Container.expand(function (isPlayer) { var self = Container.call(this); self.isPlayer = isPlayer || false; self.maxHealth = 300; self.health = self.maxHealth; self.maxStamina = 100; self.stamina = self.maxStamina; self.attackPower = 20; self.isBlocking = false; self.isAttacking = false; self.canAttack = true; self.staminaRegenRate = 0.5; self.lastAttackTime = 0; var assetName = 'playerFighter'; if (isPlayer) { // Use the selected character for the player assetName = selectedCharacter + 'Fighter'; console.log('Using player asset:', assetName, 'selectedCharacter:', selectedCharacter); } else { // Randomly select enemy type for variety var enemyTypes = ['enemy', 'lizard', 'shark', 'wolf', 'bear', 'tiger', 'eagle']; var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; assetName = randomType + 'Fighter'; console.log('Using enemy asset:', assetName); } var fighterGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 1 }); self.attack = function () { if (!self.canAttack || self.stamina < 25) { return false; } self.isAttacking = true; self.canAttack = false; self.stamina -= 25; self.lastAttackTime = Date.now(); tween(fighterGraphics, { scaleX: 1.2, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(fighterGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); LK.getSound('punch').play(); // Add punch particles if (self.isPlayer) { var punchParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', self.x + 50, self.y - 100, 8)); } LK.setTimeout(function () { self.isAttacking = false; self.canAttack = true; }, 300); return true; }; self.block = function () { if (self.stamina < 15) { return false; } self.isBlocking = true; self.stamina -= 15; self.lastAttackTime = Date.now(); tween(fighterGraphics, { tint: 0x3498db }, { duration: 200, onFinish: function onFinish() { tween(fighterGraphics, { tint: 0xffffff }, { duration: 200 }); } }); LK.getSound('block').play(); // Add block particles if (self.isPlayer) { var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', self.x, self.y - 100, 12)); } LK.setTimeout(function () { self.isBlocking = false; }, 400); return true; }; self.specialAttack = function () { if (self.stamina < 60) { return false; } self.stamina -= 60; self.lastAttackTime = Date.now(); tween(fighterGraphics, { scaleX: 1.5, scaleY: 1.5, tint: 0xffd700 }, { duration: 300, onFinish: function onFinish() { tween(fighterGraphics, { scaleX: 1, scaleY: 1, tint: 0xffffff }, { duration: 300 }); } }); LK.getSound('special').play(); return true; }; self.takeDamage = function (damage) { if (self.isBlocking) { damage = Math.floor(damage * 0.2); } self.health -= damage; if (self.health < 0) { self.health = 0; } LK.effects.flashObject(self, 0xff0000, 200); tween(fighterGraphics, { x: fighterGraphics.x + (self.isPlayer ? -20 : 20) }, { duration: 100, onFinish: function onFinish() { tween(fighterGraphics, { x: 0 }, { duration: 100 }); } }); }; self.update = function () { var currentTime = Date.now(); // Only regenerate stamina if not attacking recently (1 second cooldown) if (currentTime - self.lastAttackTime > 1000) { if (self.stamina < self.maxStamina) { self.stamina += self.staminaRegenRate; if (self.stamina > self.maxStamina) { self.stamina = self.maxStamina; } } } }; return self; }); var HealthBar = Container.expand(function (maxValue) { var self = Container.call(this); self.maxValue = maxValue; self.currentValue = maxValue; var background = self.attachAsset('healthBarBg', { anchorX: 0, anchorY: 0 }); var bar = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0 }); self.setValue = function (value) { self.currentValue = value; var percentage = value / self.maxValue; bar.scaleX = percentage; if (percentage > 0.6) { bar.tint = 0x2ecc71; } else if (percentage > 0.3) { bar.tint = 0xf39c12; } else { bar.tint = 0xe74c3c; } }; return self; }); var ParticleSystem = Container.expand(function (particleType, x, y, count) { var self = Container.call(this); self.particles = []; self.particleType = particleType; self.x = x; self.y = y; // Create particles for (var i = 0; i < count; i++) { var particle = self.addChild(LK.getAsset(particleType, { anchorX: 0.5, anchorY: 0.5 })); // Set initial properties based on particle type if (particleType === 'sparkParticle') { particle.velocityX = (Math.random() - 0.5) * 200; particle.velocityY = (Math.random() - 0.5) * 200 - 100; particle.life = 1.0; particle.decay = 0.02; } else if (particleType === 'blockParticle') { particle.velocityX = (Math.random() - 0.5) * 150; particle.velocityY = (Math.random() - 0.5) * 150; particle.life = 1.0; particle.decay = 0.03; } else if (particleType === 'hitParticle') { particle.velocityX = (Math.random() - 0.5) * 300; particle.velocityY = (Math.random() - 0.5) * 300 - 50; particle.life = 1.0; particle.decay = 0.025; } self.particles.push(particle); } self.update = function () { for (var i = self.particles.length - 1; i >= 0; i--) { var particle = self.particles[i]; // Update position particle.x += particle.velocityX * 0.016; // 60fps particle.y += particle.velocityY * 0.016; // Apply gravity for spark and hit particles if (particleType === 'sparkParticle' || particleType === 'hitParticle') { particle.velocityY += 300 * 0.016; // Gravity } // Update life and alpha particle.life -= particle.decay; particle.alpha = particle.life; // Remove dead particles if (particle.life <= 0) { particle.destroy(); self.particles.splice(i, 1); } } // Remove system when all particles are gone if (self.particles.length === 0) { self.destroy(); } }; return self; }); var StaminaBar = Container.expand(function (maxValue) { var self = Container.call(this); self.maxValue = maxValue; self.currentValue = maxValue; var background = self.attachAsset('staminaBarBg', { anchorX: 0, anchorY: 0 }); var bar = self.attachAsset('staminaBar', { anchorX: 0, anchorY: 0 }); self.setValue = function (value) { self.currentValue = value; var percentage = value / self.maxValue; bar.scaleX = percentage; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ var gameState = 'menu'; var roundTimer = 60; var roundStartTime = 0; var battleCountdown = 3; var countdownActive = false; var timerMode = 'unlimited'; // 'unlimited' or 'limited' var selectedCharacter = 'shark'; var characterCards = []; var currentEnemyIndex = 0; var totalEnemies = 20; var enemyNames = ['Razor Claw', 'Iron Fang', 'Storm Fury', 'Shadow Beast', 'Thunder Paws', 'Venom Strike', 'Blade Runner', 'Fire Tooth', 'Ice Crusher', 'Wind Slasher', 'Stone Jaw', 'Lightning Bolt', 'Dark Hunter', 'Flame Warrior', 'Frost Bite', 'Night Stalker', 'Blood Fang', 'Steel Claw', 'Wild Storm', 'Bone Breaker', 'Crimson Fang', 'Golden Claw', 'Silver Strike', 'Midnight Howl', 'Dawn Breaker', 'Skull Crusher', 'Void Walker', 'Star Slayer', 'Moon Fang', 'Sun Warrior']; var menuContainer = game.addChild(new Container()); var characterSelectContainer = game.addChild(new Container()); var gameplayContainer = game.addChild(new Container()); // Create animated background for menu var menuBg = menuContainer.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1366, alpha: 0.3 })); // Create fighting characters in background var menuFighter1 = menuContainer.addChild(LK.getAsset('sharkFighter', { anchorX: 0.5, anchorY: 1, x: 2048 / 2 - 400, y: 1600, alpha: 0.4 })); var menuFighter2 = menuContainer.addChild(LK.getAsset('wolfFighter', { anchorX: 0.5, anchorY: 1, x: 2048 / 2 + 400, y: 1600, alpha: 0.4 })); // Animate background fighters tween(menuFighter1, { x: menuFighter1.x + 50, scaleX: 1.1, scaleY: 0.9 }, { duration: 1000, loop: true, yoyo: true }); tween(menuFighter2, { x: menuFighter2.x - 50, scaleX: 1.1, scaleY: 0.9 }, { duration: 1200, loop: true, yoyo: true }); var titleText = new Text2('FURRY FIGHTER ARENA', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; menuContainer.addChild(titleText); // Display previous game score var previousScore = storage.lastScore || 0; var previousScoreText = new Text2('Previous Score: ' + previousScore, { size: 50, fill: 0xecf0f1 }); previousScoreText.anchor.set(0.5, 0.5); previousScoreText.x = 2048 / 2; previousScoreText.y = 1000; menuContainer.addChild(previousScoreText); var startButton = new Button('menuButton', 'START COMBAT'); startButton.x = 2048 / 2; startButton.y = 1200; menuContainer.addChild(startButton); startButton.down = function (x, y, obj) { if (gameState === 'menu') { gameState = 'characterSelect'; menuContainer.visible = false; characterSelectContainer.visible = true; } }; var characterSelectTitle = new Text2('SELECT YOUR FIGHTER', { size: 60, fill: 0xFFFFFF }); characterSelectTitle.anchor.set(0.5, 0.5); characterSelectTitle.x = 2048 / 2; characterSelectTitle.y = 400; characterSelectContainer.addChild(characterSelectTitle); var sharkCard = new CharacterCard('shark', 'SHARK'); sharkCard.x = 2048 / 2 - 300; sharkCard.y = 1000; characterSelectContainer.addChild(sharkCard); characterCards.push(sharkCard); var lizardCard = new CharacterCard('lizard', 'LIZARD'); lizardCard.x = 2048 / 2; lizardCard.y = 1000; characterSelectContainer.addChild(lizardCard); characterCards.push(lizardCard); var wolfCard = new CharacterCard('wolf', 'WOLF'); wolfCard.x = 2048 / 2 + 300; wolfCard.y = 1000; characterSelectContainer.addChild(wolfCard); characterCards.push(wolfCard); sharkCard.setSelected(true); selectedCharacter = 'shark'; console.log('Initial selected character:', selectedCharacter); var difficultyText = new Text2('DIFFICULTY: MEDIUM', { size: 50, fill: 0xFFFFFF }); difficultyText.anchor.set(0.5, 0.5); difficultyText.x = 2048 / 2; difficultyText.y = 1300; characterSelectContainer.addChild(difficultyText); var difficultyButton = new Button('menuButton', 'CHANGE DIFFICULTY'); difficultyButton.x = 2048 / 2; difficultyButton.y = 1400; characterSelectContainer.addChild(difficultyButton); var timerModeText = new Text2('TIMER MODE: UNLIMITED', { size: 50, fill: 0xFFFFFF }); timerModeText.anchor.set(0.5, 0.5); timerModeText.x = 2048 / 2; timerModeText.y = 1500; characterSelectContainer.addChild(timerModeText); difficultyButton.down = function (x, y, obj) { if (gameState === 'characterSelect') { if (enemyAI.difficulty === 'easy') { enemyAI.difficulty = 'medium'; difficultyText.setText('DIFFICULTY: MEDIUM'); } else if (enemyAI.difficulty === 'medium') { enemyAI.difficulty = 'hard'; difficultyText.setText('DIFFICULTY: HARD'); } else { enemyAI.difficulty = 'easy'; difficultyText.setText('DIFFICULTY: EASY'); } } }; var timerModeButton = new Button('menuButton', 'TOGGLE TIMER'); timerModeButton.x = 2048 / 2; timerModeButton.y = 1550; characterSelectContainer.addChild(timerModeButton); timerModeButton.down = function (x, y, obj) { if (gameState === 'characterSelect') { if (timerMode === 'unlimited') { timerMode = 'limited'; timerModeText.setText('TIMER MODE: 90 SECONDS'); } else { timerMode = 'unlimited'; timerModeText.setText('TIMER MODE: UNLIMITED'); } } }; var fightButton = new Button('menuButton', 'FIGHT!'); fightButton.x = 2048 / 2; fightButton.y = 1650; characterSelectContainer.addChild(fightButton); fightButton.down = function (x, y, obj) { if (gameState === 'characterSelect') { gameState = 'countdown'; characterSelectContainer.visible = false; gameplayContainer.visible = true; // Show health and stamina bars when combat starts playerHealthBar.visible = true; enemyHealthBar.visible = true; playerStaminaBar.visible = true; enemyStaminaBar.visible = true; // Recreate player fighter with selected character gameplayContainer.removeChild(playerFighter); playerFighter = gameplayContainer.addChild(new Fighter(true)); playerFighter.x = 2048 / 2 - 300; playerFighter.y = 1600; if (timerMode === 'limited') { roundTimer = 90; } else { roundTimer = -1; // Unlimited time } battleCountdown = 3; countdownActive = true; // Reset enemy progression currentEnemyIndex = 0; // Shuffle enemy names for random encounters for (var i = enemyNames.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = enemyNames[i]; enemyNames[i] = enemyNames[j]; enemyNames[j] = temp; } } }; characterSelectContainer.visible = false; gameplayContainer.visible = false; var arena = gameplayContainer.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 1800 })); var arenaLine = gameplayContainer.addChild(LK.getAsset('arenaLine', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 1600 })); var playerFighter = gameplayContainer.addChild(new Fighter(true)); playerFighter.x = 2048 / 2 - 300; playerFighter.y = 1600; // Aligned with arena line var enemyFighter = gameplayContainer.addChild(new Fighter(false)); enemyFighter.x = 2048 / 2 + 300; enemyFighter.y = 1600; // Aligned with arena line var playerHealthBar = new HealthBar(300); playerHealthBar.x = 100; playerHealthBar.y = 100; playerHealthBar.visible = false; LK.gui.topLeft.addChild(playerHealthBar); var enemyHealthBar = new HealthBar(300); enemyHealthBar.x = -500; enemyHealthBar.y = 100; enemyHealthBar.visible = false; LK.gui.topRight.addChild(enemyHealthBar); var playerStaminaBar = new StaminaBar(100); playerStaminaBar.x = 100; playerStaminaBar.y = 150; playerStaminaBar.visible = false; LK.gui.topLeft.addChild(playerStaminaBar); var enemyStaminaBar = new StaminaBar(100); enemyStaminaBar.x = -500; enemyStaminaBar.y = 150; enemyStaminaBar.visible = false; LK.gui.topRight.addChild(enemyStaminaBar); var timerText = new Text2('60', { size: 80, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); var countdownText = new Text2('3', { size: 200, fill: 0xf39c12 }); countdownText.anchor.set(0.5, 0.5); countdownText.x = 2048 / 2; countdownText.y = 1366; gameplayContainer.addChild(countdownText); countdownText.visible = false; var scoreText = new Text2('Score: 0', { size: 50, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); scoreText.y = 100; LK.gui.top.addChild(scoreText); var actionSprite = LK.getAsset('actionSprite', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1000 }); gameplayContainer.addChild(actionSprite); actionSprite.visible = false; // Victory screen elements var victoryContainer = game.addChild(new Container()); victoryContainer.visible = false; var victoryBg = victoryContainer.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1366, scaleX: 1.2, scaleY: 1.5 })); victoryBg.tint = 0x2c3e50; victoryBg.alpha = 0.9; var koText = new Text2('K.O.!', { size: 150, fill: 0xf39c12 }); koText.anchor.set(0.5, 0.5); koText.x = 2048 / 2; koText.y = 800; victoryContainer.addChild(koText); var victoryText = new Text2('YOU WIN!', { size: 80, fill: 0x2ecc71 }); victoryText.anchor.set(0.5, 0.5); victoryText.x = 2048 / 2; victoryText.y = 950; victoryContainer.addChild(victoryText); var enemyDefeatedText = new Text2('', { size: 60, fill: 0xFFFFFF }); enemyDefeatedText.anchor.set(0.5, 0.5); enemyDefeatedText.x = 2048 / 2; enemyDefeatedText.y = 1100; victoryContainer.addChild(enemyDefeatedText); var progressText = new Text2('', { size: 50, fill: 0xecf0f1 }); progressText.anchor.set(0.5, 0.5); progressText.x = 2048 / 2; progressText.y = 1200; victoryContainer.addChild(progressText); var continueButton = new Button('menuButton', 'CONTINUE FIGHTING'); continueButton.x = 2048 / 2 - 250; continueButton.y = 1400; victoryContainer.addChild(continueButton); var stopButton = new Button('menuButton', 'STOP HERE'); stopButton.x = 2048 / 2 + 250; stopButton.y = 1400; victoryContainer.addChild(stopButton); function showActionSprite(actionType, color) { if (gameState !== 'playing') { return; } actionSprite.visible = true; actionSprite.tint = color; actionSprite.scaleX = 0.5; actionSprite.scaleY = 0.5; tween(actionSprite, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 500, onFinish: function onFinish() { actionSprite.visible = false; actionSprite.alpha = 1; actionSprite.scaleX = 1; actionSprite.scaleY = 1; } }); } // Movement controls in d-pad formation - bottom center-left positioning var moveUpButton = new Button('moveButton', '↑'); moveUpButton.x = -400; moveUpButton.y = -320; moveUpButton.scaleX = 1.5; moveUpButton.scaleY = 1.5; LK.gui.bottom.addChild(moveUpButton); var moveLeftButton = new Button('moveButton', '←'); moveLeftButton.x = -500; moveLeftButton.y = -220; moveLeftButton.scaleX = 1.5; moveLeftButton.scaleY = 1.5; LK.gui.bottom.addChild(moveLeftButton); var moveRightButton = new Button('moveButton', '→'); moveRightButton.x = -300; moveRightButton.y = -220; moveRightButton.scaleX = 1.5; moveRightButton.scaleY = 1.5; LK.gui.bottom.addChild(moveRightButton); var moveDownButton = new Button('moveButton', '↓'); moveDownButton.x = -400; moveDownButton.y = -120; moveDownButton.scaleX = 1.5; moveDownButton.scaleY = 1.5; LK.gui.bottom.addChild(moveDownButton); // Combat controls - bottom center positioning with better spacing var attackButton = new Button('attackButton', 'PUNCH'); attackButton.x = 0; attackButton.y = -320; attackButton.scaleX = 1.5; attackButton.scaleY = 1.5; LK.gui.bottom.addChild(attackButton); var kickButton = new Button('attackButton', 'KICK'); kickButton.x = 300; kickButton.y = -320; kickButton.scaleX = 1.5; kickButton.scaleY = 1.5; LK.gui.bottom.addChild(kickButton); var blockButton = new Button('blockButton', 'BLOCK'); blockButton.x = 150; blockButton.y = -180; blockButton.scaleX = 1.5; blockButton.scaleY = 1.5; LK.gui.bottom.addChild(blockButton); // Hide all action buttons initially moveUpButton.visible = false; moveLeftButton.visible = false; moveRightButton.visible = false; moveDownButton.visible = false; attackButton.visible = false; kickButton.visible = false; blockButton.visible = false; var playerSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50; var playerProjectiles = []; moveUpButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } // Jump functionality tween(playerFighter, { y: playerFighter.y - 100 }, { duration: 300, onFinish: function onFinish() { tween(playerFighter, { y: playerFighter.y + 100 }, { duration: 300 }); } }); }; moveLeftButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50; if (playerFighter.x > 200) { playerFighter.x -= currentSpeed; } }; moveRightButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50; if (playerFighter.x < 1848) { playerFighter.x += currentSpeed; } }; moveDownButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } // Crouch functionality tween(playerFighter, { scaleY: 0.5 }, { duration: 200, onFinish: function onFinish() { LK.setTimeout(function () { tween(playerFighter, { scaleY: 1 }, { duration: 200 }); }, 500); } }); }; attackButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } showActionSprite('attack', 0xe74c3c); if (playerFighter.attack()) { var distance = Math.abs(playerFighter.x - enemyFighter.x); if (distance < 350) { var damage = playerFighter.attackPower; enemyFighter.takeDamage(damage); // Add hit particles on enemy var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 10)); } } }; var kickCooldown = 0; kickButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } var currentTime = Date.now(); if (currentTime < kickCooldown) { return; // Kick is on cooldown } showActionSprite('kick', 0xff6b35); if (playerFighter.attack()) { // Add kick particles (more intense than punch) var kickParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', playerFighter.x + 60, playerFighter.y - 80, 15)); var distance = Math.abs(playerFighter.x - enemyFighter.x); if (distance < 400) { var damage = playerFighter.attackPower * 2.0; enemyFighter.takeDamage(damage); // Add more intense hit particles for kicks var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 15)); } kickCooldown = currentTime + 800; // 800ms cooldown for kicks } }; blockButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } showActionSprite('block', 0x3498db); playerFighter.block(); // Add additional block particles for visual feedback var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', playerFighter.x, playerFighter.y - 120, 15)); }; var enemyAI = { nextActionTime: 0, actionCooldown: 1000, nextMoveTime: 0, moveCooldown: 500, difficulty: 'medium', // easy, medium, hard playerHealthHistory: [], playerMovementHistory: [], consecutiveAttacks: 0, lastPlayerPosition: 0, adaptiveStrategy: 'balanced', // balanced, aggressive, defensive strategyTimer: 0, update: function update() { if (gameState !== 'playing') { return; } var currentTime = Date.now(); var distance = Math.abs(playerFighter.x - enemyFighter.x); // Track player behavior for adaptive AI this.trackPlayerBehavior(currentTime); // Update adaptive strategy based on difficulty this.updateAdaptiveStrategy(currentTime); // Get difficulty-based multipliers var difficultySettings = this.getDifficultySettings(); // Enhanced Movement AI with intelligent positioning if (currentTime >= this.nextMoveTime) { var moveAction = Math.random(); if (moveAction < difficultySettings.moveFrequency) { var optimalDistance = this.getOptimalDistance(); if (distance > optimalDistance + 50) { // Move closer with smart pathfinding var approachSpeed = difficultySettings.moveSpeed * this.getApproachMultiplier(); if (playerFighter.x > enemyFighter.x && enemyFighter.x < 1848) { enemyFighter.x += approachSpeed; } else if (playerFighter.x < enemyFighter.x && enemyFighter.x > 200) { enemyFighter.x -= approachSpeed; } } else if (distance < optimalDistance - 50) { // Maintain optimal distance with tactical retreats var retreatChance = difficultySettings.retreatChance; if (Math.random() < retreatChance) { var retreatSpeed = difficultySettings.moveSpeed * 0.8; if (playerFighter.x > enemyFighter.x && enemyFighter.x > 200) { enemyFighter.x -= retreatSpeed; } else if (playerFighter.x < enemyFighter.x && enemyFighter.x < 1848) { enemyFighter.x += retreatSpeed; } } } else { // Optimal distance - intelligent repositioning based on strategy var repositionChance = difficultySettings.repositionChance; if (Math.random() < repositionChance) { var tacticalMove = this.getTacticalMove(); if (enemyFighter.x + tacticalMove > 200 && enemyFighter.x + tacticalMove < 1848) { enemyFighter.x += tacticalMove; } } } } this.nextMoveTime = currentTime + difficultySettings.moveCooldown + Math.random() * 200; } // Advanced Dodge/Evasion AI with predictive movement if (playerFighter.isAttacking && distance < 400) { var dodgeChance = difficultySettings.dodgeChance; // Increase dodge chance if player is predictable if (this.consecutiveAttacks > 2) { dodgeChance *= 1.5; } if (Math.random() < dodgeChance && currentTime >= this.nextMoveTime) { var dodgeDirection = this.getPredictiveDodge(); if (enemyFighter.x + dodgeDirection > 200 && enemyFighter.x + dodgeDirection < 1848) { enemyFighter.x += dodgeDirection; this.nextMoveTime = currentTime + 150; // Quick cooldown after dodge } } } // Intelligent Combat AI with pattern recognition if (currentTime < this.nextActionTime) { return; } var combatDecision = this.makeCombatDecision(distance, currentTime); if (combatDecision.action === 'attack') { this.executeAttack(combatDecision.attackType, distance); } else if (combatDecision.action === 'block') { enemyFighter.block(); } else if (combatDecision.action === 'special') { if (enemyFighter.specialAttack()) { var specialDamage = enemyFighter.attackPower * (combatDecision.damageMultiplier || 2); playerFighter.takeDamage(specialDamage); } } // Dynamic cooldown based on AI intelligence and player behavior var finalCooldown = this.calculateAdaptiveCooldown(currentTime, difficultySettings); this.nextActionTime = currentTime + finalCooldown; }, getDifficultySettings: function getDifficultySettings() { var settings = { easy: { moveFrequency: 0.3, moveSpeed: 20, retreatChance: 0.2, repositionChance: 0.1, moveCooldown: 800, dodgeChance: 0.15, attackChance: 0.25, blockChance: 0.4, specialChance: 0.05, reactionTime: 1000, patternRecognition: 0.1 }, medium: { moveFrequency: 0.5, moveSpeed: 35, retreatChance: 0.35, repositionChance: 0.25, moveCooldown: 600, dodgeChance: 0.3, attackChance: 0.4, blockChance: 0.55, specialChance: 0.15, reactionTime: 700, patternRecognition: 0.3 }, hard: { moveFrequency: 0.7, moveSpeed: 50, retreatChance: 0.5, repositionChance: 0.4, moveCooldown: 400, dodgeChance: 0.45, attackChance: 0.55, blockChance: 0.7, specialChance: 0.25, reactionTime: 400, patternRecognition: 0.6 } }; return settings[this.difficulty]; }, trackPlayerBehavior: function trackPlayerBehavior(currentTime) { // Track player health changes this.playerHealthHistory.push({ time: currentTime, health: playerFighter.health, stamina: playerFighter.stamina }); if (this.playerHealthHistory.length > 10) { this.playerHealthHistory.shift(); } // Track player movement patterns if (this.lastPlayerPosition !== playerFighter.x) { this.playerMovementHistory.push({ time: currentTime, position: playerFighter.x, direction: playerFighter.x > this.lastPlayerPosition ? 'right' : 'left' }); this.lastPlayerPosition = playerFighter.x; } if (this.playerMovementHistory.length > 8) { this.playerMovementHistory.shift(); } // Track consecutive attacks if (playerFighter.isAttacking) { this.consecutiveAttacks++; } else if (currentTime - (playerFighter.lastAttackTime || 0) > 1000) { this.consecutiveAttacks = 0; } }, updateAdaptiveStrategy: function updateAdaptiveStrategy(currentTime) { if (currentTime < this.strategyTimer) return; var difficultySettings = this.getDifficultySettings(); var healthPercentage = enemyFighter.health / enemyFighter.maxHealth; var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina; // Switch strategies based on situation and difficulty intelligence if (difficultySettings.patternRecognition > Math.random()) { if (healthPercentage < 0.3) { this.adaptiveStrategy = 'defensive'; } else if (playerFighter.health < enemyFighter.health && staminaPercentage > 0.6) { this.adaptiveStrategy = 'aggressive'; } else { this.adaptiveStrategy = 'balanced'; } } this.strategyTimer = currentTime + 3000; // Re-evaluate every 3 seconds }, getOptimalDistance: function getOptimalDistance() { var baseDistance = 250; switch (this.adaptiveStrategy) { case 'aggressive': return baseDistance - 50; case 'defensive': return baseDistance + 100; default: return baseDistance; } }, getApproachMultiplier: function getApproachMultiplier() { var playerHealthPercentage = playerFighter.health / playerFighter.maxHealth; var multiplier = 1.0; // More aggressive approach when player is weak if (playerHealthPercentage < 0.3) { multiplier = 1.5; } else if (playerHealthPercentage < 0.6) { multiplier = 1.2; } return multiplier; }, getTacticalMove: function getTacticalMove() { var baseMove = Math.random() < 0.5 ? -30 : 30; // Add tactical positioning based on player movement patterns if (this.playerMovementHistory.length >= 3) { var recentMoves = this.playerMovementHistory.slice(-3); var rightMovements = recentMoves.filter(function (move) { return move.direction === 'right'; }).length; if (rightMovements >= 2) { // Player moving right, position for intercept baseMove = 40; } else if (rightMovements === 0) { // Player moving left, position for intercept baseMove = -40; } } return baseMove; }, getPredictiveDodge: function getPredictiveDodge() { var baseDodge = Math.random() < 0.5 ? -60 : 60; // Predict player attack direction based on position if (playerFighter.x > enemyFighter.x) { // Player attacking from right, dodge left baseDodge = -Math.abs(baseDodge); } else { // Player attacking from left, dodge right baseDodge = Math.abs(baseDodge); } return baseDodge; }, makeCombatDecision: function makeCombatDecision(distance, currentTime) { var difficultySettings = this.getDifficultySettings(); var decision = { action: 'wait' }; // Enhanced decision making based on multiple factors var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800; var shouldBlock = playerAttackingRecently && Math.random() < difficultySettings.blockChance * 1.5; var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina; var action = Math.random(); if (distance < 350) { if (shouldBlock && !enemyFighter.isBlocking) { decision.action = 'block'; } else if (action < difficultySettings.attackChance && enemyFighter.canAttack && enemyFighter.stamina >= 25) { decision.action = 'attack'; decision.attackType = this.chooseAttackType(distance, staminaPercentage); } else if (action < difficultySettings.blockChance && !playerAttackingRecently) { decision.action = 'block'; } } else if (distance < 500 && enemyFighter.stamina >= 60 && Math.random() < difficultySettings.specialChance) { decision.action = 'special'; decision.damageMultiplier = 1.5; } return decision; }, chooseAttackType: function chooseAttackType(distance, staminaPercentage) { var attackType = Math.random(); if (distance < 200 && attackType < 0.4) { return 'punch'; } else if (distance < 300 && attackType < 0.7) { return 'kick'; } else if (distance < 180 && attackType < 0.9) { return 'grab'; } else if (staminaPercentage > 0.6 && Math.random() < 0.3) { return 'special'; } return 'punch'; }, executeAttack: function executeAttack(attackType, distance) { switch (attackType) { case 'punch': if (enemyFighter.attack()) { playerFighter.takeDamage(enemyFighter.attackPower); } break; case 'kick': if (enemyFighter.attack()) { LK.setTimeout(function () { // Kick delay effect }, 400); playerFighter.takeDamage(enemyFighter.attackPower * 2.0); } break; case 'grab': if (enemyFighter.attack()) { playerFighter.takeDamage(enemyFighter.attackPower * 1.2); // Intelligent grab positioning var pullDistance = this.difficulty === 'hard' ? 40 : 30; if (playerFighter.x > enemyFighter.x) { playerFighter.x -= pullDistance; } else { playerFighter.x += pullDistance; } } break; case 'special': if (enemyFighter.specialAttack()) { playerFighter.takeDamage(enemyFighter.attackPower * 2); } break; } }, calculateAdaptiveCooldown: function calculateAdaptiveCooldown(currentTime, difficultySettings) { var baseCooldown = difficultySettings.reactionTime; var cooldownVariation = baseCooldown * 0.3; // Reduce cooldown based on player aggression var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800; var playerAggressiveBonus = playerAttackingRecently ? 0.7 : 1.0; // Increase cooldown if enemy is low on stamina var staminaPenalty = enemyFighter.stamina < 30 ? 1.5 : 1.0; // Strategy-based cooldown modification var strategyMultiplier = 1.0; switch (this.adaptiveStrategy) { case 'aggressive': strategyMultiplier = 0.8; break; case 'defensive': strategyMultiplier = 1.2; break; } var finalCooldown = baseCooldown * playerAggressiveBonus * staminaPenalty * strategyMultiplier + Math.random() * cooldownVariation; return Math.max(finalCooldown, 100); // Minimum 100ms cooldown } }; function checkGameEnd() { if (playerFighter.health <= 0) { gameState = 'gameOver'; storage.lastScore = LK.getScore(); LK.showGameOver(); return true; } if (enemyFighter.health <= 0) { gameState = 'victory'; LK.setScore(LK.getScore() + 100); // Show victory screen gameplayContainer.visible = false; victoryContainer.visible = true; enemyDefeatedText.setText(enemyNames[currentEnemyIndex] + ' DEFEATED!'); progressText.setText('Enemies Defeated: ' + (currentEnemyIndex + 1) + '/' + totalEnemies); // Hide action buttons moveUpButton.visible = false; moveLeftButton.visible = false; moveRightButton.visible = false; moveDownButton.visible = false; attackButton.visible = false; kickButton.visible = false; blockButton.visible = false; return true; } if (timerMode === 'limited' && roundTimer <= 0) { gameState = 'timeUp'; storage.lastScore = LK.getScore(); if (playerFighter.health > enemyFighter.health) { LK.setScore(LK.getScore() + 50); storage.lastScore = LK.getScore(); LK.showYouWin(); } else { LK.showGameOver(); } return true; } return false; } continueButton.down = function (x, y, obj) { if (gameState === 'victory') { currentEnemyIndex++; if (currentEnemyIndex >= totalEnemies) { // All enemies defeated var finalText = new Text2('CHAMPION!', { size: 100, fill: 0xf39c12 }); finalText.anchor.set(0.5, 0.5); finalText.x = 2048 / 2; finalText.y = 1366; game.addChild(finalText); LK.setScore(LK.getScore() + 500); storage.lastScore = LK.getScore(); LK.showYouWin(); return; } // Start next fight victoryContainer.visible = false; gameplayContainer.visible = true; gameState = 'countdown'; battleCountdown = 3; countdownActive = true; // Reset and recreate both fighters to ensure proper character selection gameplayContainer.removeChild(playerFighter); gameplayContainer.removeChild(enemyFighter); playerFighter = gameplayContainer.addChild(new Fighter(true)); playerFighter.x = 2048 / 2 - 300; playerFighter.y = 1600; enemyFighter = gameplayContainer.addChild(new Fighter(false)); enemyFighter.x = 2048 / 2 + 300; enemyFighter.y = 1600; if (timerMode === 'limited') { roundTimer = 90; } else { roundTimer = -1; } } }; stopButton.down = function (x, y, obj) { if (gameState === 'victory') { LK.setScore(LK.getScore() + 50); storage.lastScore = LK.getScore(); LK.showYouWin(); } }; LK.playMusic('battleMusic'); game.update = function () { if (gameState === 'countdown') { if (countdownActive) { countdownText.visible = true; countdownText.setText(battleCountdown.toString()); if (LK.ticks % 60 === 0) { battleCountdown--; if (battleCountdown <= 0) { countdownActive = false; countdownText.visible = false; gameState = 'playing'; } } } } if (gameState === 'playing') { // Show action buttons when game starts moveUpButton.visible = true; moveLeftButton.visible = true; moveRightButton.visible = true; moveDownButton.visible = true; attackButton.visible = true; kickButton.visible = true; blockButton.visible = true; if (timerMode === 'limited') { if (LK.ticks % 60 === 0) { roundTimer--; timerText.setText(roundTimer.toString()); if (roundTimer <= 10) { timerText.tint = 0xe74c3c; } } } else { timerText.setText('∞'); } playerHealthBar.setValue(playerFighter.health); enemyHealthBar.setValue(enemyFighter.health); playerStaminaBar.setValue(playerFighter.stamina); enemyStaminaBar.setValue(enemyFighter.stamina); scoreText.setText('Score: ' + LK.getScore()); enemyAI.update(); // Update projectiles for (var i = playerProjectiles.length - 1; i >= 0; i--) { var projectile = playerProjectiles[i]; var deltaX = projectile.targetX - projectile.x; var deltaY = (projectile.targetY || enemyFighter.y - 50) - projectile.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 50) { // Hit enemy var damage = selectedCharacter === 'shark' ? playerFighter.attackPower * 1.8 : playerFighter.attackPower * 2; enemyFighter.takeDamage(damage); projectile.destroy(); playerProjectiles.splice(i, 1); } else if (distance > 800) { // Out of range projectile.destroy(); playerProjectiles.splice(i, 1); } else { // Move projectile projectile.x += deltaX / distance * projectile.speed; projectile.y += deltaY / distance * projectile.speed; } } checkGameEnd(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Button = Container.expand(function (assetName, text) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function (x, y, obj) {
tween(buttonGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(buttonGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
return self;
});
var CharacterCard = Container.expand(function (characterType, name) {
var self = Container.call(this);
self.characterType = characterType;
self.isSelected = false;
var cardBg = self.attachAsset('characterCard', {
anchorX: 0.5,
anchorY: 0.5
});
var character = self.attachAsset(characterType + 'Fighter', {
anchorX: 0.5,
anchorY: 0.8,
y: -20
});
var nameText = new Text2(name, {
size: 30,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = 100;
self.addChild(nameText);
self.setSelected = function (selected) {
self.isSelected = selected;
if (selected) {
cardBg.tint = 0xf39c12;
tween(cardBg, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200
});
} else {
cardBg.tint = 0xFFFFFF;
tween(cardBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
};
self.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
selectedCharacter = self.characterType;
for (var i = 0; i < characterCards.length; i++) {
characterCards[i].setSelected(characterCards[i] === self);
}
console.log('Selected character:', selectedCharacter);
}
};
return self;
});
var Fighter = Container.expand(function (isPlayer) {
var self = Container.call(this);
self.isPlayer = isPlayer || false;
self.maxHealth = 300;
self.health = self.maxHealth;
self.maxStamina = 100;
self.stamina = self.maxStamina;
self.attackPower = 20;
self.isBlocking = false;
self.isAttacking = false;
self.canAttack = true;
self.staminaRegenRate = 0.5;
self.lastAttackTime = 0;
var assetName = 'playerFighter';
if (isPlayer) {
// Use the selected character for the player
assetName = selectedCharacter + 'Fighter';
console.log('Using player asset:', assetName, 'selectedCharacter:', selectedCharacter);
} else {
// Randomly select enemy type for variety
var enemyTypes = ['enemy', 'lizard', 'shark', 'wolf', 'bear', 'tiger', 'eagle'];
var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
assetName = randomType + 'Fighter';
console.log('Using enemy asset:', assetName);
}
var fighterGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1
});
self.attack = function () {
if (!self.canAttack || self.stamina < 25) {
return false;
}
self.isAttacking = true;
self.canAttack = false;
self.stamina -= 25;
self.lastAttackTime = Date.now();
tween(fighterGraphics, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(fighterGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
LK.getSound('punch').play();
// Add punch particles
if (self.isPlayer) {
var punchParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', self.x + 50, self.y - 100, 8));
}
LK.setTimeout(function () {
self.isAttacking = false;
self.canAttack = true;
}, 300);
return true;
};
self.block = function () {
if (self.stamina < 15) {
return false;
}
self.isBlocking = true;
self.stamina -= 15;
self.lastAttackTime = Date.now();
tween(fighterGraphics, {
tint: 0x3498db
}, {
duration: 200,
onFinish: function onFinish() {
tween(fighterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
LK.getSound('block').play();
// Add block particles
if (self.isPlayer) {
var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', self.x, self.y - 100, 12));
}
LK.setTimeout(function () {
self.isBlocking = false;
}, 400);
return true;
};
self.specialAttack = function () {
if (self.stamina < 60) {
return false;
}
self.stamina -= 60;
self.lastAttackTime = Date.now();
tween(fighterGraphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xffd700
}, {
duration: 300,
onFinish: function onFinish() {
tween(fighterGraphics, {
scaleX: 1,
scaleY: 1,
tint: 0xffffff
}, {
duration: 300
});
}
});
LK.getSound('special').play();
return true;
};
self.takeDamage = function (damage) {
if (self.isBlocking) {
damage = Math.floor(damage * 0.2);
}
self.health -= damage;
if (self.health < 0) {
self.health = 0;
}
LK.effects.flashObject(self, 0xff0000, 200);
tween(fighterGraphics, {
x: fighterGraphics.x + (self.isPlayer ? -20 : 20)
}, {
duration: 100,
onFinish: function onFinish() {
tween(fighterGraphics, {
x: 0
}, {
duration: 100
});
}
});
};
self.update = function () {
var currentTime = Date.now();
// Only regenerate stamina if not attacking recently (1 second cooldown)
if (currentTime - self.lastAttackTime > 1000) {
if (self.stamina < self.maxStamina) {
self.stamina += self.staminaRegenRate;
if (self.stamina > self.maxStamina) {
self.stamina = self.maxStamina;
}
}
}
};
return self;
});
var HealthBar = Container.expand(function (maxValue) {
var self = Container.call(this);
self.maxValue = maxValue;
self.currentValue = maxValue;
var background = self.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
var bar = self.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
self.setValue = function (value) {
self.currentValue = value;
var percentage = value / self.maxValue;
bar.scaleX = percentage;
if (percentage > 0.6) {
bar.tint = 0x2ecc71;
} else if (percentage > 0.3) {
bar.tint = 0xf39c12;
} else {
bar.tint = 0xe74c3c;
}
};
return self;
});
var ParticleSystem = Container.expand(function (particleType, x, y, count) {
var self = Container.call(this);
self.particles = [];
self.particleType = particleType;
self.x = x;
self.y = y;
// Create particles
for (var i = 0; i < count; i++) {
var particle = self.addChild(LK.getAsset(particleType, {
anchorX: 0.5,
anchorY: 0.5
}));
// Set initial properties based on particle type
if (particleType === 'sparkParticle') {
particle.velocityX = (Math.random() - 0.5) * 200;
particle.velocityY = (Math.random() - 0.5) * 200 - 100;
particle.life = 1.0;
particle.decay = 0.02;
} else if (particleType === 'blockParticle') {
particle.velocityX = (Math.random() - 0.5) * 150;
particle.velocityY = (Math.random() - 0.5) * 150;
particle.life = 1.0;
particle.decay = 0.03;
} else if (particleType === 'hitParticle') {
particle.velocityX = (Math.random() - 0.5) * 300;
particle.velocityY = (Math.random() - 0.5) * 300 - 50;
particle.life = 1.0;
particle.decay = 0.025;
}
self.particles.push(particle);
}
self.update = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
// Update position
particle.x += particle.velocityX * 0.016; // 60fps
particle.y += particle.velocityY * 0.016;
// Apply gravity for spark and hit particles
if (particleType === 'sparkParticle' || particleType === 'hitParticle') {
particle.velocityY += 300 * 0.016; // Gravity
}
// Update life and alpha
particle.life -= particle.decay;
particle.alpha = particle.life;
// Remove dead particles
if (particle.life <= 0) {
particle.destroy();
self.particles.splice(i, 1);
}
}
// Remove system when all particles are gone
if (self.particles.length === 0) {
self.destroy();
}
};
return self;
});
var StaminaBar = Container.expand(function (maxValue) {
var self = Container.call(this);
self.maxValue = maxValue;
self.currentValue = maxValue;
var background = self.attachAsset('staminaBarBg', {
anchorX: 0,
anchorY: 0
});
var bar = self.attachAsset('staminaBar', {
anchorX: 0,
anchorY: 0
});
self.setValue = function (value) {
self.currentValue = value;
var percentage = value / self.maxValue;
bar.scaleX = percentage;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var gameState = 'menu';
var roundTimer = 60;
var roundStartTime = 0;
var battleCountdown = 3;
var countdownActive = false;
var timerMode = 'unlimited'; // 'unlimited' or 'limited'
var selectedCharacter = 'shark';
var characterCards = [];
var currentEnemyIndex = 0;
var totalEnemies = 20;
var enemyNames = ['Razor Claw', 'Iron Fang', 'Storm Fury', 'Shadow Beast', 'Thunder Paws', 'Venom Strike', 'Blade Runner', 'Fire Tooth', 'Ice Crusher', 'Wind Slasher', 'Stone Jaw', 'Lightning Bolt', 'Dark Hunter', 'Flame Warrior', 'Frost Bite', 'Night Stalker', 'Blood Fang', 'Steel Claw', 'Wild Storm', 'Bone Breaker', 'Crimson Fang', 'Golden Claw', 'Silver Strike', 'Midnight Howl', 'Dawn Breaker', 'Skull Crusher', 'Void Walker', 'Star Slayer', 'Moon Fang', 'Sun Warrior'];
var menuContainer = game.addChild(new Container());
var characterSelectContainer = game.addChild(new Container());
var gameplayContainer = game.addChild(new Container());
// Create animated background for menu
var menuBg = menuContainer.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366,
alpha: 0.3
}));
// Create fighting characters in background
var menuFighter1 = menuContainer.addChild(LK.getAsset('sharkFighter', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 - 400,
y: 1600,
alpha: 0.4
}));
var menuFighter2 = menuContainer.addChild(LK.getAsset('wolfFighter', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 + 400,
y: 1600,
alpha: 0.4
}));
// Animate background fighters
tween(menuFighter1, {
x: menuFighter1.x + 50,
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 1000,
loop: true,
yoyo: true
});
tween(menuFighter2, {
x: menuFighter2.x - 50,
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 1200,
loop: true,
yoyo: true
});
var titleText = new Text2('FURRY FIGHTER ARENA', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
menuContainer.addChild(titleText);
// Display previous game score
var previousScore = storage.lastScore || 0;
var previousScoreText = new Text2('Previous Score: ' + previousScore, {
size: 50,
fill: 0xecf0f1
});
previousScoreText.anchor.set(0.5, 0.5);
previousScoreText.x = 2048 / 2;
previousScoreText.y = 1000;
menuContainer.addChild(previousScoreText);
var startButton = new Button('menuButton', 'START COMBAT');
startButton.x = 2048 / 2;
startButton.y = 1200;
menuContainer.addChild(startButton);
startButton.down = function (x, y, obj) {
if (gameState === 'menu') {
gameState = 'characterSelect';
menuContainer.visible = false;
characterSelectContainer.visible = true;
}
};
var characterSelectTitle = new Text2('SELECT YOUR FIGHTER', {
size: 60,
fill: 0xFFFFFF
});
characterSelectTitle.anchor.set(0.5, 0.5);
characterSelectTitle.x = 2048 / 2;
characterSelectTitle.y = 400;
characterSelectContainer.addChild(characterSelectTitle);
var sharkCard = new CharacterCard('shark', 'SHARK');
sharkCard.x = 2048 / 2 - 300;
sharkCard.y = 1000;
characterSelectContainer.addChild(sharkCard);
characterCards.push(sharkCard);
var lizardCard = new CharacterCard('lizard', 'LIZARD');
lizardCard.x = 2048 / 2;
lizardCard.y = 1000;
characterSelectContainer.addChild(lizardCard);
characterCards.push(lizardCard);
var wolfCard = new CharacterCard('wolf', 'WOLF');
wolfCard.x = 2048 / 2 + 300;
wolfCard.y = 1000;
characterSelectContainer.addChild(wolfCard);
characterCards.push(wolfCard);
sharkCard.setSelected(true);
selectedCharacter = 'shark';
console.log('Initial selected character:', selectedCharacter);
var difficultyText = new Text2('DIFFICULTY: MEDIUM', {
size: 50,
fill: 0xFFFFFF
});
difficultyText.anchor.set(0.5, 0.5);
difficultyText.x = 2048 / 2;
difficultyText.y = 1300;
characterSelectContainer.addChild(difficultyText);
var difficultyButton = new Button('menuButton', 'CHANGE DIFFICULTY');
difficultyButton.x = 2048 / 2;
difficultyButton.y = 1400;
characterSelectContainer.addChild(difficultyButton);
var timerModeText = new Text2('TIMER MODE: UNLIMITED', {
size: 50,
fill: 0xFFFFFF
});
timerModeText.anchor.set(0.5, 0.5);
timerModeText.x = 2048 / 2;
timerModeText.y = 1500;
characterSelectContainer.addChild(timerModeText);
difficultyButton.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
if (enemyAI.difficulty === 'easy') {
enemyAI.difficulty = 'medium';
difficultyText.setText('DIFFICULTY: MEDIUM');
} else if (enemyAI.difficulty === 'medium') {
enemyAI.difficulty = 'hard';
difficultyText.setText('DIFFICULTY: HARD');
} else {
enemyAI.difficulty = 'easy';
difficultyText.setText('DIFFICULTY: EASY');
}
}
};
var timerModeButton = new Button('menuButton', 'TOGGLE TIMER');
timerModeButton.x = 2048 / 2;
timerModeButton.y = 1550;
characterSelectContainer.addChild(timerModeButton);
timerModeButton.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
if (timerMode === 'unlimited') {
timerMode = 'limited';
timerModeText.setText('TIMER MODE: 90 SECONDS');
} else {
timerMode = 'unlimited';
timerModeText.setText('TIMER MODE: UNLIMITED');
}
}
};
var fightButton = new Button('menuButton', 'FIGHT!');
fightButton.x = 2048 / 2;
fightButton.y = 1650;
characterSelectContainer.addChild(fightButton);
fightButton.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
gameState = 'countdown';
characterSelectContainer.visible = false;
gameplayContainer.visible = true;
// Show health and stamina bars when combat starts
playerHealthBar.visible = true;
enemyHealthBar.visible = true;
playerStaminaBar.visible = true;
enemyStaminaBar.visible = true;
// Recreate player fighter with selected character
gameplayContainer.removeChild(playerFighter);
playerFighter = gameplayContainer.addChild(new Fighter(true));
playerFighter.x = 2048 / 2 - 300;
playerFighter.y = 1600;
if (timerMode === 'limited') {
roundTimer = 90;
} else {
roundTimer = -1; // Unlimited time
}
battleCountdown = 3;
countdownActive = true;
// Reset enemy progression
currentEnemyIndex = 0;
// Shuffle enemy names for random encounters
for (var i = enemyNames.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = enemyNames[i];
enemyNames[i] = enemyNames[j];
enemyNames[j] = temp;
}
}
};
characterSelectContainer.visible = false;
gameplayContainer.visible = false;
var arena = gameplayContainer.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 1800
}));
var arenaLine = gameplayContainer.addChild(LK.getAsset('arenaLine', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 1600
}));
var playerFighter = gameplayContainer.addChild(new Fighter(true));
playerFighter.x = 2048 / 2 - 300;
playerFighter.y = 1600; // Aligned with arena line
var enemyFighter = gameplayContainer.addChild(new Fighter(false));
enemyFighter.x = 2048 / 2 + 300;
enemyFighter.y = 1600; // Aligned with arena line
var playerHealthBar = new HealthBar(300);
playerHealthBar.x = 100;
playerHealthBar.y = 100;
playerHealthBar.visible = false;
LK.gui.topLeft.addChild(playerHealthBar);
var enemyHealthBar = new HealthBar(300);
enemyHealthBar.x = -500;
enemyHealthBar.y = 100;
enemyHealthBar.visible = false;
LK.gui.topRight.addChild(enemyHealthBar);
var playerStaminaBar = new StaminaBar(100);
playerStaminaBar.x = 100;
playerStaminaBar.y = 150;
playerStaminaBar.visible = false;
LK.gui.topLeft.addChild(playerStaminaBar);
var enemyStaminaBar = new StaminaBar(100);
enemyStaminaBar.x = -500;
enemyStaminaBar.y = 150;
enemyStaminaBar.visible = false;
LK.gui.topRight.addChild(enemyStaminaBar);
var timerText = new Text2('60', {
size: 80,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
var countdownText = new Text2('3', {
size: 200,
fill: 0xf39c12
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 2048 / 2;
countdownText.y = 1366;
gameplayContainer.addChild(countdownText);
countdownText.visible = false;
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 100;
LK.gui.top.addChild(scoreText);
var actionSprite = LK.getAsset('actionSprite', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1000
});
gameplayContainer.addChild(actionSprite);
actionSprite.visible = false;
// Victory screen elements
var victoryContainer = game.addChild(new Container());
victoryContainer.visible = false;
var victoryBg = victoryContainer.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366,
scaleX: 1.2,
scaleY: 1.5
}));
victoryBg.tint = 0x2c3e50;
victoryBg.alpha = 0.9;
var koText = new Text2('K.O.!', {
size: 150,
fill: 0xf39c12
});
koText.anchor.set(0.5, 0.5);
koText.x = 2048 / 2;
koText.y = 800;
victoryContainer.addChild(koText);
var victoryText = new Text2('YOU WIN!', {
size: 80,
fill: 0x2ecc71
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 2048 / 2;
victoryText.y = 950;
victoryContainer.addChild(victoryText);
var enemyDefeatedText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
enemyDefeatedText.anchor.set(0.5, 0.5);
enemyDefeatedText.x = 2048 / 2;
enemyDefeatedText.y = 1100;
victoryContainer.addChild(enemyDefeatedText);
var progressText = new Text2('', {
size: 50,
fill: 0xecf0f1
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 2048 / 2;
progressText.y = 1200;
victoryContainer.addChild(progressText);
var continueButton = new Button('menuButton', 'CONTINUE FIGHTING');
continueButton.x = 2048 / 2 - 250;
continueButton.y = 1400;
victoryContainer.addChild(continueButton);
var stopButton = new Button('menuButton', 'STOP HERE');
stopButton.x = 2048 / 2 + 250;
stopButton.y = 1400;
victoryContainer.addChild(stopButton);
function showActionSprite(actionType, color) {
if (gameState !== 'playing') {
return;
}
actionSprite.visible = true;
actionSprite.tint = color;
actionSprite.scaleX = 0.5;
actionSprite.scaleY = 0.5;
tween(actionSprite, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
actionSprite.visible = false;
actionSprite.alpha = 1;
actionSprite.scaleX = 1;
actionSprite.scaleY = 1;
}
});
}
// Movement controls in d-pad formation - bottom center-left positioning
var moveUpButton = new Button('moveButton', '↑');
moveUpButton.x = -400;
moveUpButton.y = -320;
moveUpButton.scaleX = 1.5;
moveUpButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveUpButton);
var moveLeftButton = new Button('moveButton', '←');
moveLeftButton.x = -500;
moveLeftButton.y = -220;
moveLeftButton.scaleX = 1.5;
moveLeftButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveLeftButton);
var moveRightButton = new Button('moveButton', '→');
moveRightButton.x = -300;
moveRightButton.y = -220;
moveRightButton.scaleX = 1.5;
moveRightButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveRightButton);
var moveDownButton = new Button('moveButton', '↓');
moveDownButton.x = -400;
moveDownButton.y = -120;
moveDownButton.scaleX = 1.5;
moveDownButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveDownButton);
// Combat controls - bottom center positioning with better spacing
var attackButton = new Button('attackButton', 'PUNCH');
attackButton.x = 0;
attackButton.y = -320;
attackButton.scaleX = 1.5;
attackButton.scaleY = 1.5;
LK.gui.bottom.addChild(attackButton);
var kickButton = new Button('attackButton', 'KICK');
kickButton.x = 300;
kickButton.y = -320;
kickButton.scaleX = 1.5;
kickButton.scaleY = 1.5;
LK.gui.bottom.addChild(kickButton);
var blockButton = new Button('blockButton', 'BLOCK');
blockButton.x = 150;
blockButton.y = -180;
blockButton.scaleX = 1.5;
blockButton.scaleY = 1.5;
LK.gui.bottom.addChild(blockButton);
// Hide all action buttons initially
moveUpButton.visible = false;
moveLeftButton.visible = false;
moveRightButton.visible = false;
moveDownButton.visible = false;
attackButton.visible = false;
kickButton.visible = false;
blockButton.visible = false;
var playerSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50;
var playerProjectiles = [];
moveUpButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
// Jump functionality
tween(playerFighter, {
y: playerFighter.y - 100
}, {
duration: 300,
onFinish: function onFinish() {
tween(playerFighter, {
y: playerFighter.y + 100
}, {
duration: 300
});
}
});
};
moveLeftButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50;
if (playerFighter.x > 200) {
playerFighter.x -= currentSpeed;
}
};
moveRightButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50;
if (playerFighter.x < 1848) {
playerFighter.x += currentSpeed;
}
};
moveDownButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
// Crouch functionality
tween(playerFighter, {
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(playerFighter, {
scaleY: 1
}, {
duration: 200
});
}, 500);
}
});
};
attackButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
showActionSprite('attack', 0xe74c3c);
if (playerFighter.attack()) {
var distance = Math.abs(playerFighter.x - enemyFighter.x);
if (distance < 350) {
var damage = playerFighter.attackPower;
enemyFighter.takeDamage(damage);
// Add hit particles on enemy
var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 10));
}
}
};
var kickCooldown = 0;
kickButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
var currentTime = Date.now();
if (currentTime < kickCooldown) {
return; // Kick is on cooldown
}
showActionSprite('kick', 0xff6b35);
if (playerFighter.attack()) {
// Add kick particles (more intense than punch)
var kickParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', playerFighter.x + 60, playerFighter.y - 80, 15));
var distance = Math.abs(playerFighter.x - enemyFighter.x);
if (distance < 400) {
var damage = playerFighter.attackPower * 2.0;
enemyFighter.takeDamage(damage);
// Add more intense hit particles for kicks
var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 15));
}
kickCooldown = currentTime + 800; // 800ms cooldown for kicks
}
};
blockButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
showActionSprite('block', 0x3498db);
playerFighter.block();
// Add additional block particles for visual feedback
var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', playerFighter.x, playerFighter.y - 120, 15));
};
var enemyAI = {
nextActionTime: 0,
actionCooldown: 1000,
nextMoveTime: 0,
moveCooldown: 500,
difficulty: 'medium',
// easy, medium, hard
playerHealthHistory: [],
playerMovementHistory: [],
consecutiveAttacks: 0,
lastPlayerPosition: 0,
adaptiveStrategy: 'balanced',
// balanced, aggressive, defensive
strategyTimer: 0,
update: function update() {
if (gameState !== 'playing') {
return;
}
var currentTime = Date.now();
var distance = Math.abs(playerFighter.x - enemyFighter.x);
// Track player behavior for adaptive AI
this.trackPlayerBehavior(currentTime);
// Update adaptive strategy based on difficulty
this.updateAdaptiveStrategy(currentTime);
// Get difficulty-based multipliers
var difficultySettings = this.getDifficultySettings();
// Enhanced Movement AI with intelligent positioning
if (currentTime >= this.nextMoveTime) {
var moveAction = Math.random();
if (moveAction < difficultySettings.moveFrequency) {
var optimalDistance = this.getOptimalDistance();
if (distance > optimalDistance + 50) {
// Move closer with smart pathfinding
var approachSpeed = difficultySettings.moveSpeed * this.getApproachMultiplier();
if (playerFighter.x > enemyFighter.x && enemyFighter.x < 1848) {
enemyFighter.x += approachSpeed;
} else if (playerFighter.x < enemyFighter.x && enemyFighter.x > 200) {
enemyFighter.x -= approachSpeed;
}
} else if (distance < optimalDistance - 50) {
// Maintain optimal distance with tactical retreats
var retreatChance = difficultySettings.retreatChance;
if (Math.random() < retreatChance) {
var retreatSpeed = difficultySettings.moveSpeed * 0.8;
if (playerFighter.x > enemyFighter.x && enemyFighter.x > 200) {
enemyFighter.x -= retreatSpeed;
} else if (playerFighter.x < enemyFighter.x && enemyFighter.x < 1848) {
enemyFighter.x += retreatSpeed;
}
}
} else {
// Optimal distance - intelligent repositioning based on strategy
var repositionChance = difficultySettings.repositionChance;
if (Math.random() < repositionChance) {
var tacticalMove = this.getTacticalMove();
if (enemyFighter.x + tacticalMove > 200 && enemyFighter.x + tacticalMove < 1848) {
enemyFighter.x += tacticalMove;
}
}
}
}
this.nextMoveTime = currentTime + difficultySettings.moveCooldown + Math.random() * 200;
}
// Advanced Dodge/Evasion AI with predictive movement
if (playerFighter.isAttacking && distance < 400) {
var dodgeChance = difficultySettings.dodgeChance;
// Increase dodge chance if player is predictable
if (this.consecutiveAttacks > 2) {
dodgeChance *= 1.5;
}
if (Math.random() < dodgeChance && currentTime >= this.nextMoveTime) {
var dodgeDirection = this.getPredictiveDodge();
if (enemyFighter.x + dodgeDirection > 200 && enemyFighter.x + dodgeDirection < 1848) {
enemyFighter.x += dodgeDirection;
this.nextMoveTime = currentTime + 150; // Quick cooldown after dodge
}
}
}
// Intelligent Combat AI with pattern recognition
if (currentTime < this.nextActionTime) {
return;
}
var combatDecision = this.makeCombatDecision(distance, currentTime);
if (combatDecision.action === 'attack') {
this.executeAttack(combatDecision.attackType, distance);
} else if (combatDecision.action === 'block') {
enemyFighter.block();
} else if (combatDecision.action === 'special') {
if (enemyFighter.specialAttack()) {
var specialDamage = enemyFighter.attackPower * (combatDecision.damageMultiplier || 2);
playerFighter.takeDamage(specialDamage);
}
}
// Dynamic cooldown based on AI intelligence and player behavior
var finalCooldown = this.calculateAdaptiveCooldown(currentTime, difficultySettings);
this.nextActionTime = currentTime + finalCooldown;
},
getDifficultySettings: function getDifficultySettings() {
var settings = {
easy: {
moveFrequency: 0.3,
moveSpeed: 20,
retreatChance: 0.2,
repositionChance: 0.1,
moveCooldown: 800,
dodgeChance: 0.15,
attackChance: 0.25,
blockChance: 0.4,
specialChance: 0.05,
reactionTime: 1000,
patternRecognition: 0.1
},
medium: {
moveFrequency: 0.5,
moveSpeed: 35,
retreatChance: 0.35,
repositionChance: 0.25,
moveCooldown: 600,
dodgeChance: 0.3,
attackChance: 0.4,
blockChance: 0.55,
specialChance: 0.15,
reactionTime: 700,
patternRecognition: 0.3
},
hard: {
moveFrequency: 0.7,
moveSpeed: 50,
retreatChance: 0.5,
repositionChance: 0.4,
moveCooldown: 400,
dodgeChance: 0.45,
attackChance: 0.55,
blockChance: 0.7,
specialChance: 0.25,
reactionTime: 400,
patternRecognition: 0.6
}
};
return settings[this.difficulty];
},
trackPlayerBehavior: function trackPlayerBehavior(currentTime) {
// Track player health changes
this.playerHealthHistory.push({
time: currentTime,
health: playerFighter.health,
stamina: playerFighter.stamina
});
if (this.playerHealthHistory.length > 10) {
this.playerHealthHistory.shift();
}
// Track player movement patterns
if (this.lastPlayerPosition !== playerFighter.x) {
this.playerMovementHistory.push({
time: currentTime,
position: playerFighter.x,
direction: playerFighter.x > this.lastPlayerPosition ? 'right' : 'left'
});
this.lastPlayerPosition = playerFighter.x;
}
if (this.playerMovementHistory.length > 8) {
this.playerMovementHistory.shift();
}
// Track consecutive attacks
if (playerFighter.isAttacking) {
this.consecutiveAttacks++;
} else if (currentTime - (playerFighter.lastAttackTime || 0) > 1000) {
this.consecutiveAttacks = 0;
}
},
updateAdaptiveStrategy: function updateAdaptiveStrategy(currentTime) {
if (currentTime < this.strategyTimer) return;
var difficultySettings = this.getDifficultySettings();
var healthPercentage = enemyFighter.health / enemyFighter.maxHealth;
var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina;
// Switch strategies based on situation and difficulty intelligence
if (difficultySettings.patternRecognition > Math.random()) {
if (healthPercentage < 0.3) {
this.adaptiveStrategy = 'defensive';
} else if (playerFighter.health < enemyFighter.health && staminaPercentage > 0.6) {
this.adaptiveStrategy = 'aggressive';
} else {
this.adaptiveStrategy = 'balanced';
}
}
this.strategyTimer = currentTime + 3000; // Re-evaluate every 3 seconds
},
getOptimalDistance: function getOptimalDistance() {
var baseDistance = 250;
switch (this.adaptiveStrategy) {
case 'aggressive':
return baseDistance - 50;
case 'defensive':
return baseDistance + 100;
default:
return baseDistance;
}
},
getApproachMultiplier: function getApproachMultiplier() {
var playerHealthPercentage = playerFighter.health / playerFighter.maxHealth;
var multiplier = 1.0;
// More aggressive approach when player is weak
if (playerHealthPercentage < 0.3) {
multiplier = 1.5;
} else if (playerHealthPercentage < 0.6) {
multiplier = 1.2;
}
return multiplier;
},
getTacticalMove: function getTacticalMove() {
var baseMove = Math.random() < 0.5 ? -30 : 30;
// Add tactical positioning based on player movement patterns
if (this.playerMovementHistory.length >= 3) {
var recentMoves = this.playerMovementHistory.slice(-3);
var rightMovements = recentMoves.filter(function (move) {
return move.direction === 'right';
}).length;
if (rightMovements >= 2) {
// Player moving right, position for intercept
baseMove = 40;
} else if (rightMovements === 0) {
// Player moving left, position for intercept
baseMove = -40;
}
}
return baseMove;
},
getPredictiveDodge: function getPredictiveDodge() {
var baseDodge = Math.random() < 0.5 ? -60 : 60;
// Predict player attack direction based on position
if (playerFighter.x > enemyFighter.x) {
// Player attacking from right, dodge left
baseDodge = -Math.abs(baseDodge);
} else {
// Player attacking from left, dodge right
baseDodge = Math.abs(baseDodge);
}
return baseDodge;
},
makeCombatDecision: function makeCombatDecision(distance, currentTime) {
var difficultySettings = this.getDifficultySettings();
var decision = {
action: 'wait'
};
// Enhanced decision making based on multiple factors
var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800;
var shouldBlock = playerAttackingRecently && Math.random() < difficultySettings.blockChance * 1.5;
var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina;
var action = Math.random();
if (distance < 350) {
if (shouldBlock && !enemyFighter.isBlocking) {
decision.action = 'block';
} else if (action < difficultySettings.attackChance && enemyFighter.canAttack && enemyFighter.stamina >= 25) {
decision.action = 'attack';
decision.attackType = this.chooseAttackType(distance, staminaPercentage);
} else if (action < difficultySettings.blockChance && !playerAttackingRecently) {
decision.action = 'block';
}
} else if (distance < 500 && enemyFighter.stamina >= 60 && Math.random() < difficultySettings.specialChance) {
decision.action = 'special';
decision.damageMultiplier = 1.5;
}
return decision;
},
chooseAttackType: function chooseAttackType(distance, staminaPercentage) {
var attackType = Math.random();
if (distance < 200 && attackType < 0.4) {
return 'punch';
} else if (distance < 300 && attackType < 0.7) {
return 'kick';
} else if (distance < 180 && attackType < 0.9) {
return 'grab';
} else if (staminaPercentage > 0.6 && Math.random() < 0.3) {
return 'special';
}
return 'punch';
},
executeAttack: function executeAttack(attackType, distance) {
switch (attackType) {
case 'punch':
if (enemyFighter.attack()) {
playerFighter.takeDamage(enemyFighter.attackPower);
}
break;
case 'kick':
if (enemyFighter.attack()) {
LK.setTimeout(function () {
// Kick delay effect
}, 400);
playerFighter.takeDamage(enemyFighter.attackPower * 2.0);
}
break;
case 'grab':
if (enemyFighter.attack()) {
playerFighter.takeDamage(enemyFighter.attackPower * 1.2);
// Intelligent grab positioning
var pullDistance = this.difficulty === 'hard' ? 40 : 30;
if (playerFighter.x > enemyFighter.x) {
playerFighter.x -= pullDistance;
} else {
playerFighter.x += pullDistance;
}
}
break;
case 'special':
if (enemyFighter.specialAttack()) {
playerFighter.takeDamage(enemyFighter.attackPower * 2);
}
break;
}
},
calculateAdaptiveCooldown: function calculateAdaptiveCooldown(currentTime, difficultySettings) {
var baseCooldown = difficultySettings.reactionTime;
var cooldownVariation = baseCooldown * 0.3;
// Reduce cooldown based on player aggression
var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800;
var playerAggressiveBonus = playerAttackingRecently ? 0.7 : 1.0;
// Increase cooldown if enemy is low on stamina
var staminaPenalty = enemyFighter.stamina < 30 ? 1.5 : 1.0;
// Strategy-based cooldown modification
var strategyMultiplier = 1.0;
switch (this.adaptiveStrategy) {
case 'aggressive':
strategyMultiplier = 0.8;
break;
case 'defensive':
strategyMultiplier = 1.2;
break;
}
var finalCooldown = baseCooldown * playerAggressiveBonus * staminaPenalty * strategyMultiplier + Math.random() * cooldownVariation;
return Math.max(finalCooldown, 100); // Minimum 100ms cooldown
}
};
function checkGameEnd() {
if (playerFighter.health <= 0) {
gameState = 'gameOver';
storage.lastScore = LK.getScore();
LK.showGameOver();
return true;
}
if (enemyFighter.health <= 0) {
gameState = 'victory';
LK.setScore(LK.getScore() + 100);
// Show victory screen
gameplayContainer.visible = false;
victoryContainer.visible = true;
enemyDefeatedText.setText(enemyNames[currentEnemyIndex] + ' DEFEATED!');
progressText.setText('Enemies Defeated: ' + (currentEnemyIndex + 1) + '/' + totalEnemies);
// Hide action buttons
moveUpButton.visible = false;
moveLeftButton.visible = false;
moveRightButton.visible = false;
moveDownButton.visible = false;
attackButton.visible = false;
kickButton.visible = false;
blockButton.visible = false;
return true;
}
if (timerMode === 'limited' && roundTimer <= 0) {
gameState = 'timeUp';
storage.lastScore = LK.getScore();
if (playerFighter.health > enemyFighter.health) {
LK.setScore(LK.getScore() + 50);
storage.lastScore = LK.getScore();
LK.showYouWin();
} else {
LK.showGameOver();
}
return true;
}
return false;
}
continueButton.down = function (x, y, obj) {
if (gameState === 'victory') {
currentEnemyIndex++;
if (currentEnemyIndex >= totalEnemies) {
// All enemies defeated
var finalText = new Text2('CHAMPION!', {
size: 100,
fill: 0xf39c12
});
finalText.anchor.set(0.5, 0.5);
finalText.x = 2048 / 2;
finalText.y = 1366;
game.addChild(finalText);
LK.setScore(LK.getScore() + 500);
storage.lastScore = LK.getScore();
LK.showYouWin();
return;
}
// Start next fight
victoryContainer.visible = false;
gameplayContainer.visible = true;
gameState = 'countdown';
battleCountdown = 3;
countdownActive = true;
// Reset and recreate both fighters to ensure proper character selection
gameplayContainer.removeChild(playerFighter);
gameplayContainer.removeChild(enemyFighter);
playerFighter = gameplayContainer.addChild(new Fighter(true));
playerFighter.x = 2048 / 2 - 300;
playerFighter.y = 1600;
enemyFighter = gameplayContainer.addChild(new Fighter(false));
enemyFighter.x = 2048 / 2 + 300;
enemyFighter.y = 1600;
if (timerMode === 'limited') {
roundTimer = 90;
} else {
roundTimer = -1;
}
}
};
stopButton.down = function (x, y, obj) {
if (gameState === 'victory') {
LK.setScore(LK.getScore() + 50);
storage.lastScore = LK.getScore();
LK.showYouWin();
}
};
LK.playMusic('battleMusic');
game.update = function () {
if (gameState === 'countdown') {
if (countdownActive) {
countdownText.visible = true;
countdownText.setText(battleCountdown.toString());
if (LK.ticks % 60 === 0) {
battleCountdown--;
if (battleCountdown <= 0) {
countdownActive = false;
countdownText.visible = false;
gameState = 'playing';
}
}
}
}
if (gameState === 'playing') {
// Show action buttons when game starts
moveUpButton.visible = true;
moveLeftButton.visible = true;
moveRightButton.visible = true;
moveDownButton.visible = true;
attackButton.visible = true;
kickButton.visible = true;
blockButton.visible = true;
if (timerMode === 'limited') {
if (LK.ticks % 60 === 0) {
roundTimer--;
timerText.setText(roundTimer.toString());
if (roundTimer <= 10) {
timerText.tint = 0xe74c3c;
}
}
} else {
timerText.setText('∞');
}
playerHealthBar.setValue(playerFighter.health);
enemyHealthBar.setValue(enemyFighter.health);
playerStaminaBar.setValue(playerFighter.stamina);
enemyStaminaBar.setValue(enemyFighter.stamina);
scoreText.setText('Score: ' + LK.getScore());
enemyAI.update();
// Update projectiles
for (var i = playerProjectiles.length - 1; i >= 0; i--) {
var projectile = playerProjectiles[i];
var deltaX = projectile.targetX - projectile.x;
var deltaY = (projectile.targetY || enemyFighter.y - 50) - projectile.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance < 50) {
// Hit enemy
var damage = selectedCharacter === 'shark' ? playerFighter.attackPower * 1.8 : playerFighter.attackPower * 2;
enemyFighter.takeDamage(damage);
projectile.destroy();
playerProjectiles.splice(i, 1);
} else if (distance > 800) {
// Out of range
projectile.destroy();
playerProjectiles.splice(i, 1);
} else {
// Move projectile
projectile.x += deltaX / distance * projectile.speed;
projectile.y += deltaY / distance * projectile.speed;
}
}
checkGameEnd();
}
};
Una arena al aire libre rodeada por muros altos con patrones geométricos azul oscuro. El suelo está cubierto de hierba púrpura que brilla tenuemente y tiene zonas con charcos de líquido azul resplandeciente que pueden reflejar efectos de ataques o provocar pequeñas explosiones visuales al contacto. Los árboles están dispuestos al fondo y tienen copas rojas con formas pixeladas, no interactúan con los personajes pero aportan un fondo vibrante. La iluminación es baja, con tonos neón que cambian ligeramente de intensidad durante el combate. El área de batalla es plana, con textura suave pero con efectos de distorsión en los bordes, como si el entorno estuviera parcialmente corrompido.. In-Game asset. 2d. High contrast. No shadows
Botón de golpe sin necesidad de que diga para que es, que sea un símbolo de un puño ardiente. In-Game asset. 2d. High contrast. No shadows
Símbolo de escudo pixelado con pixeles amarillos. In-Game asset. 2d. High contrast. No shadows
Toro furry fuerte sin camisa pixelado. In-Game asset. 2d. High contrast. No shadows
Lagarto furry fuerte sin camisa y con taparrabos, que en la cara lleve un cráneo de otro lagarto, que lleve colgantes y que sea pixeleado. In-Game asset. 2d. High contrast. No shadows
Tiburón furry fuerte sin camisa y con shorts, que en la cara lleve unas gafas de sol, que lleve colgantes y que sea pixeleado que se vea todo su cuerpo In-Game asset. 2d. High contrast. No shadows
Lobo blanco fuerte revelando sus pectorales pero usando una capa y un taparrabos, que se vea todo su cuerpo y pixelado. In-Game asset. 2d. High contrast. No shadows
Tigre furry fuerte con una marca de x en su pectoral y pixeleado y que se vea todo su cuerpo, con un taparrabos y una piernera con una daga In-Game asset. 2d. High contrast. No shadows
Barra de vida llamativa In-Game asset. 2d. High contrast. No shadows
Barra de energía llamativa. In-Game asset. 2d. High contrast. No shadows
Mordida, dientes de lobo cerrados. In-Game asset. 2d. High contrast. No shadows
Botón de líneas curvas en total 3 pixeleado. In-Game asset. 2d. High contrast. No shadows
Oso polar furry fuerte con bufanda y pantalones largos y sin camisa, pixeleado. In-Game asset. 2d. High contrast. No shadows
Aguila real furry fuerte cruzando los brazos sin camisa y gran pectoral con un taparrabos de hojas pixeleado todo el cuerpo. In-Game asset. 2d. High contrast. No shadows
Partículas al golpear pixeleado In-Game asset. 2d. High contrast. No shadows
Particula de escudo siendo golpeado pixeleado In-Game asset. 2d. High contrast. No shadows
Barra de vida vacia con un corazón roto In-Game asset. 2d. High contrast. No shadows
Barra de energia vacia In-Game asset. 2d. High contrast. No shadows
Una particular de rayo pixeleada. In-Game asset. 2d. High contrast. No shadows