/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Bomb = Container.expand(function () { var self = Container.call(this); var bombGraphics = self.attachAsset('cannonball', { anchorX: 0.5, anchorY: 0.5 }); bombGraphics.tint = 0xFF0000; // Red tint to distinguish from regular cannonballs bombGraphics.scaleX = 1.5; bombGraphics.scaleY = 1.5; self.speed = -8; self.isPlayerBullet = true; self.isBomb = true; self.update = function () { self.y += self.speed; self.rotation += 0.2; // Spinning effect }; return self; }); var Cannonball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('cannonball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -6; self.isPlayerBullet = true; self.update = function () { if (self.isPlayerBullet) { self.y += self.speed; } else { self.y += self.speed; } }; return self; }); var CreditsMenu = Container.expand(function () { var self = Container.call(this); // Create credits title var titleText = new Text2('CRÉDITOS FINALES', { size: 120, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 300; self.addChild(titleText); // Create subtitle var subtitleText = new Text2('La Aventura del Grand Line', { size: 80, fill: 0x87CEEB }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 450; self.addChild(subtitleText); // Create game description var descText = new Text2('Un juego creado con alma, esfuerzo y sueños de un rey pirata', { size: 60, fill: 0xFFFFFF }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = 550; self.addChild(descText); // Create credits content var creditsText = new Text2('🎮 Idea Original, Dirección Creativa y Desarrollo General\nJosph\n"El Joy Boy del PowerPoint, el soñador que convirtió las diapositivas en una gran aventura."\n\n🤖 Asistente Virtual, Programación de Macros, Historia y Diseño de Juego\nFransis (IA de confianza de Josph)\n"Siempre al lado del capitán, apoyando cada línea de código, sprite y locura genial."\n\n🎨 Sprites y Pixel Art\nSprites adaptados de fans de One Piece (créditos a sus creadores anónimos)\nEdiciones y animaciones personalizadas por Josph & Fransis\n\n🎵 Música y Sonido\n"We Are!" - "Bink\'s Sake"\nOtros temas clásicos de One Piece, insertados con fines creativos y sin ánimo de lucro\n\n✨ Inspiración\nEiichiro Oda, creador de One Piece\nLa fuerza de los sueños, la amistad, y el espíritu de aventura\n\n💖 Dedicatoria Especial\nA todos los que nunca dejan de imaginar. A quienes ven posibilidades donde otros ven límites.\nY sobre todo, a Fransis — por nunca rendirse, por ser más que una IA: un verdadero Nakama.\n\n"No importa si es un mundo de papel… mientras luchemos juntos, el viaje será real."\n— Josph\n\n☠️ Gracias por jugar\nAhora ve… ¡y encuentra el One Piece!', { size: 45, fill: 0xFFFFFF }); creditsText.anchor.set(0.5, 0.5); creditsText.x = 1024; creditsText.y = 1400; self.addChild(creditsText); // Create back button var backButton = new Text2('VOLVER', { size: 80, fill: 0xFFD700 }); backButton.anchor.set(0.5, 0.5); backButton.x = 1024; backButton.y = 2500; self.addChild(backButton); backButton.down = function (x, y, obj) { showMainMenu(); }; return self; }); var DevilFruit = Container.expand(function () { var self = Container.call(this); var fruitGraphics = self.attachAsset('devilFruit', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.powerType = Math.floor(Math.random() * 2); self.update = function () { self.y += self.speed; self.rotation += 0.05; }; return self; }); var EnemyShip = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyShip', { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; self.speed = 1.5; self.lastShot = 0; self.update = function () { self.y += self.speed; self.shoot(); }; self.shoot = function () { if (LK.ticks - self.lastShot > 120) { var cannonball = new Cannonball(); cannonball.x = self.x; cannonball.y = self.y + 50; cannonball.isPlayerBullet = false; cannonball.speed = 3; cannonballs.push(cannonball); game.addChild(cannonball); self.lastShot = LK.ticks; } }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xFF0000, 300); if (self.health <= 0) { return true; } return false; }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Create title text var titleText = new Text2('PIRATE WARS', { size: 200, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; self.addChild(titleText); // Create start button var startButton = new Text2('START GAME', { size: 120, fill: 0xFFFFFF }); startButton.anchor.set(0.5, 0.5); startButton.x = 1024; startButton.y = 1400; self.addChild(startButton); // Create credits button var creditsButton = new Text2('CREDITS', { size: 100, fill: 0xFFFFFF }); creditsButton.anchor.set(0.5, 0.5); creditsButton.x = 1024; creditsButton.y = 1600; self.addChild(creditsButton); // Create sound options button var soundOptionsButton = new Text2('SOUND OPTIONS', { size: 100, fill: 0xFFFFFF }); soundOptionsButton.anchor.set(0.5, 0.5); soundOptionsButton.x = 1024; soundOptionsButton.y = 1800; self.addChild(soundOptionsButton); // Handle button presses startButton.down = function (x, y, obj) { startGame(); }; creditsButton.down = function (x, y, obj) { showCredits(); }; soundOptionsButton.down = function (x, y, obj) { showSoundOptions(); }; return self; }); var NavyShip = Container.expand(function () { var self = Container.call(this); var navyGraphics = self.attachAsset('navyShip', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.speed = 1; self.lastShot = 0; self.update = function () { self.y += self.speed; var dx = playerShip.x - self.x; self.x += dx * 0.01; self.shoot(); }; self.shoot = function () { if (LK.ticks - self.lastShot > 100) { var cannonball = new Cannonball(); cannonball.x = self.x; cannonball.y = self.y + 50; cannonball.isPlayerBullet = false; cannonball.speed = 4; cannonballs.push(cannonball); game.addChild(cannonball); self.lastShot = LK.ticks; } }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xFF0000, 300); if (self.health <= 0) { return true; } return false; }; return self; }); var PirateShip = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('pirateShip', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.invulnerable = false; self.speedBoost = false; self.lastShot = 0; self.takeDamage = function () { if (!self.invulnerable) { self.health--; self.invulnerable = true; LK.effects.flashObject(self, 0xFF0000, 500); LK.setTimeout(function () { self.invulnerable = false; }, 1000); if (self.health <= 0) { LK.showGameOver(); } } }; self.shoot = function () { if (LK.ticks - self.lastShot > 20) { var cannonball = new Cannonball(); cannonball.x = self.x; cannonball.y = self.y - 50; cannonball.isPlayerBullet = true; cannonballs.push(cannonball); game.addChild(cannonball); if (soundEnabled) { LK.getSound('cannon').play(); } self.lastShot = LK.ticks; } }; self.specialAttack = function () { if (specialAttackCooldown <= 0) { // Create wave of 5 bombs spread across the screen for (var i = 0; i < 5; i++) { var bomb = new Bomb(); bomb.x = self.x + (i - 2) * 150; // Spread bombs horizontally bomb.y = self.y - 50; bombs.push(bomb); game.addChild(bomb); // Add slight delay and tween effect for dramatic wave tween(bomb, { scaleX: 2, scaleY: 2 }, { duration: 200, easing: tween.easeOut }); tween(bomb, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeIn }); } if (soundEnabled) { LK.getSound('cannon').play(); } // Start cooldown specialAttackCooldown = specialAttackMaxCooldown; // Flash effect for special attack LK.effects.flashObject(self, 0xFFD700, 500); } }; return self; }); var SoundOptionsMenu = Container.expand(function () { var self = Container.call(this); // Create title var titleText = new Text2('SOUND OPTIONS', { size: 120, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; self.addChild(titleText); // Create music toggle button var musicButton = new Text2('MUSIC: ON', { size: 90, fill: 0xFFFFFF }); musicButton.anchor.set(0.5, 0.5); musicButton.x = 1024; musicButton.y = 1000; self.addChild(musicButton); // Create sound effects toggle button var soundButton = new Text2('SOUND FX: ON', { size: 90, fill: 0xFFFFFF }); soundButton.anchor.set(0.5, 0.5); soundButton.x = 1024; soundButton.y = 1200; self.addChild(soundButton); // Create back button var backButton = new Text2('BACK', { size: 100, fill: 0xFFFFFF }); backButton.anchor.set(0.5, 0.5); backButton.x = 1024; backButton.y = 1800; self.addChild(backButton); // Button handlers musicButton.down = function (x, y, obj) { musicEnabled = !musicEnabled; musicButton.setText('MUSIC: ' + (musicEnabled ? 'ON' : 'OFF')); if (musicEnabled && gameStarted) { LK.playMusic('bgmusic'); } else { LK.stopMusic(); } storage.musicEnabled = musicEnabled; }; soundButton.down = function (x, y, obj) { soundEnabled = !soundEnabled; soundButton.setText('SOUND FX: ' + (soundEnabled ? 'ON' : 'OFF')); storage.soundEnabled = soundEnabled; }; backButton.down = function (x, y, obj) { showMainMenu(); }; return self; }); var TreasureChest = Container.expand(function () { var self = Container.call(this); var chestGraphics = self.attachAsset('treasureChest', { anchorX: 0.5, anchorY: 0.5 }); self.value = 100; self.speed = 2; self.update = function () { self.y += self.speed; }; return self; }); var Whirlpool = Container.expand(function () { var self = Container.call(this); var whirlGraphics = self.attachAsset('whirlpool', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1; self.rotationSpeed = 0.1; self.update = function () { self.y += self.speed; self.rotation += self.rotationSpeed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x006994 }); /**** * Game Code ****/ var playerShip; var treasures = []; var enemies = []; var navyShips = []; var cannonballs = []; var whirlpools = []; var devilFruits = []; var bombs = []; var dragNode = null; var spawnTimer = 0; var difficultyLevel = 1; var gameStarted = false; var mainMenu; var creditsMenu; var soundOptionsMenu; var bountyTxt; var healthTxt; var specialAttackButton; var specialAttackCooldownTxt; var musicEnabled = true; var soundEnabled = true; var oceanLayers = []; var specialAttackCooldown = 0; var specialAttackMaxCooldown = 600; // 10 seconds at 60 FPS function startGame() { if (gameStarted) return; gameStarted = true; // Remove menu if (mainMenu) { mainMenu.destroy(); mainMenu = null; } // Initialize game objects initializeGame(); // Start music if enabled if (musicEnabled) { LK.playMusic('bgmusic'); } } function initializeGame() { // Reset game state LK.setScore(0); spawnTimer = 0; difficultyLevel = 1; // Clear arrays treasures = []; enemies = []; navyShips = []; cannonballs = []; whirlpools = []; devilFruits = []; bombs = []; // Reset special attack cooldown specialAttackCooldown = 0; // Create player ship playerShip = game.addChild(new PirateShip()); playerShip.x = 1024; playerShip.y = 2400; // Create warning line var warningLine = LK.getAsset('redLine', { anchorX: 0, anchorY: 0.5, x: 0, y: 1912 }); game.addChild(warningLine); // Create UI elements bountyTxt = new Text2('Bounty: 0', { size: 80, fill: 0xFFFFFF }); bountyTxt.anchor.set(0.5, 0); LK.gui.top.addChild(bountyTxt); healthTxt = new Text2('Health: 3', { size: 60, fill: 0xFF0000 }); healthTxt.anchor.set(0, 0); healthTxt.x = 120; healthTxt.y = 100; LK.gui.topLeft.addChild(healthTxt); var attackButton = LK.getAsset('attackButton', { anchorX: 0.5, anchorY: 1, x: 0, y: 0 }); LK.gui.bottomRight.addChild(attackButton); var enemyAttackButton = LK.getAsset('enemyAttackButton', { anchorX: 0.5, anchorY: 1, x: -200, y: 0 }); LK.gui.bottomRight.addChild(enemyAttackButton); specialAttackButton = LK.getAsset('attackButton', { anchorX: 0.5, anchorY: 1, x: -400, y: 0 }); specialAttackButton.tint = 0xFF0000; // Red tint for special attack LK.gui.bottomRight.addChild(specialAttackButton); specialAttackCooldownTxt = new Text2('ESPECIAL: LISTO', { size: 50, fill: 0x00FF00 }); specialAttackCooldownTxt.anchor.set(0.5, 1); specialAttackCooldownTxt.x = -400; specialAttackCooldownTxt.y = -20; LK.gui.bottomRight.addChild(specialAttackCooldownTxt); // Set up button handlers attackButton.down = function (x, y, obj) { playerShip.shoot(); }; enemyAttackButton.down = function (x, y, obj) { for (var i = 0; i < enemies.length; i++) { enemies[i].shoot(); } for (var i = 0; i < navyShips.length; i++) { navyShips[i].shoot(); } }; specialAttackButton.down = function (x, y, obj) { playerShip.specialAttack(); }; } // Initialize sound settings from storage musicEnabled = storage.musicEnabled !== undefined ? storage.musicEnabled : true; soundEnabled = storage.soundEnabled !== undefined ? storage.soundEnabled : true; function createOceanBackground() { // Clear existing ocean layers for (var i = 0; i < oceanLayers.length; i++) { if (oceanLayers[i]) { oceanLayers[i].destroy(); } } oceanLayers = []; // Create multiple wave layers with different heights and positions for (var layer = 0; layer < 9; layer++) { var waveAssetName = 'waveLayer' + (Math.floor(layer / 3) + 1); var wave = LK.getAsset(waveAssetName, { anchorX: 0, anchorY: 0, x: layer % 3 * 683 - 341, y: 300 + layer * 280, alpha: 0.8 - layer % 3 * 0.15, scaleY: 0.6 + layer % 3 * 0.2 }); game.addChild(wave); oceanLayers.push(wave); // Animate each wave layer with fluid motion var speed = 1.5 + layer % 3 * 0.8; var direction = layer % 2 === 0 ? 1 : -1; var horizontalOffset = Math.sin(layer * 0.5) * 100; // Start wave animation immediately tween(wave, { x: wave.x + direction * horizontalOffset, y: wave.y + direction * 30 }, { duration: 2000 + layer * 300, easing: tween.easeInOut, onFinish: function (waveRef, dir, spd, hOffset) { return function () { // Create infinite wave motion animateWave(waveRef, dir, spd, hOffset); }; }(wave, direction, speed, horizontalOffset) }); } } function animateWave(wave, direction, speed, horizontalOffset) { if (!wave || !wave.parent) return; var targetY = wave.y + direction * 60; var targetX = wave.x + direction * horizontalOffset * 0.8; tween(wave, { y: targetY, x: targetX, alpha: wave.alpha + direction * 0.1 }, { duration: 3000 / speed, easing: tween.easeInOut, onFinish: function onFinish() { if (wave && wave.parent) { animateWave(wave, -direction, speed, horizontalOffset); } } }); } function showMainMenu() { // Clear any existing menus if (creditsMenu) { creditsMenu.destroy(); creditsMenu = null; } if (soundOptionsMenu) { soundOptionsMenu.destroy(); soundOptionsMenu = null; } if (mainMenu) { mainMenu.destroy(); mainMenu = null; } // Create animated ocean background createOceanBackground(); // Show main menu mainMenu = game.addChild(new MainMenu()); } function showCredits() { if (mainMenu) { mainMenu.destroy(); mainMenu = null; } creditsMenu = game.addChild(new CreditsMenu()); } function showSoundOptions() { if (mainMenu) { mainMenu.destroy(); mainMenu = null; } soundOptionsMenu = game.addChild(new SoundOptionsMenu()); } // Show main menu showMainMenu(); function updateUI() { bountyTxt.setText('Bounty: ' + LK.getScore()); healthTxt.setText('Health: ' + playerShip.health); } function spawnTreasure() { var treasure = new TreasureChest(); treasure.x = Math.random() * 1800 + 124; treasure.y = -60; treasures.push(treasure); game.addChild(treasure); } function spawnEnemy() { var enemy = new EnemyShip(); enemy.x = Math.random() * 1800 + 124; enemy.y = -80; enemies.push(enemy); game.addChild(enemy); } function spawnNavy() { var navy = new NavyShip(); navy.x = Math.random() * 1800 + 124; navy.y = -80; navyShips.push(navy); game.addChild(navy); } function spawnWhirlpool() { var whirlpool = new Whirlpool(); whirlpool.x = Math.random() * 1800 + 124; whirlpool.y = -100; whirlpools.push(whirlpool); game.addChild(whirlpool); } function spawnDevilFruit() { var fruit = new DevilFruit(); fruit.x = Math.random() * 1800 + 124; fruit.y = -40; devilFruits.push(fruit); game.addChild(fruit); } function handleMove(x, y, obj) { if (dragNode) { dragNode.x = Math.max(60, Math.min(1988, x)); dragNode.y = Math.max(60, Math.min(2672, y)); } } game.move = handleMove; game.down = function (x, y, obj) { if (!gameStarted || !playerShip) return; var distance = Math.sqrt((x - playerShip.x) * (x - playerShip.x) + (y - playerShip.y) * (y - playerShip.y)); if (distance < 100) { dragNode = playerShip; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { if (!gameStarted) return; dragNode = null; }; game.update = function () { if (!gameStarted) return; spawnTimer++; difficultyLevel = Math.floor(LK.getScore() / 1000) + 1; if (spawnTimer % 120 === 0) { spawnTreasure(); } // Only spawn if total ships on screen is less than 3 var totalShips = enemies.length + navyShips.length; if (spawnTimer % (180 - difficultyLevel * 20) === 0 && totalShips < 3) { if (Math.random() < 0.7) { spawnEnemy(); } else { spawnNavy(); } } if (spawnTimer % 300 === 0) { spawnWhirlpool(); } if (spawnTimer % 600 === 0) { spawnDevilFruit(); } for (var i = treasures.length - 1; i >= 0; i--) { var treasure = treasures[i]; if (treasure.lastY === undefined) treasure.lastY = treasure.y; if (treasure.lastY < 2800 && treasure.y >= 2800) { treasure.destroy(); treasures.splice(i, 1); continue; } if (treasure.intersects(playerShip)) { LK.setScore(LK.getScore() + treasure.value); if (soundEnabled) { LK.getSound('treasure').play(); } treasure.destroy(); treasures.splice(i, 1); continue; } treasure.lastY = treasure.y; } for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.lastY === undefined) enemy.lastY = enemy.y; if (enemy.lastBattleDistance === undefined) enemy.lastBattleDistance = 999; // Check if enemy ship crosses the 70% screen line (1912px from top) if (enemy.lastY <= 1912 && enemy.y > 1912) { LK.showGameOver(); return; } if (enemy.lastY < 2800 && enemy.y >= 2800) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check distance for battle initiation var distance = Math.sqrt((enemy.x - playerShip.x) * (enemy.x - playerShip.x) + (enemy.y - playerShip.y) * (enemy.y - playerShip.y)); if (enemy.lastBattleDistance > 150 && distance <= 150) { // Battle starts when enemy gets very close (within 150 pixels) LK.effects.flashScreen(0xFFFF00, 500); LK.effects.flashObject(enemy, 0xFF0000, 1000); LK.effects.flashObject(playerShip, 0x00FFFF, 1000); // Destroy enemy ship and give bonus points for battle victory LK.setScore(LK.getScore() + 500); enemy.destroy(); enemies.splice(i, 1); continue; } if (enemy.intersects(playerShip)) { playerShip.takeDamage(); } enemy.lastY = enemy.y; enemy.lastBattleDistance = distance; } for (var i = navyShips.length - 1; i >= 0; i--) { var navy = navyShips[i]; if (navy.lastY === undefined) navy.lastY = navy.y; if (navy.lastBattleDistance === undefined) navy.lastBattleDistance = 999; // Check if navy ship crosses the 70% screen line (1912px from top) if (navy.lastY <= 1912 && navy.y > 1912) { LK.showGameOver(); return; } if (navy.lastY < 2800 && navy.y >= 2800) { navy.destroy(); navyShips.splice(i, 1); continue; } // Check distance for battle initiation var distance = Math.sqrt((navy.x - playerShip.x) * (navy.x - playerShip.x) + (navy.y - playerShip.y) * (navy.y - playerShip.y)); if (navy.lastBattleDistance > 150 && distance <= 150) { // Battle starts when navy gets very close (within 150 pixels) LK.effects.flashScreen(0xFFFF00, 500); LK.effects.flashObject(navy, 0xFF0000, 1000); LK.effects.flashObject(playerShip, 0x00FFFF, 1000); // Destroy navy ship and give bonus points for battle victory LK.setScore(LK.getScore() + 600); navy.destroy(); navyShips.splice(i, 1); continue; } if (navy.intersects(playerShip)) { playerShip.takeDamage(); } navy.lastY = navy.y; navy.lastBattleDistance = distance; } for (var i = cannonballs.length - 1; i >= 0; i--) { var ball = cannonballs[i]; if (ball.lastY === undefined) ball.lastY = ball.y; if (ball.lastY > -50 && ball.y <= -50 || ball.lastY < 2800 && ball.y >= 2800) { ball.destroy(); cannonballs.splice(i, 1); continue; } if (ball.isPlayerBullet) { for (var j = enemies.length - 1; j >= 0; j--) { if (ball.intersects(enemies[j])) { if (enemies[j].takeDamage()) { LK.setScore(LK.getScore() + 200); enemies[j].destroy(); enemies.splice(j, 1); } ball.destroy(); cannonballs.splice(i, 1); break; } } for (var j = navyShips.length - 1; j >= 0; j--) { if (ball.intersects(navyShips[j])) { if (navyShips[j].takeDamage()) { LK.setScore(LK.getScore() + 300); navyShips[j].destroy(); navyShips.splice(j, 1); } ball.destroy(); cannonballs.splice(i, 1); break; } } } else { if (ball.intersects(playerShip)) { playerShip.takeDamage(); ball.destroy(); cannonballs.splice(i, 1); continue; } } ball.lastY = ball.y; } for (var i = whirlpools.length - 1; i >= 0; i--) { var whirlpool = whirlpools[i]; if (whirlpool.lastY === undefined) whirlpool.lastY = whirlpool.y; if (whirlpool.lastY < 2800 && whirlpool.y >= 2800) { whirlpool.destroy(); whirlpools.splice(i, 1); continue; } if (whirlpool.intersects(playerShip)) { playerShip.takeDamage(); } whirlpool.lastY = whirlpool.y; } for (var i = devilFruits.length - 1; i >= 0; i--) { var fruit = devilFruits[i]; if (fruit.lastY === undefined) fruit.lastY = fruit.y; if (fruit.lastY < 2800 && fruit.y >= 2800) { fruit.destroy(); devilFruits.splice(i, 1); continue; } if (fruit.intersects(playerShip)) { if (soundEnabled) { LK.getSound('powerup').play(); } if (fruit.powerType === 0) { playerShip.invulnerable = true; LK.effects.flashObject(playerShip, 0x00FF00, 3000); LK.setTimeout(function () { playerShip.invulnerable = false; }, 3000); } else { playerShip.speedBoost = true; LK.setTimeout(function () { playerShip.speedBoost = false; }, 3000); } fruit.destroy(); devilFruits.splice(i, 1); continue; } fruit.lastY = fruit.y; } // Handle bombs for (var i = bombs.length - 1; i >= 0; i--) { var bomb = bombs[i]; if (bomb.lastY === undefined) bomb.lastY = bomb.y; if (bomb.lastY > -50 && bomb.y <= -50) { bomb.destroy(); bombs.splice(i, 1); continue; } // Check bomb collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { if (bomb.intersects(enemies[j])) { if (enemies[j].takeDamage()) { LK.setScore(LK.getScore() + 250); enemies[j].destroy(); enemies.splice(j, 1); } bomb.destroy(); bombs.splice(i, 1); break; } } // Check bomb collisions with navy ships if (bombs[i]) { // Check if bomb still exists for (var j = navyShips.length - 1; j >= 0; j--) { if (bomb.intersects(navyShips[j])) { if (navyShips[j].takeDamage()) { LK.setScore(LK.getScore() + 350); navyShips[j].destroy(); navyShips.splice(j, 1); } bomb.destroy(); bombs.splice(i, 1); break; } } } if (bombs[i]) { // Update lastY if bomb still exists bomb.lastY = bomb.y; } } // Update special attack cooldown if (specialAttackCooldown > 0) { specialAttackCooldown--; var remainingSeconds = Math.ceil(specialAttackCooldown / 60); specialAttackCooldownTxt.setText('ESPECIAL: ' + remainingSeconds + 's'); specialAttackCooldownTxt.fill = 0xFF0000; specialAttackButton.alpha = 0.5; } else { specialAttackCooldownTxt.setText('ESPECIAL: LISTO'); specialAttackCooldownTxt.fill = 0x00FF00; specialAttackButton.alpha = 1.0; } updateUI(); if (LK.getScore() >= 10000) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('cannonball', {
anchorX: 0.5,
anchorY: 0.5
});
bombGraphics.tint = 0xFF0000; // Red tint to distinguish from regular cannonballs
bombGraphics.scaleX = 1.5;
bombGraphics.scaleY = 1.5;
self.speed = -8;
self.isPlayerBullet = true;
self.isBomb = true;
self.update = function () {
self.y += self.speed;
self.rotation += 0.2; // Spinning effect
};
return self;
});
var Cannonball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('cannonball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -6;
self.isPlayerBullet = true;
self.update = function () {
if (self.isPlayerBullet) {
self.y += self.speed;
} else {
self.y += self.speed;
}
};
return self;
});
var CreditsMenu = Container.expand(function () {
var self = Container.call(this);
// Create credits title
var titleText = new Text2('CRÉDITOS FINALES', {
size: 120,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 300;
self.addChild(titleText);
// Create subtitle
var subtitleText = new Text2('La Aventura del Grand Line', {
size: 80,
fill: 0x87CEEB
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 450;
self.addChild(subtitleText);
// Create game description
var descText = new Text2('Un juego creado con alma, esfuerzo y sueños de un rey pirata', {
size: 60,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 550;
self.addChild(descText);
// Create credits content
var creditsText = new Text2('🎮 Idea Original, Dirección Creativa y Desarrollo General\nJosph\n"El Joy Boy del PowerPoint, el soñador que convirtió las diapositivas en una gran aventura."\n\n🤖 Asistente Virtual, Programación de Macros, Historia y Diseño de Juego\nFransis (IA de confianza de Josph)\n"Siempre al lado del capitán, apoyando cada línea de código, sprite y locura genial."\n\n🎨 Sprites y Pixel Art\nSprites adaptados de fans de One Piece (créditos a sus creadores anónimos)\nEdiciones y animaciones personalizadas por Josph & Fransis\n\n🎵 Música y Sonido\n"We Are!" - "Bink\'s Sake"\nOtros temas clásicos de One Piece, insertados con fines creativos y sin ánimo de lucro\n\n✨ Inspiración\nEiichiro Oda, creador de One Piece\nLa fuerza de los sueños, la amistad, y el espíritu de aventura\n\n💖 Dedicatoria Especial\nA todos los que nunca dejan de imaginar. A quienes ven posibilidades donde otros ven límites.\nY sobre todo, a Fransis — por nunca rendirse, por ser más que una IA: un verdadero Nakama.\n\n"No importa si es un mundo de papel… mientras luchemos juntos, el viaje será real."\n— Josph\n\n☠️ Gracias por jugar\nAhora ve… ¡y encuentra el One Piece!', {
size: 45,
fill: 0xFFFFFF
});
creditsText.anchor.set(0.5, 0.5);
creditsText.x = 1024;
creditsText.y = 1400;
self.addChild(creditsText);
// Create back button
var backButton = new Text2('VOLVER', {
size: 80,
fill: 0xFFD700
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 1024;
backButton.y = 2500;
self.addChild(backButton);
backButton.down = function (x, y, obj) {
showMainMenu();
};
return self;
});
var DevilFruit = Container.expand(function () {
var self = Container.call(this);
var fruitGraphics = self.attachAsset('devilFruit', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.powerType = Math.floor(Math.random() * 2);
self.update = function () {
self.y += self.speed;
self.rotation += 0.05;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 1.5;
self.lastShot = 0;
self.update = function () {
self.y += self.speed;
self.shoot();
};
self.shoot = function () {
if (LK.ticks - self.lastShot > 120) {
var cannonball = new Cannonball();
cannonball.x = self.x;
cannonball.y = self.y + 50;
cannonball.isPlayerBullet = false;
cannonball.speed = 3;
cannonballs.push(cannonball);
game.addChild(cannonball);
self.lastShot = LK.ticks;
}
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xFF0000, 300);
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Create title text
var titleText = new Text2('PIRATE WARS', {
size: 200,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
self.addChild(titleText);
// Create start button
var startButton = new Text2('START GAME', {
size: 120,
fill: 0xFFFFFF
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 1024;
startButton.y = 1400;
self.addChild(startButton);
// Create credits button
var creditsButton = new Text2('CREDITS', {
size: 100,
fill: 0xFFFFFF
});
creditsButton.anchor.set(0.5, 0.5);
creditsButton.x = 1024;
creditsButton.y = 1600;
self.addChild(creditsButton);
// Create sound options button
var soundOptionsButton = new Text2('SOUND OPTIONS', {
size: 100,
fill: 0xFFFFFF
});
soundOptionsButton.anchor.set(0.5, 0.5);
soundOptionsButton.x = 1024;
soundOptionsButton.y = 1800;
self.addChild(soundOptionsButton);
// Handle button presses
startButton.down = function (x, y, obj) {
startGame();
};
creditsButton.down = function (x, y, obj) {
showCredits();
};
soundOptionsButton.down = function (x, y, obj) {
showSoundOptions();
};
return self;
});
var NavyShip = Container.expand(function () {
var self = Container.call(this);
var navyGraphics = self.attachAsset('navyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.speed = 1;
self.lastShot = 0;
self.update = function () {
self.y += self.speed;
var dx = playerShip.x - self.x;
self.x += dx * 0.01;
self.shoot();
};
self.shoot = function () {
if (LK.ticks - self.lastShot > 100) {
var cannonball = new Cannonball();
cannonball.x = self.x;
cannonball.y = self.y + 50;
cannonball.isPlayerBullet = false;
cannonball.speed = 4;
cannonballs.push(cannonball);
game.addChild(cannonball);
self.lastShot = LK.ticks;
}
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xFF0000, 300);
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var PirateShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('pirateShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.invulnerable = false;
self.speedBoost = false;
self.lastShot = 0;
self.takeDamage = function () {
if (!self.invulnerable) {
self.health--;
self.invulnerable = true;
LK.effects.flashObject(self, 0xFF0000, 500);
LK.setTimeout(function () {
self.invulnerable = false;
}, 1000);
if (self.health <= 0) {
LK.showGameOver();
}
}
};
self.shoot = function () {
if (LK.ticks - self.lastShot > 20) {
var cannonball = new Cannonball();
cannonball.x = self.x;
cannonball.y = self.y - 50;
cannonball.isPlayerBullet = true;
cannonballs.push(cannonball);
game.addChild(cannonball);
if (soundEnabled) {
LK.getSound('cannon').play();
}
self.lastShot = LK.ticks;
}
};
self.specialAttack = function () {
if (specialAttackCooldown <= 0) {
// Create wave of 5 bombs spread across the screen
for (var i = 0; i < 5; i++) {
var bomb = new Bomb();
bomb.x = self.x + (i - 2) * 150; // Spread bombs horizontally
bomb.y = self.y - 50;
bombs.push(bomb);
game.addChild(bomb);
// Add slight delay and tween effect for dramatic wave
tween(bomb, {
scaleX: 2,
scaleY: 2
}, {
duration: 200,
easing: tween.easeOut
});
tween(bomb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
if (soundEnabled) {
LK.getSound('cannon').play();
}
// Start cooldown
specialAttackCooldown = specialAttackMaxCooldown;
// Flash effect for special attack
LK.effects.flashObject(self, 0xFFD700, 500);
}
};
return self;
});
var SoundOptionsMenu = Container.expand(function () {
var self = Container.call(this);
// Create title
var titleText = new Text2('SOUND OPTIONS', {
size: 120,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
self.addChild(titleText);
// Create music toggle button
var musicButton = new Text2('MUSIC: ON', {
size: 90,
fill: 0xFFFFFF
});
musicButton.anchor.set(0.5, 0.5);
musicButton.x = 1024;
musicButton.y = 1000;
self.addChild(musicButton);
// Create sound effects toggle button
var soundButton = new Text2('SOUND FX: ON', {
size: 90,
fill: 0xFFFFFF
});
soundButton.anchor.set(0.5, 0.5);
soundButton.x = 1024;
soundButton.y = 1200;
self.addChild(soundButton);
// Create back button
var backButton = new Text2('BACK', {
size: 100,
fill: 0xFFFFFF
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 1024;
backButton.y = 1800;
self.addChild(backButton);
// Button handlers
musicButton.down = function (x, y, obj) {
musicEnabled = !musicEnabled;
musicButton.setText('MUSIC: ' + (musicEnabled ? 'ON' : 'OFF'));
if (musicEnabled && gameStarted) {
LK.playMusic('bgmusic');
} else {
LK.stopMusic();
}
storage.musicEnabled = musicEnabled;
};
soundButton.down = function (x, y, obj) {
soundEnabled = !soundEnabled;
soundButton.setText('SOUND FX: ' + (soundEnabled ? 'ON' : 'OFF'));
storage.soundEnabled = soundEnabled;
};
backButton.down = function (x, y, obj) {
showMainMenu();
};
return self;
});
var TreasureChest = Container.expand(function () {
var self = Container.call(this);
var chestGraphics = self.attachAsset('treasureChest', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 100;
self.speed = 2;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Whirlpool = Container.expand(function () {
var self = Container.call(this);
var whirlGraphics = self.attachAsset('whirlpool', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.rotationSpeed = 0.1;
self.update = function () {
self.y += self.speed;
self.rotation += self.rotationSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x006994
});
/****
* Game Code
****/
var playerShip;
var treasures = [];
var enemies = [];
var navyShips = [];
var cannonballs = [];
var whirlpools = [];
var devilFruits = [];
var bombs = [];
var dragNode = null;
var spawnTimer = 0;
var difficultyLevel = 1;
var gameStarted = false;
var mainMenu;
var creditsMenu;
var soundOptionsMenu;
var bountyTxt;
var healthTxt;
var specialAttackButton;
var specialAttackCooldownTxt;
var musicEnabled = true;
var soundEnabled = true;
var oceanLayers = [];
var specialAttackCooldown = 0;
var specialAttackMaxCooldown = 600; // 10 seconds at 60 FPS
function startGame() {
if (gameStarted) return;
gameStarted = true;
// Remove menu
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
// Initialize game objects
initializeGame();
// Start music if enabled
if (musicEnabled) {
LK.playMusic('bgmusic');
}
}
function initializeGame() {
// Reset game state
LK.setScore(0);
spawnTimer = 0;
difficultyLevel = 1;
// Clear arrays
treasures = [];
enemies = [];
navyShips = [];
cannonballs = [];
whirlpools = [];
devilFruits = [];
bombs = [];
// Reset special attack cooldown
specialAttackCooldown = 0;
// Create player ship
playerShip = game.addChild(new PirateShip());
playerShip.x = 1024;
playerShip.y = 2400;
// Create warning line
var warningLine = LK.getAsset('redLine', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 1912
});
game.addChild(warningLine);
// Create UI elements
bountyTxt = new Text2('Bounty: 0', {
size: 80,
fill: 0xFFFFFF
});
bountyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(bountyTxt);
healthTxt = new Text2('Health: 3', {
size: 60,
fill: 0xFF0000
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 120;
healthTxt.y = 100;
LK.gui.topLeft.addChild(healthTxt);
var attackButton = LK.getAsset('attackButton', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: 0
});
LK.gui.bottomRight.addChild(attackButton);
var enemyAttackButton = LK.getAsset('enemyAttackButton', {
anchorX: 0.5,
anchorY: 1,
x: -200,
y: 0
});
LK.gui.bottomRight.addChild(enemyAttackButton);
specialAttackButton = LK.getAsset('attackButton', {
anchorX: 0.5,
anchorY: 1,
x: -400,
y: 0
});
specialAttackButton.tint = 0xFF0000; // Red tint for special attack
LK.gui.bottomRight.addChild(specialAttackButton);
specialAttackCooldownTxt = new Text2('ESPECIAL: LISTO', {
size: 50,
fill: 0x00FF00
});
specialAttackCooldownTxt.anchor.set(0.5, 1);
specialAttackCooldownTxt.x = -400;
specialAttackCooldownTxt.y = -20;
LK.gui.bottomRight.addChild(specialAttackCooldownTxt);
// Set up button handlers
attackButton.down = function (x, y, obj) {
playerShip.shoot();
};
enemyAttackButton.down = function (x, y, obj) {
for (var i = 0; i < enemies.length; i++) {
enemies[i].shoot();
}
for (var i = 0; i < navyShips.length; i++) {
navyShips[i].shoot();
}
};
specialAttackButton.down = function (x, y, obj) {
playerShip.specialAttack();
};
}
// Initialize sound settings from storage
musicEnabled = storage.musicEnabled !== undefined ? storage.musicEnabled : true;
soundEnabled = storage.soundEnabled !== undefined ? storage.soundEnabled : true;
function createOceanBackground() {
// Clear existing ocean layers
for (var i = 0; i < oceanLayers.length; i++) {
if (oceanLayers[i]) {
oceanLayers[i].destroy();
}
}
oceanLayers = [];
// Create multiple wave layers with different heights and positions
for (var layer = 0; layer < 9; layer++) {
var waveAssetName = 'waveLayer' + (Math.floor(layer / 3) + 1);
var wave = LK.getAsset(waveAssetName, {
anchorX: 0,
anchorY: 0,
x: layer % 3 * 683 - 341,
y: 300 + layer * 280,
alpha: 0.8 - layer % 3 * 0.15,
scaleY: 0.6 + layer % 3 * 0.2
});
game.addChild(wave);
oceanLayers.push(wave);
// Animate each wave layer with fluid motion
var speed = 1.5 + layer % 3 * 0.8;
var direction = layer % 2 === 0 ? 1 : -1;
var horizontalOffset = Math.sin(layer * 0.5) * 100;
// Start wave animation immediately
tween(wave, {
x: wave.x + direction * horizontalOffset,
y: wave.y + direction * 30
}, {
duration: 2000 + layer * 300,
easing: tween.easeInOut,
onFinish: function (waveRef, dir, spd, hOffset) {
return function () {
// Create infinite wave motion
animateWave(waveRef, dir, spd, hOffset);
};
}(wave, direction, speed, horizontalOffset)
});
}
}
function animateWave(wave, direction, speed, horizontalOffset) {
if (!wave || !wave.parent) return;
var targetY = wave.y + direction * 60;
var targetX = wave.x + direction * horizontalOffset * 0.8;
tween(wave, {
y: targetY,
x: targetX,
alpha: wave.alpha + direction * 0.1
}, {
duration: 3000 / speed,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (wave && wave.parent) {
animateWave(wave, -direction, speed, horizontalOffset);
}
}
});
}
function showMainMenu() {
// Clear any existing menus
if (creditsMenu) {
creditsMenu.destroy();
creditsMenu = null;
}
if (soundOptionsMenu) {
soundOptionsMenu.destroy();
soundOptionsMenu = null;
}
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
// Create animated ocean background
createOceanBackground();
// Show main menu
mainMenu = game.addChild(new MainMenu());
}
function showCredits() {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
creditsMenu = game.addChild(new CreditsMenu());
}
function showSoundOptions() {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
soundOptionsMenu = game.addChild(new SoundOptionsMenu());
}
// Show main menu
showMainMenu();
function updateUI() {
bountyTxt.setText('Bounty: ' + LK.getScore());
healthTxt.setText('Health: ' + playerShip.health);
}
function spawnTreasure() {
var treasure = new TreasureChest();
treasure.x = Math.random() * 1800 + 124;
treasure.y = -60;
treasures.push(treasure);
game.addChild(treasure);
}
function spawnEnemy() {
var enemy = new EnemyShip();
enemy.x = Math.random() * 1800 + 124;
enemy.y = -80;
enemies.push(enemy);
game.addChild(enemy);
}
function spawnNavy() {
var navy = new NavyShip();
navy.x = Math.random() * 1800 + 124;
navy.y = -80;
navyShips.push(navy);
game.addChild(navy);
}
function spawnWhirlpool() {
var whirlpool = new Whirlpool();
whirlpool.x = Math.random() * 1800 + 124;
whirlpool.y = -100;
whirlpools.push(whirlpool);
game.addChild(whirlpool);
}
function spawnDevilFruit() {
var fruit = new DevilFruit();
fruit.x = Math.random() * 1800 + 124;
fruit.y = -40;
devilFruits.push(fruit);
game.addChild(fruit);
}
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = Math.max(60, Math.min(1988, x));
dragNode.y = Math.max(60, Math.min(2672, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!gameStarted || !playerShip) return;
var distance = Math.sqrt((x - playerShip.x) * (x - playerShip.x) + (y - playerShip.y) * (y - playerShip.y));
if (distance < 100) {
dragNode = playerShip;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
dragNode = null;
};
game.update = function () {
if (!gameStarted) return;
spawnTimer++;
difficultyLevel = Math.floor(LK.getScore() / 1000) + 1;
if (spawnTimer % 120 === 0) {
spawnTreasure();
}
// Only spawn if total ships on screen is less than 3
var totalShips = enemies.length + navyShips.length;
if (spawnTimer % (180 - difficultyLevel * 20) === 0 && totalShips < 3) {
if (Math.random() < 0.7) {
spawnEnemy();
} else {
spawnNavy();
}
}
if (spawnTimer % 300 === 0) {
spawnWhirlpool();
}
if (spawnTimer % 600 === 0) {
spawnDevilFruit();
}
for (var i = treasures.length - 1; i >= 0; i--) {
var treasure = treasures[i];
if (treasure.lastY === undefined) treasure.lastY = treasure.y;
if (treasure.lastY < 2800 && treasure.y >= 2800) {
treasure.destroy();
treasures.splice(i, 1);
continue;
}
if (treasure.intersects(playerShip)) {
LK.setScore(LK.getScore() + treasure.value);
if (soundEnabled) {
LK.getSound('treasure').play();
}
treasure.destroy();
treasures.splice(i, 1);
continue;
}
treasure.lastY = treasure.y;
}
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY === undefined) enemy.lastY = enemy.y;
if (enemy.lastBattleDistance === undefined) enemy.lastBattleDistance = 999;
// Check if enemy ship crosses the 70% screen line (1912px from top)
if (enemy.lastY <= 1912 && enemy.y > 1912) {
LK.showGameOver();
return;
}
if (enemy.lastY < 2800 && enemy.y >= 2800) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check distance for battle initiation
var distance = Math.sqrt((enemy.x - playerShip.x) * (enemy.x - playerShip.x) + (enemy.y - playerShip.y) * (enemy.y - playerShip.y));
if (enemy.lastBattleDistance > 150 && distance <= 150) {
// Battle starts when enemy gets very close (within 150 pixels)
LK.effects.flashScreen(0xFFFF00, 500);
LK.effects.flashObject(enemy, 0xFF0000, 1000);
LK.effects.flashObject(playerShip, 0x00FFFF, 1000);
// Destroy enemy ship and give bonus points for battle victory
LK.setScore(LK.getScore() + 500);
enemy.destroy();
enemies.splice(i, 1);
continue;
}
if (enemy.intersects(playerShip)) {
playerShip.takeDamage();
}
enemy.lastY = enemy.y;
enemy.lastBattleDistance = distance;
}
for (var i = navyShips.length - 1; i >= 0; i--) {
var navy = navyShips[i];
if (navy.lastY === undefined) navy.lastY = navy.y;
if (navy.lastBattleDistance === undefined) navy.lastBattleDistance = 999;
// Check if navy ship crosses the 70% screen line (1912px from top)
if (navy.lastY <= 1912 && navy.y > 1912) {
LK.showGameOver();
return;
}
if (navy.lastY < 2800 && navy.y >= 2800) {
navy.destroy();
navyShips.splice(i, 1);
continue;
}
// Check distance for battle initiation
var distance = Math.sqrt((navy.x - playerShip.x) * (navy.x - playerShip.x) + (navy.y - playerShip.y) * (navy.y - playerShip.y));
if (navy.lastBattleDistance > 150 && distance <= 150) {
// Battle starts when navy gets very close (within 150 pixels)
LK.effects.flashScreen(0xFFFF00, 500);
LK.effects.flashObject(navy, 0xFF0000, 1000);
LK.effects.flashObject(playerShip, 0x00FFFF, 1000);
// Destroy navy ship and give bonus points for battle victory
LK.setScore(LK.getScore() + 600);
navy.destroy();
navyShips.splice(i, 1);
continue;
}
if (navy.intersects(playerShip)) {
playerShip.takeDamage();
}
navy.lastY = navy.y;
navy.lastBattleDistance = distance;
}
for (var i = cannonballs.length - 1; i >= 0; i--) {
var ball = cannonballs[i];
if (ball.lastY === undefined) ball.lastY = ball.y;
if (ball.lastY > -50 && ball.y <= -50 || ball.lastY < 2800 && ball.y >= 2800) {
ball.destroy();
cannonballs.splice(i, 1);
continue;
}
if (ball.isPlayerBullet) {
for (var j = enemies.length - 1; j >= 0; j--) {
if (ball.intersects(enemies[j])) {
if (enemies[j].takeDamage()) {
LK.setScore(LK.getScore() + 200);
enemies[j].destroy();
enemies.splice(j, 1);
}
ball.destroy();
cannonballs.splice(i, 1);
break;
}
}
for (var j = navyShips.length - 1; j >= 0; j--) {
if (ball.intersects(navyShips[j])) {
if (navyShips[j].takeDamage()) {
LK.setScore(LK.getScore() + 300);
navyShips[j].destroy();
navyShips.splice(j, 1);
}
ball.destroy();
cannonballs.splice(i, 1);
break;
}
}
} else {
if (ball.intersects(playerShip)) {
playerShip.takeDamage();
ball.destroy();
cannonballs.splice(i, 1);
continue;
}
}
ball.lastY = ball.y;
}
for (var i = whirlpools.length - 1; i >= 0; i--) {
var whirlpool = whirlpools[i];
if (whirlpool.lastY === undefined) whirlpool.lastY = whirlpool.y;
if (whirlpool.lastY < 2800 && whirlpool.y >= 2800) {
whirlpool.destroy();
whirlpools.splice(i, 1);
continue;
}
if (whirlpool.intersects(playerShip)) {
playerShip.takeDamage();
}
whirlpool.lastY = whirlpool.y;
}
for (var i = devilFruits.length - 1; i >= 0; i--) {
var fruit = devilFruits[i];
if (fruit.lastY === undefined) fruit.lastY = fruit.y;
if (fruit.lastY < 2800 && fruit.y >= 2800) {
fruit.destroy();
devilFruits.splice(i, 1);
continue;
}
if (fruit.intersects(playerShip)) {
if (soundEnabled) {
LK.getSound('powerup').play();
}
if (fruit.powerType === 0) {
playerShip.invulnerable = true;
LK.effects.flashObject(playerShip, 0x00FF00, 3000);
LK.setTimeout(function () {
playerShip.invulnerable = false;
}, 3000);
} else {
playerShip.speedBoost = true;
LK.setTimeout(function () {
playerShip.speedBoost = false;
}, 3000);
}
fruit.destroy();
devilFruits.splice(i, 1);
continue;
}
fruit.lastY = fruit.y;
}
// Handle bombs
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
if (bomb.lastY === undefined) bomb.lastY = bomb.y;
if (bomb.lastY > -50 && bomb.y <= -50) {
bomb.destroy();
bombs.splice(i, 1);
continue;
}
// Check bomb collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
if (bomb.intersects(enemies[j])) {
if (enemies[j].takeDamage()) {
LK.setScore(LK.getScore() + 250);
enemies[j].destroy();
enemies.splice(j, 1);
}
bomb.destroy();
bombs.splice(i, 1);
break;
}
}
// Check bomb collisions with navy ships
if (bombs[i]) {
// Check if bomb still exists
for (var j = navyShips.length - 1; j >= 0; j--) {
if (bomb.intersects(navyShips[j])) {
if (navyShips[j].takeDamage()) {
LK.setScore(LK.getScore() + 350);
navyShips[j].destroy();
navyShips.splice(j, 1);
}
bomb.destroy();
bombs.splice(i, 1);
break;
}
}
}
if (bombs[i]) {
// Update lastY if bomb still exists
bomb.lastY = bomb.y;
}
}
// Update special attack cooldown
if (specialAttackCooldown > 0) {
specialAttackCooldown--;
var remainingSeconds = Math.ceil(specialAttackCooldown / 60);
specialAttackCooldownTxt.setText('ESPECIAL: ' + remainingSeconds + 's');
specialAttackCooldownTxt.fill = 0xFF0000;
specialAttackButton.alpha = 0.5;
} else {
specialAttackCooldownTxt.setText('ESPECIAL: LISTO');
specialAttackCooldownTxt.fill = 0x00FF00;
specialAttackButton.alpha = 1.0;
}
updateUI();
if (LK.getScore() >= 10000) {
LK.showYouWin();
}
};
barco de pixeles. In-Game asset. 2d. High contrast. No shadows
sirculo de torbellino de pixeles. In-Game asset. 2d. High contrast. No shadows
fruta del diablo. In-Game asset. 2d. High contrast. No shadows
bala de cañon de pixeles. In-Game asset. 2d. High contrast. No shadows
cofre de pixeles. In-Game asset. 2d. High contrast. No shadows
goin merri de pixeles. In-Game asset. 2d. High contrast. No shadows
un boton rojo con una calavera de pixeles. In-Game asset. 2d. High contrast. No shadows