/****
* 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