User prompt
In the Select Boss menu ??? If we press the button that says "When you close your eyes..." warning should appear
User prompt
In the Select Boss menu ??? If we press the button that says "When you close your eyes..." warning should appear
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'mainMenu.destroy();' Line Number: 5430
User prompt
Kalkan must send the Bananjohn attacks back towards Bananjohn. And when the Shield is active, the boss should not take damage and create new assets for the Boss and his attacks and add the Watermelon juice attack ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a new boss named Monster Watermelon II, This boss looks like a Monster Watermelon, but create a new asset for him, the attacks he can make in his first phase: 1- He takes out 3 large cores from his mouth, these cores can make three different attacks. They can follow Banajohn, they can move towards the walls and bounce from there, or they can be scattered in random places 2- He vomits watermelon juice from his mouth towards Bananjohn, THIS watermelon juice goes long and wide 3- He attacks dash backwards and takes out a watermelon slice in front of him 2. In Phase, these are more challenging, and in the second phase, it sometimes opens a shield that reflects Bananjohn's attacks back, and this shield lasts for 5 seconds, and when the shield is active, it becomes yellow. Both Phases have 600 health. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Fix the bug that Pineapple At shrinks after doing the dash attack. Also remove Watermelon Bananjohn and Pineapple Bananjohn skins from the skins section. And when fighting the Big Grape, a ghost of grapes comes from the bottom with an interval of 17 seconds, so make a new asset called ghost grapes
User prompt
Homing bullet should be usable on DJ Apple
User prompt
Make the health of the Big Grape 300 and weaken the way of attack, and while fighting it, ghost grapes should come from the bottom up and throw a bullet at the player and continue to go up.
User prompt
Cakes should be able to fall apart when they touch the lower walls and remove the attack that Annoying Grapes rotates around the player and make the way they move more unpredictable.
User prompt
Grapes should not surround the player, remove this attack
User prompt
Cakes should be able to fall apart when they touch the lower walls and remove the attack that Annoying Grapes rotates around the player and make the way they move more unpredictable.
User prompt
Make cake and cake pieces bigger and delete Annoying Grapes’ quotes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a new attack to the annoying grapes, they can throw a cake in this attack, it moves quickly and when it hits the wall, the pieces that are divided into three go in the opposite direction where the cake is thrown. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a new attack to the annoying grapes, they can throw a cake in this attack, it moves quickly and when it hits the wall, the pieces that are divided into three go in the opposite direction where the cake is thrown. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'bossSelectionScreen.destroy();' Line Number: 5027
User prompt
DJ Apple is too hard, make him more beatable.
User prompt
To prevent the music from mixing with each other, the 'Bj' music in the main menu should start playing directly without any delay.
User prompt
Sound waves must get larger and larger over time. In Phase 1, it can grow for a maximum of 2 seconds. 3 seconds in Phase 2 5 seconds in Phase 3 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add ‘DJ’ song to DJ Apple.
User prompt
Add ‘DJ’ song to DJ Apple.
User prompt
Big Notes’ dash should be more slower and predictable and they will dissapear after 2 dashes. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Big Notes’ dash mechanic is same as Pineapple Horse. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make a new attack minion called Big Notes, this minion is like normal Notes but much bigger and they dash towards the player. It is present in all 3 phases. Also Phase lives Phase 1: 300 Phase 2: 400 3. Phase: Change it to 500 and as with other bosses, we should only be able to see the current phase health.
User prompt
The musical notes should go very randomly to make the boss more difficult and confusing.
User prompt
Make DJ Apple’s first phase harder and make sound waves bigger.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Banana = Container.expand(function () {
var self = Container.call(this);
var skinAsset = selectedSkin === 'tuxedo' ? 'tuxedoBanana' : selectedSkin === 'clown' ? 'clownBanana' : selectedSkin === 'student' ? 'studentBanana' : selectedSkin === 'watermelon' ? 'watermelonBanana' : selectedSkin === 'pineapple' ? 'pineappleBanana' : 'banana';
var graphics = self.attachAsset(skinAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var gun = self.attachAsset('gun', {
anchorX: 0,
anchorY: 0.5
});
gun.x = 30;
gun.y = 0;
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootCooldown = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.potionEffectActive = false;
self.potionEffectTimer = 0;
self.potionEffectDuration = 300; // 5 seconds at 60fps
self.horseshoeInvincible = false;
self.horseshoeInvincibleTimer = 0;
self.horseshoeInvincibleDuration = 300; // 5 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invulnerable || self.horseshoeInvincible) return;
self.health -= damage;
self.invulnerable = true;
self.invulnerableTimer = 60; // 1 second at 60fps
// Flash effect
LK.effects.flashObject(self, 0xFF0000, 500);
LK.getSound('hit').play();
if (self.health <= 0) {
if (selectedMode === '2player') {
// In 2-player mode, hide dead player and remove barrier if one dies
self.alpha = 0; // Hide dead player
self.canShoot = false; // Prevent dead player from shooting
// Remove barrier when first player dies
var dividerElements = [];
for (var i = 0; i < game.children.length; i++) {
var child = game.children[i];
if (child.width === 2048 && child.height === 4) {
dividerElements.push(child);
}
}
for (var j = 0; j < dividerElements.length; j++) {
dividerElements[j].destroy();
}
// Check if both bananas are dead
var bothDead = false;
if (upperBanana && lowerBanana) {
bothDead = upperBanana.health <= 0 && lowerBanana.health <= 0;
}
if (bothDead) {
LK.showGameOver();
}
} else {
// Single player mode - end game immediately
LK.showGameOver();
}
}
};
self.activatePotionEffect = function () {
self.potionEffectActive = true;
self.potionEffectTimer = self.potionEffectDuration;
// Visual effect - purple tint
self.tint = 0xFF88FF;
// Flash effect
LK.effects.flashObject(self, 0x9932cc, 800);
};
self.activateHorseshoeInvincibility = function () {
self.horseshoeInvincible = true;
self.horseshoeInvincibleTimer = self.horseshoeInvincibleDuration;
// Visual effect - blue tint for invincibility
self.tint = 0x0080FF;
// Flash effect
LK.effects.flashObject(self, 0x0080FF, 1000);
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.invulnerable && self.invulnerableTimer > 0) {
self.invulnerableTimer--;
if (self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
}
// Handle potion effect
if (self.potionEffectActive) {
self.potionEffectTimer--;
if (self.potionEffectTimer <= 0) {
self.potionEffectActive = false;
// Remove visual effect only if not invincible from horseshoe
if (!self.horseshoeInvincible) {
self.tint = 0xFFFFFF;
} else {
// If still horseshoe invincible, set blue tint
self.tint = 0x0080FF;
}
}
}
// Handle horseshoe invincibility effect
if (self.horseshoeInvincible) {
self.horseshoeInvincibleTimer--;
if (self.horseshoeInvincibleTimer <= 0) {
self.horseshoeInvincible = false;
// Remove visual effect only if potion effect is not active
if (!self.potionEffectActive) {
self.tint = 0xFFFFFF;
} else {
// If still potion effect active, set purple tint
self.tint = 0xFF88FF;
}
}
} else if (self.potionEffectActive) {
// Maintain blue tint while horseshoe invincible, even if potion is active
self.tint = 0x0080FF;
}
};
return self;
});
var BananaProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bananaProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 5;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var BigNote = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('musicNote', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
// Much bigger than normal notes
scaleY: 3.0
});
self.speedX = 0;
self.speedY = 0;
self.damage = 20; // Higher damage than normal notes
self.dashSpeed = 5; // Slower dash speed towards player
self.isDashing = false;
self.target = null; // Target to dash towards
self.rotationSpeed = 0.1; // Slower rotation for predictability
self.dashCount = 0; // Track number of dashes performed
self.maxDashes = 2; // Maximum dashes before disappearing
self.originalPosition = {
x: 0,
y: 0
};
self.chargeTarget = {
x: 0,
y: 0
};
self.dashAttack = function () {
if (self.isDashing || !self.target || self.dashCount >= self.maxDashes) return;
self.isDashing = true;
self.dashCount++; // Increment dash counter
self.originalPosition.x = self.x;
self.originalPosition.y = self.y;
// Target player's current position for predictable behavior
self.chargeTarget.x = self.target.x;
self.chargeTarget.y = self.target.y;
// Phase 1: Preparation phase - pull back and flash warning
LK.effects.flashObject(self, 0xFFFF00, 1000);
// Calculate pullback position (opposite direction from target)
var pullbackDistance = 60; // Shorter pullback for slower feel
var dx = self.x - self.target.x;
var dy = self.y - self.target.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
var pullbackX = self.x + dx * pullbackDistance;
var pullbackY = self.y + dy * pullbackDistance;
// Clamp pullback position within screen bounds
pullbackX = Math.max(100, Math.min(1948, pullbackX));
pullbackY = Math.max(200, Math.min(2532, pullbackY));
// Phase 1: Pull back with anticipation - longer duration for predictability
tween(self, {
x: pullbackX,
y: pullbackY,
scaleX: 3.2,
scaleY: 3.2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
// Phase 2: Forward charge attack
LK.effects.flashObject(self, 0xFF4400, 500);
var chargeDuration = 400; // Slower charge for predictability
var chargeDistance = 80; // Shorter dash extension
// Calculate extended target position
var finalTargetX = self.chargeTarget.x;
var finalTargetY = self.chargeTarget.y;
var dx = self.chargeTarget.x - self.x;
var dy = self.chargeTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
finalTargetX = self.chargeTarget.x + dx * chargeDistance;
finalTargetY = self.chargeTarget.y + dy * chargeDistance;
}
// Clamp extended position within screen bounds
finalTargetX = Math.max(100, Math.min(1948, finalTargetX));
finalTargetY = Math.max(200, Math.min(2532, finalTargetY));
// Slower charge towards target position
tween(self, {
x: finalTargetX,
y: finalTargetY,
scaleX: 3.0,
scaleY: 3.0
}, {
duration: chargeDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Check if hit target during charge
if (self.target && self.intersects(self.target)) {
self.target.takeDamage(self.damage);
}
// Check if max dashes reached
if (self.dashCount >= self.maxDashes) {
// Disappear after 2 dashes
for (var i = djAppleProjectiles.length - 1; i >= 0; i--) {
if (djAppleProjectiles[i] === self) {
self.destroy();
djAppleProjectiles.splice(i, 1);
break;
}
}
} else {
// Return to original position if not at max dashes
tween(self, {
x: self.originalPosition.x,
y: self.originalPosition.y
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isDashing = false;
}
});
}
}
});
}
});
};
self.update = function () {
if (self.target && !self.isDashing && self.dashCount < self.maxDashes) {
// Start dashing towards target using the new dash attack method
self.dashAttack();
}
// Continue rotating while moving - slower for predictability
self.rotation += self.rotationSpeed;
};
return self;
});
var Bird = Container.expand(function (birdNumber) {
var self = Container.call(this);
var birdAssetName = 'bird' + Math.min(birdNumber, 10); // Use bird1-bird10 assets
var graphics = self.attachAsset(birdAssetName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0 + birdNumber * 0.05,
// Slightly less scaling since assets already vary in size
scaleY: 1.0 + birdNumber * 0.05
});
// No additional tinting needed since each bird asset has its own color
self.birdNumber = birdNumber;
self.maxHealth = 100;
self.health = self.maxHealth;
self.moveSpeed = 1.5 + birdNumber * 0.5; // Significantly faster birds
self.attackTimer = 0;
self.attackCooldown = 75 - birdNumber * 7; // Much more frequent attacks as birds progress
self.moveDirection = Math.random() * Math.PI * 2;
self.specialAttackCharge = 0;
self.specialAttackReady = false;
self.dashAttackCooldown = 0;
self.isDashing = false;
self.dashTarget = {
x: 0,
y: 0
};
self.dashSpeed = 8;
self.takeDamage = function (damage, isIce) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Handle ice bullet freeze effect
if (isIce) {
if (!self.iceHits) self.iceHits = 0;
self.iceHits++;
if (self.iceHits >= 2 + birdNumber && !self.frozen) {
self.frozen = true;
self.freezeTimer = 30 + birdNumber * 5; // Higher birds harder to freeze
self.originalTint = graphics.tint;
tween(graphics, {
tint: 0x87ceeb
}, {
duration: 100
});
self.iceHits = 0;
}
}
if (self.health <= 0) {
// Remove from birds array
for (var i = currentLevelBirds.length - 1; i >= 0; i--) {
if (currentLevelBirds[i] === self) {
currentLevelBirds.splice(i, 1);
break;
}
}
// Spawn next bird if any remain
if (remainingBirdsCount > 0) {
spawnNextBird();
}
self.destroy();
}
};
self.performDashAttack = function () {
if (self.birdNumber < 3 || self.isDashing || self.dashAttackCooldown > 0) return;
self.isDashing = true;
self.dashAttackCooldown = 240; // 4 seconds cooldown
self.dashTarget.x = banana.x;
self.dashTarget.y = banana.y;
// Flash warning effect
LK.effects.flashObject(self, 0xFFFF00, 300);
// Dash towards banana with high speed
var dx = self.dashTarget.x - self.x;
var dy = self.dashTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Use tween for smooth dash animation
tween(self, {
x: self.dashTarget.x,
y: self.dashTarget.y
}, {
duration: Math.min(800, distance / self.dashSpeed * 16.67),
// Variable duration based on distance
easing: tween.easeOut,
onFinish: function onFinish() {
self.isDashing = false;
// Knockback any banana hit during dash
if (self.intersects(banana)) {
banana.takeDamage(25 + self.birdNumber * 5);
}
}
});
};
self.performSpecialAttack = function () {
// Each bird has unique special attacks based on their number
if (self.birdNumber <= 3) {
// Early birds: Simple projectile barrage
var projectileCount = 2 + self.birdNumber;
for (var i = 0; i < projectileCount; i++) {
var projectile = new BirdWave();
projectile.x = self.x;
projectile.y = self.y;
var angle = Math.random() * Math.PI * 2;
var speed = 3 + Math.random() * 2;
projectile.speedX = Math.cos(angle) * speed;
projectile.speedY = Math.sin(angle) * speed;
projectile.damage = 8 + self.birdNumber * 2;
projectile.rotation = angle; // Rotate triangle to match direction
grapeProjectiles.push(projectile);
game.addChild(projectile);
}
} else if (self.birdNumber <= 6) {
// Mid birds: Homing projectiles
var projectileCount = 2;
for (var i = 0; i < projectileCount; i++) {
var projectile = new BirdWave();
projectile.x = self.x;
projectile.y = self.y;
var dx = banana.x - projectile.x;
var dy = banana.y - projectile.y;
var angle = Math.atan2(dy, dx) + (i - 0.5) * 0.5;
var speed = 4 + self.birdNumber * 0.5;
projectile.speedX = Math.cos(angle) * speed;
projectile.speedY = Math.sin(angle) * speed;
projectile.damage = 12 + self.birdNumber * 2;
projectile.rotation = angle; // Rotate triangle to match direction
grapeProjectiles.push(projectile);
game.addChild(projectile);
}
} else {
// Late birds: Screen-wide attacks
var projectileCount = 8 + (self.birdNumber - 6) * 2;
var angleStep = Math.PI * 2 / projectileCount;
for (var i = 0; i < projectileCount; i++) {
var projectile = new BirdWave();
projectile.x = self.x;
projectile.y = self.y;
var angle = i * angleStep;
var speed = 5 + (self.birdNumber - 6);
projectile.speedX = Math.cos(angle) * speed;
projectile.speedY = Math.sin(angle) * speed;
projectile.damage = 15 + (self.birdNumber - 6) * 3;
projectile.scaleX = 1.2 + (self.birdNumber - 6) * 0.2;
projectile.scaleY = 1.2 + (self.birdNumber - 6) * 0.2;
projectile.rotation = angle; // Rotate triangle to match direction
grapeProjectiles.push(projectile);
game.addChild(projectile);
}
}
self.specialAttackCharge = 0;
self.specialAttackReady = false;
};
self.update = function () {
// Handle freeze effect
if (self.frozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
tween(graphics, {
tint: self.originalTint
}, {
duration: 100
});
}
return; // Skip all actions while frozen
}
// Movement becomes more erratic for higher numbered birds
var effectiveMoveSpeed = self.moveSpeed;
if (selectedDifficulty === 'simple') {
effectiveMoveSpeed = self.moveSpeed * 0.7;
}
// Higher birds have more complex movement patterns
if (self.birdNumber <= 3) {
// Simple bouncing movement
self.x += Math.cos(self.moveDirection) * effectiveMoveSpeed;
self.y += Math.sin(self.moveDirection) * effectiveMoveSpeed;
} else if (self.birdNumber <= 6) {
// Figure-8 pattern mixed with random movement
self.x += Math.cos(self.moveDirection + Math.sin(LK.ticks * 0.05) * 2) * effectiveMoveSpeed;
self.y += Math.sin(self.moveDirection + Math.cos(LK.ticks * 0.03) * 1.5) * effectiveMoveSpeed;
} else {
// Highly erratic and unpredictable movement for final birds
var erraticFactor = (self.birdNumber - 6) * 0.3;
var speedMultiplier = 1 + (self.birdNumber - 6) * 0.2;
self.x += Math.cos(self.moveDirection + Math.sin(LK.ticks * (0.08 + erraticFactor)) * (3 + erraticFactor) + Math.random() * (0.5 + erraticFactor)) * effectiveMoveSpeed * speedMultiplier;
self.y += Math.sin(self.moveDirection + Math.cos(LK.ticks * (0.06 + erraticFactor)) * (2 + erraticFactor) + Math.random() * (0.3 + erraticFactor)) * effectiveMoveSpeed * speedMultiplier;
}
// Bounce off walls
if (self.x <= 50 || self.x >= 1998) {
self.moveDirection = Math.PI - self.moveDirection;
}
if (self.y <= 50 || self.y >= 2682) {
self.moveDirection = -self.moveDirection;
}
self.x = Math.max(50, Math.min(1998, self.x));
self.y = Math.max(50, Math.min(2682, self.y));
// Charge special attack
self.specialAttackCharge++;
if (self.specialAttackCharge >= 300 - self.birdNumber * 20) {
// Higher birds charge faster
self.specialAttackReady = true;
}
// Attack logic
self.attackTimer++;
var effectiveAttackCooldown = self.attackCooldown;
if (selectedDifficulty === 'simple') {
effectiveAttackCooldown = Math.floor(self.attackCooldown * 1.3);
}
if (self.attackTimer >= effectiveAttackCooldown) {
// Update dash attack cooldown
if (self.dashAttackCooldown > 0) {
self.dashAttackCooldown--;
}
// Check for dash attack (birds 3+ can dash)
if (self.birdNumber >= 3 && !self.isDashing && self.dashAttackCooldown <= 0 && Math.random() < 0.15) {
self.performDashAttack();
} else if (self.specialAttackReady && Math.random() < 0.3) {
// Use special attack
self.performSpecialAttack();
} else {
// Triangle wave attack towards banana
if (banana) {
var dx = banana.x - self.x;
var dy = banana.y - self.y;
var baseAngle = Math.atan2(dy, dx);
var speed = 3 + self.birdNumber * 0.4; // Faster and more difficult
var waveCount = 3; // Create triangle wave pattern
var spreadAngle = Math.PI / 4; // 45 degrees spread
for (var w = 0; w < waveCount; w++) {
var angleOffset = (w - 1) * (spreadAngle / 2); // -22.5, 0, 22.5 degrees
var finalAngle = baseAngle + angleOffset;
var projectile = new BirdWave();
projectile.x = self.x;
projectile.y = self.y;
projectile.speedX = Math.cos(finalAngle) * speed;
projectile.speedY = Math.sin(finalAngle) * speed;
projectile.damage = 6 + self.birdNumber * 2; // Slightly less per projectile but more total damage
// Scale for triangle wave effect
projectile.scaleX = 0.8;
projectile.scaleY = 1.3;
projectile.rotation = finalAngle; // Rotate triangle to match direction
grapeProjectiles.push(projectile);
game.addChild(projectile);
}
}
}
self.attackTimer = 0;
}
};
return self;
});
var BirdWave = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('triangleWave', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 10;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var BouncyProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bouncyProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 8; // Horizontal speed
self.speedY = 0; // Vertical speed
self.damage = 2;
self.enhanced = false;
self.bounces = 0; // Track number of bounces
self.maxBounces = 3; // Maximum bounces before disappearing
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Check wall bounces
if (self.x <= 25 || self.x >= 2023) {
self.speedX *= -1; // Reverse horizontal direction
self.bounces++;
if (self.bounces >= self.maxBounces) {
// Find and remove from bananaProjectiles array
for (var i = bananaProjectiles.length - 1; i >= 0; i--) {
if (bananaProjectiles[i] === self) {
self.destroy();
bananaProjectiles.splice(i, 1);
break;
}
}
}
}
if (self.y <= 25 || self.y >= 2707) {
self.speedY *= -1; // Reverse vertical direction
self.bounces++;
if (self.bounces >= self.maxBounces) {
// Find and remove from bananaProjectiles array
for (var i = bananaProjectiles.length - 1; i >= 0; i--) {
if (bananaProjectiles[i] === self) {
self.destroy();
bananaProjectiles.splice(i, 1);
break;
}
}
}
}
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
var graphics = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5 + Math.random() * 1.5; // Random speed between 0.5 and 2
self.update = function () {
self.x -= self.speed;
// Reset cloud position when it goes off screen
if (self.x < -200) {
self.x = 2248; // Reset to right side of screen
self.y = Math.random() * 1000 + 200; // Random height
}
};
return self;
});
var DJAppleBoss = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('DjApple', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// DJ Apple specific properties
self.phase = 1;
self.maxHealth = 300;
self.health = self.maxHealth;
self.totalMaxHealth = 1200; // Total across all phases (300+400+500)
self.attackTimer = 0;
self.attackCooldown = 80; // 1.33 seconds base cooldown (faster Phase 1)
self.moveDirection = 1;
self.moveSpeed = 1.5;
self.discoBallAttackTimer = 0;
self.speakerSpawnTimer = 0;
self.speakers = []; // Track spawned speakers
self.backgroundLights = 0x4444FF; // Start with blue/pink lights
self.takeDamage = function (damage, isIce) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Handle ice bullet freeze effect
if (isIce) {
if (!self.iceHits) self.iceHits = 0;
self.iceHits++;
var iceThreshold = 4 + self.phase * 2; // Harder to freeze in later phases
if (self.iceHits >= iceThreshold && !self.frozen) {
self.frozen = true;
self.freezeTimer = 45; // 0.75 seconds
self.originalTint = self.graphics.tint;
tween(self.graphics, {
tint: 0x87ceeb
}, {
duration: 100
});
self.iceHits = 0;
}
}
// Phase transitions
if (self.health <= 0 && self.phase < 3) {
self.nextPhase();
} else if (self.health <= 0 && self.phase === 3) {
self.defeat();
}
};
self.nextPhase = function () {
self.phase++;
if (self.phase === 2) {
self.maxHealth = 400;
self.health = 400;
} else if (self.phase === 3) {
self.maxHealth = 500;
self.health = 500;
}
// Update visual appearance for new phase
self.removeChild(self.graphics);
if (self.phase === 2) {
self.graphics = self.attachAsset('djApplePhase2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.6,
scaleY: 1.6
});
self.attackCooldown = 90; // Faster attacks
self.moveSpeed = 2.0; // Faster movement
self.backgroundLights = 0x9932CC; // Purple/green lights
} else if (self.phase === 3) {
self.graphics = self.attachAsset('djApplePhase3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8
});
self.attackCooldown = 60; // Even faster attacks
self.moveSpeed = 2.5; // Fastest movement
self.backgroundLights = 0xFF0000; // Red/black lights
}
// Phase transition effects
LK.effects.flashScreen(self.backgroundLights, 1500);
tween(self, {
scaleX: 1.3,
scaleY: 1.3,
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.rotation = 0;
self.scaleX = 1.0;
self.scaleY = 1.0;
}
});
};
self.defeat = function () {
// Final defeat animation
LK.stopMusic();
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
};
// Phase 1 attacks - Warm-Up
self.musicNoteAttack = function () {
var numNotes = self.phase === 1 ? 5 : self.phase === 2 ? 6 : 10;
var speed = self.phase === 1 ? 3.5 : self.phase === 2 ? 4 : 6;
for (var i = 0; i < numNotes; i++) {
var note = new MusicNote();
note.x = self.x;
note.y = self.y;
// Make notes go in completely random directions instead of organized circular pattern
var angle = Math.random() * Math.PI * 2;
// Add some speed variation for even more randomness
var randomSpeed = speed + (Math.random() - 0.5) * speed * 0.4; // ±20% speed variation
note.speedX = Math.cos(angle) * randomSpeed;
note.speedY = Math.sin(angle) * randomSpeed;
note.damage = 8 + self.phase * 2;
djAppleProjectiles.push(note);
game.addChild(note);
}
};
self.soundWaveAttack = function () {
var wave = new SoundWave();
wave.x = self.x;
wave.y = self.y;
var dx = banana.x - self.x;
var dy = banana.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
var speed = self.phase === 1 ? 4.5 : self.phase === 2 ? 4 : 5;
wave.speedX = dx * speed;
wave.speedY = dy * speed;
wave.damage = 12 + self.phase * 3;
// Make sound waves much bigger in all phases
if (self.phase === 1) {
wave.scaleX = 2.5;
wave.scaleY = 2.5;
} else if (self.phase >= 2) {
wave.scaleX = 1.5;
wave.scaleY = 1.5;
}
if (self.phase === 3) {
wave.scaleX = 2.0;
wave.scaleY = 2.0;
}
djAppleProjectiles.push(wave);
game.addChild(wave);
};
// Phase 2+ attacks
self.vinylDiscAttack = function () {
if (self.phase < 2) return;
var numDiscs = self.phase === 2 ? 2 : 4;
for (var i = 0; i < numDiscs; i++) {
var disc = new VinylDisc();
disc.x = self.x;
disc.y = self.y;
var angle = Math.random() * Math.PI * 2;
var speed = 4 + Math.random() * 2;
disc.speedX = Math.cos(angle) * speed;
disc.speedY = Math.sin(angle) * speed;
disc.damage = 15 + self.phase * 2;
disc.rotation = angle;
djAppleProjectiles.push(disc);
game.addChild(disc);
}
};
self.spawnSpeaker = function () {
if (self.phase < 2 || self.speakers.length >= 3) return;
var speaker = new SpeakerMinion();
speaker.x = 1800 + Math.random() * 200;
speaker.y = 400 + Math.random() * 1600;
self.speakers.push(speaker);
game.addChild(speaker);
};
// Phase 3 attacks
self.discoBallAttack = function () {
if (self.phase < 3) return;
var discoBall = new DiscoBall();
discoBall.x = self.x;
discoBall.y = self.y;
var dx = banana.x - self.x;
var dy = banana.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
discoBall.speedX = dx * 2; // Slow but deadly
discoBall.speedY = dy * 2;
discoBall.damage = 50; // High damage
djAppleProjectiles.push(discoBall);
game.addChild(discoBall);
};
self.bulletHellAttack = function () {
if (self.phase < 3) return;
var numNotes = 20;
for (var i = 0; i < numNotes; i++) {
var note = new MusicNote();
note.x = self.x;
note.y = self.y;
// Multi-directional spray
var baseAngle = Math.atan2(banana.y - self.y, banana.x - self.x);
var spread = Math.PI / 3; // 60 degrees spread
var angle = baseAngle + (Math.random() - 0.5) * spread;
var speed = 6 + Math.random() * 4;
note.speedX = Math.cos(angle) * speed;
note.speedY = Math.sin(angle) * speed;
note.damage = 12;
djAppleProjectiles.push(note);
game.addChild(note);
}
};
self.bigNotesAttack = function () {
// Spawn Big Notes that dash towards player
var numBigNotes = self.phase === 1 ? 2 : self.phase === 2 ? 3 : 4;
for (var i = 0; i < numBigNotes; i++) {
var bigNote = new BigNote();
// Spawn from random positions around the boss
var spawnRadius = 200;
var spawnAngle = Math.random() * Math.PI * 2;
bigNote.x = self.x + Math.cos(spawnAngle) * spawnRadius;
bigNote.y = self.y + Math.sin(spawnAngle) * spawnRadius;
// Set target to banana for dashing behavior
bigNote.target = banana;
bigNote.damage = 20 + self.phase * 5;
djAppleProjectiles.push(bigNote);
game.addChild(bigNote);
}
};
self.powerSoundBlast = function () {
if (self.phase < 3) return;
// Wide area blast
var numWaves = 8;
for (var i = 0; i < numWaves; i++) {
var wave = new SoundWave();
wave.x = self.x;
wave.y = self.y;
var angle = i / numWaves * Math.PI * 2;
wave.speedX = Math.cos(angle) * 3;
wave.speedY = Math.sin(angle) * 3;
wave.damage = 25;
wave.scaleX = 2.5;
wave.scaleY = 2.5;
djAppleProjectiles.push(wave);
game.addChild(wave);
}
};
self.update = function () {
// Handle freeze effect
if (self.frozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
tween(self.graphics, {
tint: self.originalTint
}, {
duration: 100
});
}
return; // Skip all actions while frozen
}
// Movement pattern - figure-8 with turntable spinning effect
var effectiveMoveSpeed = self.moveSpeed;
if (selectedDifficulty === 'simple') {
effectiveMoveSpeed = self.moveSpeed * 0.7;
}
// Complex movement pattern
self.y += self.moveDirection * effectiveMoveSpeed;
self.x += Math.sin(LK.ticks * 0.03) * (effectiveMoveSpeed * 0.8);
// Bounce off boundaries
if (self.y <= 300 || self.y >= 2400) {
self.moveDirection *= -1;
}
if (self.x <= 200 || self.x >= 1848) {
// Add slight direction change when hitting walls
self.moveDirection += (Math.random() - 0.5) * 0.3;
}
// Turntable spinning visual effect
self.graphics.rotation += 0.02 * self.phase; // Spin faster in later phases
// Attack logic
self.attackTimer++;
var effectiveAttackCooldown = self.attackCooldown;
if (selectedDifficulty === 'simple') {
effectiveAttackCooldown = Math.floor(self.attackCooldown * 1.4);
}
if (self.attackTimer >= effectiveAttackCooldown) {
var attackChoice = Math.random();
if (self.phase === 1) {
// Phase 1: Warm-up attacks
if (attackChoice < 0.5) {
self.musicNoteAttack();
} else if (attackChoice < 0.7) {
self.bigNotesAttack();
} else {
self.soundWaveAttack();
}
} else if (self.phase === 2) {
// Phase 2: Remix mode
if (attackChoice < 0.25) {
self.musicNoteAttack();
} else if (attackChoice < 0.4) {
self.bigNotesAttack();
} else if (attackChoice < 0.55) {
self.soundWaveAttack();
} else if (attackChoice < 0.75) {
self.vinylDiscAttack();
} else {
self.spawnSpeaker();
}
} else {
// Phase 3: Final Drop
if (attackChoice < 0.15) {
self.discoBallAttack();
} else if (attackChoice < 0.3) {
self.bigNotesAttack();
} else if (attackChoice < 0.55) {
self.bulletHellAttack();
} else if (attackChoice < 0.7) {
self.powerSoundBlast();
} else {
self.vinylDiscAttack();
}
}
self.attackTimer = 0;
}
// Clean up destroyed speakers
for (var i = self.speakers.length - 1; i >= 0; i--) {
if (!self.speakers[i] || self.speakers[i].health <= 0) {
self.speakers.splice(i, 1);
}
}
};
return self;
});
var DiscoBall = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('discoBall', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 50;
self.sparkleTimer = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Slow rotation and sparkle effects
self.rotation += 0.05;
self.sparkleTimer++;
if (self.sparkleTimer % 10 === 0) {
// Flash effect every 10 frames
var flashTint = Math.random() > 0.5 ? 0xFFFFFF : 0xFFD700;
graphics.tint = flashTint;
LK.setTimeout(function () {
graphics.tint = 0xFFFFFF;
}, 100);
}
};
return self;
});
var Grape = Container.expand(function (grapeNumber) {
var self = Container.call(this);
var grapeAssetName = 'grape' + (grapeNumber || 1);
var graphics = self.attachAsset(grapeAssetName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.grapeNumber = grapeNumber || 1;
self.maxHealth = 100; // 5 grapes * 100 = 500 total health
self.health = self.maxHealth;
self.moveSpeed = 2 + Math.random() * 2; // Random speed between 2-4
self.moveDirection = Math.random() * Math.PI * 2; // Random initial direction
self.attackTimer = 0;
self.attackCooldown = 120 + Math.random() * 60; // 2-3 seconds
self.bounceOffWalls = true;
self.formationMode = false;
self.formationTarget = {
x: 0,
y: 0
};
self.coverMode = false;
self.coverTarget = null;
self.takeDamage = function (damage, isIce) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Handle ice bullet freeze effect
if (isIce) {
if (!self.iceHits) self.iceHits = 0;
self.iceHits++;
if (self.iceHits >= 3 && !self.frozen) {
// Easier to freeze individual grapes
self.frozen = true;
self.freezeTimer = 60; // 1 second at 60fps
self.originalTint = self.graphics ? self.graphics.tint : 0xFFFFFF;
tween(graphics, {
tint: 0x87ceeb
}, {
duration: 100
});
self.iceHits = 0;
}
}
if (self.health <= 0) {
// Remove from grapes array
for (var i = grapes.length - 1; i >= 0; i--) {
if (grapes[i] === self) {
grapes.splice(i, 1);
break;
}
}
self.destroy();
}
};
self.bounceOffWall = function () {
// Bounce off screen edges
if (self.x <= 50 || self.x >= 1998) {
self.moveDirection = Math.PI - self.moveDirection;
}
if (self.y <= 50 || self.y >= 2682) {
self.moveDirection = -self.moveDirection;
}
// Keep within bounds
self.x = Math.max(50, Math.min(1998, self.x));
self.y = Math.max(50, Math.min(2682, self.y));
};
self.moveToFormation = function (targetX, targetY) {
self.formationMode = true;
self.formationTarget.x = targetX;
self.formationTarget.y = targetY;
};
self.startCoverMode = function (target) {
self.coverMode = true;
self.coverTarget = target;
};
self.update = function () {
// Handle freeze effect
if (self.frozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
tween(graphics, {
tint: self.originalTint
}, {
duration: 100
});
}
return; // Skip all actions while frozen
}
// Collision avoidance with other grapes
for (var i = 0; i < grapes.length; i++) {
var otherGrape = grapes[i];
if (otherGrape === self) continue;
var dx = self.x - otherGrape.x;
var dy = self.y - otherGrape.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = 120; // Minimum distance between grapes
if (distance < minDistance && distance > 0) {
// Push away from other grape
var pushStrength = (minDistance - distance) * 0.1;
var pushX = dx / distance * pushStrength;
var pushY = dy / distance * pushStrength;
self.x += pushX;
self.y += pushY;
}
}
// Movement behavior
if (self.formationMode) {
// Move towards formation position
var dx = self.formationTarget.x - self.x;
var dy = self.formationTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
var speed = Math.min(self.moveSpeed * 2, distance * 0.1);
self.x += dx / distance * speed;
self.y += dy / distance * speed;
} else {
self.formationMode = false;
}
} else if (self.coverMode && self.coverTarget) {
// Move to cover/surround the target
var dx = self.coverTarget.x - self.x;
var dy = self.coverTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var idealDistance = 150 + self.grapeNumber * 30; // Different distances for each grape
if (distance > idealDistance + 20) {
// Move closer
var speed = self.moveSpeed * 1.5;
self.x += dx / distance * speed;
self.y += dy / distance * speed;
} else if (distance < idealDistance - 20) {
// Move away
var speed = self.moveSpeed;
self.x -= dx / distance * speed;
self.y -= dy / distance * speed;
} else {
// Orbit around target
var angle = Math.atan2(dy, dx) + self.grapeNumber * 0.02;
self.x = self.coverTarget.x + Math.cos(angle) * idealDistance;
self.y = self.coverTarget.y + Math.sin(angle) * idealDistance;
}
} else {
// Normal bouncing movement
var effectiveMoveSpeed = self.moveSpeed;
if (selectedDifficulty === 'simple') {
effectiveMoveSpeed = self.moveSpeed * 0.7;
}
self.x += Math.cos(self.moveDirection) * effectiveMoveSpeed;
self.y += Math.sin(self.moveDirection) * effectiveMoveSpeed;
self.bounceOffWall();
}
// Speech bubble system - show angry quotes every 10 seconds
if (!self.speechBubble && LK.ticks % 600 === 0) {
// Every 10 seconds (600 ticks at 60fps)
self.showSpeechBubble();
}
// Attack logic
self.attackTimer++;
var effectiveAttackCooldown = self.attackCooldown;
if (selectedDifficulty === 'simple') {
effectiveAttackCooldown = Math.floor(self.attackCooldown * 1.5);
}
if (self.attackTimer >= effectiveAttackCooldown) {
// Simple projectile attack towards banana
var target = banana; // Always target first banana for simplicity
if (target) {
var dx = target.x - self.x;
var dy = target.y - self.y;
var angle = Math.atan2(dy, dx);
var speed = 3 + Math.random() * 2;
// Create a simple grape projectile (reuse grape eye)
var projectile = new GrapeEye();
projectile.x = self.x;
projectile.y = self.y;
projectile.speedX = Math.cos(angle) * speed;
projectile.speedY = Math.sin(angle) * speed;
projectile.damage = 10;
grapeProjectiles.push(projectile);
game.addChild(projectile);
}
self.attackTimer = 0;
}
};
self.showSpeechBubble = function () {
if (self.speechBubble) return; // Don't create multiple bubbles
var angryQuotes = ["You can't stop us!", "We are unstoppable!", "Surrender now!", "Your doom awaits!", "Feel our wrath!", "We will crush you!", "You stand no chance!", "Prepare for defeat!"];
var randomQuote = angryQuotes[Math.floor(Math.random() * angryQuotes.length)];
// Create speech bubble background
self.speechBubble = LK.getAsset('shape', {
width: 250,
height: 80,
anchorX: 0.5,
anchorY: 1
});
self.speechBubble.tint = 0xFFFFFF;
self.speechBubble.x = self.x;
self.speechBubble.y = self.y - 60;
game.addChild(self.speechBubble);
// Create speech text
self.speechText = new Text2(randomQuote, {
size: 60,
fill: 0xFFFFFF
});
self.speechText.anchor.set(0.5, 0.5);
self.speechText.x = self.x;
self.speechText.y = self.y - 100;
game.addChild(self.speechText);
// Auto-remove after 3 seconds
LK.setTimeout(function () {
if (self.speechBubble) {
self.speechBubble.destroy();
self.speechBubble = null;
}
if (self.speechText) {
self.speechText.destroy();
self.speechText = null;
}
}, 3000);
};
return self;
});
// Create vitamins selection screen
var GrapeEye = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('grapeEye', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 15;
self.isPhase2 = false; // Track if this is from phase 2
self.setPhase2 = function () {
self.isPhase2 = true;
self.scaleX = 5.0; // Even larger in phase 2
self.scaleY = 5.0;
self.damage = 35; // Significantly more damage in phase 2
};
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var GrapeMouth = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('grapeMouth', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 20;
self.isPhase2 = false; // Track if this is from phase 2
self.setPhase2 = function () {
self.isPhase2 = true;
self.scaleX = 6.0; // Even larger in phase 2
self.scaleY = 6.0;
self.damage = 45; // Significantly more damage in phase 2
};
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var GrapesBoss = Container.expand(function () {
var self = Container.call(this);
self.phase = 1;
self.maxHealth = 500; // Health for phase 1 (distributed among grapes)
self.health = self.maxHealth;
self.attackTimer = 0;
self.attackCooldown = 180; // 3 seconds
self.formationAttackTimer = 0;
self.coverAttackTimer = 0;
self.merging = false;
self.bigGrapeGraphics = null;
// Phase 2 properties
self.moveDirection = 1;
self.moveSpeed = 1.5;
self.eyeAttackTimer = 0;
self.mouthAttackTimer = 0;
self.takeDamage = function (damage, isIce) {
if (self.phase === 2) {
// Phase 2 - damage the big grape directly
self.health -= damage;
LK.effects.flashObject(self.bigGrapeGraphics, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Handle ice bullet freeze effect
if (isIce) {
if (!self.iceHits) self.iceHits = 0;
self.iceHits++;
if (self.iceHits >= 12 && !self.frozen) {
// Much harder to freeze big grape - requires 12 hits instead of 8
self.frozen = true;
self.freezeTimer = 60; // Reduced freeze time to 1 second at 60fps
self.originalTint = self.bigGrapeGraphics.tint;
tween(self.bigGrapeGraphics, {
tint: 0x87ceeb
}, {
duration: 100
});
self.iceHits = 0;
}
}
if (self.health <= 0) {
// Final defeat
self.defeat();
}
}
};
self.defeat = function () {
// Check win condition
var shouldWin = true;
if (selectedBoss === 'both') {
if (watermelonBoss && watermelonBoss.health > 0) {
shouldWin = false;
}
if (pineappleBoss && pineappleBoss.health > 0) {
shouldWin = false;
}
}
if (shouldWin) {
// Unlock achievement for defeating annoying grapes
unlockAchievement('annoying_grapes');
if (selectedMode === '2player') {
unlockAchievement('power_bananas');
}
// Victory animation
LK.stopMusic();
var targetGraphics = self.phase === 2 ? self.bigGrapeGraphics : self;
tween(targetGraphics, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
} else {
// Just explosion animation without winning
LK.stopMusic();
var targetGraphics = self.phase === 2 ? self.bigGrapeGraphics : self;
tween(targetGraphics, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Boss defeated but don't show win yet
}
});
}
};
self.checkPhaseTransition = function () {
// Check if all individual grapes are defeated
if (grapes.length === 0 && self.phase === 1 && !self.merging) {
self.startMerging();
}
};
self.startMerging = function () {
self.merging = true;
self.phase = 2;
self.health = 500; // Phase 2 health set back to 500
self.maxHealth = 500;
// Create big grape
self.bigGrapeGraphics = self.attachAsset('bigGrape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.x = 1600;
self.y = 1366;
// Dramatic merging animation with multiple effects
LK.effects.flashScreen(0x9932CC, 2000);
// Create pulsing effect before main animation
tween(self.bigGrapeGraphics, {
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.5
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Main dramatic scaling animation
tween(self.bigGrapeGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 1.0
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.merging = false;
// Add rotation animation
tween(self, {
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.rotation = 0;
}
});
}
});
}
});
};
self.formationAttack = function () {
// Line up grapes side by side and charge at player
var startX = 1800;
var startY = 1366;
var spacing = 100;
for (var i = 0; i < grapes.length; i++) {
var grape = grapes[i];
var targetX = startX;
var targetY = startY + (i - 2) * spacing; // Center around middle
grape.moveToFormation(targetX, targetY);
}
// After formation, charge towards banana
LK.setTimeout(function () {
for (var i = 0; i < grapes.length; i++) {
var grape = grapes[i];
grape.formationMode = false;
// Set direction towards banana
var dx = banana.x - grape.x;
var dy = banana.y - grape.y;
grape.moveDirection = Math.atan2(dy, dx);
grape.moveSpeed = 6; // Fast charge
}
}, 1500); // 1.5 seconds to get in formation
};
self.coverAttack = function () {
// Grapes surround and cover the player
for (var i = 0; i < grapes.length; i++) {
var grape = grapes[i];
grape.startCoverMode(banana);
}
};
self.eyeAttack = function () {
if (self.phase !== 2) return;
// Shoot multiple eyes in spread pattern - more eyes and faster
var numEyes = 10; // Increased from 6 to 10
var angleStep = Math.PI * 2 / numEyes;
for (var i = 0; i < numEyes; i++) {
var eye = new GrapeEye();
eye.setPhase2(); // Make it larger for phase 2
eye.x = self.x;
eye.y = self.y;
var angle = i * angleStep;
var speed = 6; // Increased speed from 4 to 6
eye.speedX = Math.cos(angle) * speed;
eye.speedY = Math.sin(angle) * speed;
grapeProjectiles.push(eye);
game.addChild(eye);
}
};
self.mouthAttack = function () {
if (self.phase !== 2) return;
// Shoot mouths towards banana - more projectiles and faster
var numMouths = 5; // Increased from 3 to 5
for (var i = 0; i < numMouths; i++) {
var mouth = new GrapeMouth();
mouth.setPhase2(); // Make it larger for phase 2
mouth.x = self.x;
mouth.y = self.y;
// Calculate angle towards banana with spread
var dx = banana.x - self.x;
var dy = banana.y - self.y;
var baseAngle = Math.atan2(dy, dx);
var spread = (i - 2) * 0.4; // Wider spread with more projectiles
var angle = baseAngle + spread;
var speed = 7.5; // Increased speed from 5 to 7.5
mouth.speedX = Math.cos(angle) * speed;
mouth.speedY = Math.sin(angle) * speed;
grapeProjectiles.push(mouth);
game.addChild(mouth);
}
};
self.update = function () {
if (self.phase === 1) {
// Phase 1 - manage individual grapes
self.checkPhaseTransition();
if (grapes.length > 0) {
self.attackTimer++;
var effectiveAttackCooldown = self.attackCooldown;
if (selectedDifficulty === 'simple') {
effectiveAttackCooldown = Math.floor(self.attackCooldown * 1.5);
}
if (self.attackTimer >= effectiveAttackCooldown) {
var attackType = Math.random();
if (attackType < 0.33) {
// Random bouncing movement (33% chance)
for (var i = 0; i < grapes.length; i++) {
var grape = grapes[i];
grape.formationMode = false;
grape.coverMode = false;
grape.moveDirection = Math.random() * Math.PI * 2;
grape.moveSpeed = 2 + Math.random() * 2;
}
} else if (attackType < 0.66) {
// Formation attack - line up and charge (33% chance)
self.formationAttack();
} else {
// Cover attack - surround player (33% chance)
self.coverAttack();
}
self.attackTimer = 0;
}
}
} else if (self.phase === 2 && !self.merging) {
// Handle freeze effect
if (self.frozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
tween(self.bigGrapeGraphics, {
tint: self.originalTint
}, {
duration: 100
});
}
return; // Skip all actions while frozen
}
// Phase 2 - big grape movement and attacks
var effectiveMoveSpeed = self.moveSpeed * 1.8; // Much faster base movement
if (selectedDifficulty === 'simple') {
effectiveMoveSpeed = self.moveSpeed * 1.2; // Still faster even on simple difficulty
}
// More erratic movement pattern
self.y += self.moveDirection * effectiveMoveSpeed;
// Add sine wave movement for unpredictability
self.x += self.moveDirection * effectiveMoveSpeed * 0.5 + Math.sin(LK.ticks * 0.05) * 2;
if (self.y <= 200 || self.y >= 2500) {
self.moveDirection *= -1;
// Add random direction change on bounce
if (Math.random() < 0.3) {
self.moveDirection += (Math.random() - 0.5) * 0.4;
}
}
// Bounce off walls with more aggressive behavior
if (self.x <= 50 || self.x >= 1998) {
self.moveDirection *= -1;
// Occasional direction change when hitting walls
if (Math.random() < 0.4) {
self.moveDirection += (Math.random() - 0.5) * 0.6;
}
}
// Eye attack - more frequent
self.eyeAttackTimer++;
if (self.eyeAttackTimer >= 75) {
// Every 1.25 seconds (faster attacks)
self.eyeAttack();
self.eyeAttackTimer = 0;
}
// Mouth attack - more frequent
self.mouthAttackTimer++;
if (self.mouthAttackTimer >= 105) {
// Every 1.75 seconds (faster attacks)
self.mouthAttack();
self.mouthAttackTimer = 0;
}
}
};
return self;
});
var GrenadeProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('grenadeProjectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
self.speed = 4;
self.damage = 50;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var HomingProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('homingProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 3;
self.enhanced = false;
self.target = null;
self.update = function () {
if (self.target && self.target.health > 0) {
// Calculate angle to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var angle = Math.atan2(dy, dx);
// Move towards target
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
// Move forward if no target
self.x += self.speed;
}
};
return self;
});
var Horseshoe = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('horseshoe', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 0; // No damage, just grants invincibility
self.rotationSpeed = 0.1; // Spinning effect
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.rotation += self.rotationSpeed;
};
return self;
});
var IceProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('iceProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 3;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var LaserProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('laserProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 1;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var MusicNote = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('musicNote', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 10;
self.rotationSpeed = 0.1;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.rotation += self.rotationSpeed;
};
return self;
});
var PineappleHorseBoss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pineappleHorse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Tint to make it look different (golden yellow for pineapple horse)
graphics.tint = 0xFFD700;
self.graphics = graphics; // Store reference to graphics
self.maxHealth = 400;
self.health = self.maxHealth;
self.attackTimer = 0;
self.attackCooldown = 90; // 1.5 seconds at 60fps
self.phase = 1;
self.moveDirection = 1;
self.moveSpeed = 2.5; // Faster movement than watermelon
self.chargeAttackCooldown = 0;
self.isCharging = false;
self.chargeTarget = {
x: 0,
y: 0
};
self.originalPosition = {
x: 0,
y: 0
};
self.takeDamage = function (damage, isIce) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Handle ice bullet freeze effect
if (isIce) {
if (!self.iceHits) self.iceHits = 0;
self.iceHits++;
if (self.iceHits >= 5 && !self.frozen) {
self.frozen = true;
self.freezeTimer = 48; // 0.8 seconds at 60fps
self.originalTint = self.graphics.tint;
tween(self.graphics, {
tint: 0x87ceeb
}, {
duration: 100
});
self.iceHits = 0; // Reset ice hit counter
}
}
if (self.health <= 0) {
if (selectedBoss === 'both') {
// In both bosses mode, no phase 2 - just die
// Check if we should show win condition
var shouldWin = true;
if (watermelonBoss && watermelonBoss.health > 0) {
shouldWin = false; // Don't win until both bosses are defeated
}
if (shouldWin) {
// Unlock Horse But Pineapple achievement
unlockAchievement('horse_pineapple');
// Check for 2-player mode achievement
if (selectedMode === '2player') {
unlockAchievement('power_bananas');
}
// Final death - explosion animation before showing You Win
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
} else {
// Just explosion animation without winning
LK.stopMusic();
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Boss is defeated but don't show win yet
}
});
}
} else if (self.phase < 2) {
// If not in final phase yet and not in both bosses mode, transition to phase 2
self.phase = 2; // Move to phase 2
self.maxHealth = 400; // Set phase 2 max health
self.health = 400; // Reset health for phase 2
self.attackCooldown = 102; // 1.7 seconds at 60fps for spear attacks
self.moveSpeed = 3.5; // Even faster movement
// Switch to phase 2 asset
self.removeChild(self.graphics);
self.graphics = self.attachAsset('pineappleHorsePhase2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.56,
scaleY: 1.56
});
// Phase 2 uses natural colors, no tint needed
// Flash effect for phase transition
LK.effects.flashObject(self, 0x00FF00, 1000);
// Add dramatic animation for phase transition
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Keep the bigger size in phase 2
}
});
// Add rotation animation for phase transition
tween(self, {
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.rotation = 0;
}
});
} else {
// Check if we should show win condition
var shouldWin = true;
if (selectedBoss === 'both' && watermelonBoss && watermelonBoss.health > 0) {
shouldWin = false; // Don't win until both bosses are defeated
}
if (shouldWin) {
// Unlock Horse But Pineapple achievement
unlockAchievement('horse_pineapple');
// Check for 2-player mode achievement
if (selectedMode === '2player') {
unlockAchievement('power_bananas');
}
// Final death - explosion animation before showing You Win
LK.stopMusic();
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
} else {
// Just explosion animation without winning
LK.stopMusic();
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Boss is defeated but don't show win yet
}
});
}
}
}
};
self.spearAttack = function () {
var spear = new PineappleSpear();
// Spawn spear directly at boss position
spear.x = self.x;
spear.y = self.y;
// Set banana as target for seeking behavior
spear.target = banana;
// Calculate initial direction towards banana for rotation
var dx = banana.x - spear.x;
var dy = banana.y - spear.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Set initial rotation
spear.rotation = Math.atan2(dy, dx);
// Add fade-in effect for 3-second duration
tween(spear, {
alpha: 0.3
}, {
duration: 3000,
// 3 seconds
easing: tween.linear,
onFinish: function onFinish() {
// Spear will be destroyed by its own update method when lifeTime reaches 0
}
});
pineappleSpears.push(spear);
game.addChild(spear);
};
self.pineappleThrowAttack = function () {
var thrownPineapple = new PineappleThrow();
// Spawn pineapple at boss position
thrownPineapple.x = self.x;
thrownPineapple.y = self.y;
// Calculate trajectory towards banana's position
var dx = banana.x - thrownPineapple.x;
var dy = banana.y - thrownPineapple.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Set initial velocity
var throwSpeed = 6;
thrownPineapple.speedX = dx * throwSpeed;
thrownPineapple.speedY = dy * throwSpeed;
// Add throwing animation
tween(thrownPineapple, {
rotation: Math.PI * 4 // Spin while flying
}, {
duration: 2000,
easing: tween.linear
});
thrownPineapples.push(thrownPineapple);
game.addChild(thrownPineapple);
};
self.horseshoeAttack = function () {
var horseshoe = new Horseshoe();
// Spawn horseshoe at boss position
horseshoe.x = self.x;
horseshoe.y = self.y;
// Calculate trajectory towards banana's position
var dx = banana.x - horseshoe.x;
var dy = banana.y - horseshoe.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Set horseshoe velocity (slower than other projectiles)
var horseshoeSpeed = 4;
horseshoe.speedX = dx * horseshoeSpeed;
horseshoe.speedY = dy * horseshoeSpeed;
// Add spinning animation
tween(horseshoe, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut
});
horseshoes.push(horseshoe);
game.addChild(horseshoe);
};
self.chargeAttack = function () {
if (self.isCharging || self.chargeAttackCooldown > 0) return;
self.isCharging = true;
self.originalPosition.x = self.x;
self.originalPosition.y = self.y;
self.chargeTarget.x = banana.x;
self.chargeTarget.y = banana.y;
// Phase 1: Preparation phase - pull back and flash warning
// Flash to indicate charge preparation
LK.effects.flashObject(self, 0xFFFF00, 800);
// Calculate pullback position (opposite direction from banana)
var pullbackDistance = 100;
var dx = self.x - banana.x;
var dy = self.y - banana.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
var pullbackX = self.x + dx * pullbackDistance;
var pullbackY = self.y + dy * pullbackDistance;
// Clamp pullback position within screen bounds
pullbackX = Math.max(100, Math.min(1948, pullbackX));
pullbackY = Math.max(200, Math.min(2532, pullbackY));
// Phase 1: Pull back with anticipation
tween(self, {
x: pullbackX,
y: pullbackY,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
// Phase 2: Forward charge attack
// Flash brighter to indicate charge execution
LK.effects.flashObject(self, 0xFF4400, 400);
// Determine charge parameters based on phase
var chargeDuration = self.phase === 2 ? 150 : 300; // Phase 2: faster charge (150ms vs 300ms)
var chargeDistance = self.phase === 2 ? 300 : 0; // Phase 2: longer dash distance
// Calculate extended target position for phase 2
var finalTargetX = self.chargeTarget.x;
var finalTargetY = self.chargeTarget.y;
if (self.phase === 2) {
// Extend the charge beyond banana's position for longer dash
var dx = self.chargeTarget.x - self.x;
var dy = self.chargeTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
finalTargetX = self.chargeTarget.x + dx * chargeDistance;
finalTargetY = self.chargeTarget.y + dy * chargeDistance;
}
// Clamp extended position within screen bounds
finalTargetX = Math.max(100, Math.min(1948, finalTargetX));
finalTargetY = Math.max(200, Math.min(2532, finalTargetY));
}
// Quick charge towards target position (faster and longer in phase 2)
tween(self, {
x: finalTargetX,
y: finalTargetY,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: chargeDuration,
easing: tween.easeIn,
onFinish: function onFinish() {
// Check if hit banana during charge
if (self.intersects(banana)) {
banana.takeDamage(40);
}
// Return to original position
tween(self, {
x: self.originalPosition.x,
y: self.originalPosition.y
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isCharging = false;
self.chargeAttackCooldown = 180; // 3 second cooldown
}
});
}
});
}
});
};
self.update = function () {
// Handle freeze effect
if (self.frozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
tween(self.graphics, {
tint: self.originalTint
}, {
duration: 100
});
}
return; // Skip all actions while frozen
}
// Only move when not charging
if (!self.isCharging) {
// Apply difficulty modifiers to movement
var effectiveMoveSpeed = self.moveSpeed;
if (selectedDifficulty === 'simple') {
effectiveMoveSpeed = self.moveSpeed * 0.7; // 30% slower movement
}
// Circular movement pattern
self.y += self.moveDirection * effectiveMoveSpeed;
if (self.y <= 300 || self.y >= 2400) {
self.moveDirection *= -1;
}
// Add horizontal movement in figure-8 pattern
var horizontalModifier = selectedDifficulty === 'simple' ? 1.0 : 1.5;
self.x += Math.sin(LK.ticks * 0.02) * horizontalModifier;
}
// Update charge cooldown
if (self.chargeAttackCooldown > 0) {
self.chargeAttackCooldown--;
}
// Attack logic
self.attackTimer++;
// Apply difficulty modifiers
var effectiveAttackCooldown = self.attackCooldown;
if (selectedDifficulty === 'simple') {
effectiveAttackCooldown = Math.floor(self.attackCooldown * 1.5); // 50% slower attacks
}
if (self.attackTimer >= effectiveAttackCooldown) {
var attackChoice = Math.random();
if (attackChoice < 0.2 && self.chargeAttackCooldown <= 0) {
// Charge attack (20% chance)
self.chargeAttack();
} else if (attackChoice < 0.25) {
// Pineapple throw attack (5% chance - reduced)
self.pineappleThrowAttack();
} else if (attackChoice < 0.27) {
// Horseshoe attack (2% chance - very rare attack)
self.horseshoeAttack();
} else {
// Spear attack (70% chance)
self.spearAttack();
}
self.attackTimer = 0;
}
};
return self;
});
var PineappleSlice = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pineappleSpear', {
anchorX: 0.5,
anchorY: 0.5
});
// Different tint for slices to distinguish from spears
graphics.tint = 0xFFA500; // Orange tint
self.scaleX = 2.0;
self.scaleY = 2.0;
self.speedX = 0;
self.speedY = 0;
self.damage = 20;
self.lifeTime = 300; // 5 seconds at 60fps
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Keep constant movement - no slowing down
// Decrease lifetime
self.lifeTime--;
if (self.lifeTime <= 0) {
// Find and remove from pineappleSlices array
for (var i = pineappleSlices.length - 1; i >= 0; i--) {
if (pineappleSlices[i] === self) {
self.destroy();
pineappleSlices.splice(i, 1);
break;
}
}
}
};
return self;
});
var PineappleSpear = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pineappleSpear', {
anchorX: 0.5,
anchorY: 0.5
});
// Golden yellow tint for pineapple spears
graphics.tint = 0xFFD700;
self.scaleX = 4.0;
self.scaleY = 4.0;
self.speedX = 0;
self.speedY = 0;
self.damage = 25;
self.seekSpeed = 5.5; // Speed for seeking behavior
self.target = null; // Target to seek
self.lifeTime = 180; // 3 seconds at 60fps
self.maxLifeTime = 180; // Store original lifetime
self.update = function () {
// Decrease lifetime
self.lifeTime--;
// If lifetime expired, destroy the spear
if (self.lifeTime <= 0) {
// Find and remove from pineappleSpears array
for (var i = pineappleSpears.length - 1; i >= 0; i--) {
if (pineappleSpears[i] === self) {
self.destroy();
pineappleSpears.splice(i, 1);
break;
}
}
return;
}
// Seeking behavior towards target (banana)
if (self.target && self.target.health > 0) {
// Calculate direction to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply seek speed
var dirX = dx / distance;
var dirY = dy / distance;
// Use different speed based on boss phase - check if pineapple boss exists and is in phase 2
var currentSeekSpeed = self.seekSpeed;
if (pineappleBoss && pineappleBoss.phase === 2) {
currentSeekSpeed = 10;
}
self.x += dirX * currentSeekSpeed;
self.y += dirY * currentSeekSpeed;
// Update rotation to face target
self.rotation = Math.atan2(dy, dx);
}
} else {
// Fallback to original movement if no target
self.x += self.speedX;
self.y += self.speedY;
}
};
return self;
});
var PineappleThrow = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('pineappleHorse', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale down to make it smaller than the boss
self.scaleX = 0.3;
self.scaleY = 0.3;
// Golden yellow tint for thrown pineapple
graphics.tint = 0xFFD700;
self.speedX = 0;
self.speedY = 0;
self.hitCount = 0; // Track number of bullet hits
self.maxHits = 2; // Explode after 2 hits
self.damaged = false; // Track if it's been hit
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Keep constant movement - no slowing down
};
self.takeDamage = function (damage) {
self.hitCount++;
// Flash effect when hit
LK.effects.flashObject(self, 0xFF0000, 200);
self.damaged = true;
if (self.hitCount >= self.maxHits) {
self.explode();
}
};
self.explode = function () {
// Create 8 pineapple slices in different directions
var numSlices = 8;
for (var i = 0; i < numSlices; i++) {
var slice = new PineappleSlice();
slice.x = self.x;
slice.y = self.y;
// Calculate angle for each slice (45 degrees apart)
var angle = i * Math.PI * 2 / numSlices;
var speed = 4 + Math.random() * 2; // Random speed variation
slice.speedX = Math.cos(angle) * speed;
slice.speedY = Math.sin(angle) * speed;
// Add slight rotation for visual effect
slice.rotation = angle;
pineappleSlices.push(slice);
game.addChild(slice);
}
// Remove this pineapple from the array and destroy it
for (var j = thrownPineapples.length - 1; j >= 0; j--) {
if (thrownPineapples[j] === self) {
self.destroy();
thrownPineapples.splice(j, 1);
break;
}
}
};
return self;
});
var ReverseProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('reverseProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -8; // Negative speed to shoot backwards
self.damage = 8;
self.enhanced = false;
self.update = function () {
self.x += self.speed; // Moving backwards (left)
};
return self;
});
var SoundWave = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('soundWave', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 15;
self.pulseTimer = 0;
self.growthTimer = 0; // Track how long the sound wave has been alive
self.maxGrowthTime = 120; // Default 2 seconds (120 ticks at 60fps) for Phase 1
self.initialScale = 1.0; // Starting scale
self.maxScale = 3.0; // Maximum scale the wave can reach
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Growth effect over time
self.growthTimer++;
// Determine max growth time based on DJ Apple phase
if (djAppleBoss) {
if (djAppleBoss.phase === 1) {
self.maxGrowthTime = 120; // 2 seconds
} else if (djAppleBoss.phase === 2) {
self.maxGrowthTime = 180; // 3 seconds
} else if (djAppleBoss.phase === 3) {
self.maxGrowthTime = 300; // 5 seconds
}
}
// Calculate growth progress (0 to 1)
var growthProgress = Math.min(self.growthTimer / self.maxGrowthTime, 1.0);
// Use easing function to make growth smoother
var easedProgress = growthProgress * growthProgress; // Quadratic easing
// Calculate current scale based on growth
var currentScale = self.initialScale + (self.maxScale - self.initialScale) * easedProgress;
// Apply pulsing effect on top of growth
self.pulseTimer++;
var pulse = 1 + Math.sin(self.pulseTimer * 0.2) * 0.1; // Reduced pulse intensity
self.scaleX = currentScale * pulse;
self.scaleY = currentScale * pulse;
};
return self;
});
var SpeakerMinion = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('speaker', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 30;
self.maxHealth = 30;
self.attackTimer = 0;
self.attackCooldown = 120; // 2 seconds
self.damage = 12;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
}
};
self.update = function () {
// Simple attack - shoot sound waves at banana
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
var wave = new SoundWave();
wave.x = self.x;
wave.y = self.y;
var dx = banana.x - self.x;
var dy = banana.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
wave.speedX = dx * 3;
wave.speedY = dy * 3;
wave.damage = self.damage;
wave.scaleX = 0.8;
wave.scaleY = 0.8;
djAppleProjectiles.push(wave);
game.addChild(wave);
self.attackTimer = 0;
}
};
return self;
});
var SpreadProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('spreadProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7;
self.damage = 3;
self.enhanced = false;
self.angle = 0; // Angle for spread direction
self.update = function () {
self.x += Math.cos(self.angle) * self.speed;
self.y += Math.sin(self.angle) * self.speed;
};
return self;
});
var VinylDisc = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('vinylDisc', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 18;
self.bounces = 0;
self.maxBounces = 3;
self.rotationSpeed = 0.15;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.rotation += self.rotationSpeed;
// Bounce off walls
if (self.x <= 25 || self.x >= 2023) {
self.speedX *= -1;
self.bounces++;
}
if (self.y <= 25 || self.y >= 2707) {
self.speedY *= -1;
self.bounces++;
}
// Remove after max bounces
if (self.bounces >= self.maxBounces) {
for (var i = djAppleProjectiles.length - 1; i >= 0; i--) {
if (djAppleProjectiles[i] === self) {
self.destroy();
djAppleProjectiles.splice(i, 1);
break;
}
}
}
};
return self;
});
var WatermelonBoss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelon', {
anchorX: 0.5,
anchorY: 0.5
});
self.graphics = graphics; // Store reference to graphics for phase switching
self.maxHealth = 500;
self.health = self.maxHealth;
self.attackTimer = 0;
self.attackCooldown = 120; // 2 seconds - more frequent attacks in phase 1
self.phase = 1;
self.moveDirection = 1;
self.moveSpeed = 1;
self.potionsDroppedThisPhase = 0;
self.maxPotionsPerPhase = 1;
self.minPotionsPerPhase = 1;
self.mustDropPotion = false;
self.attacking = false;
self.divisionSlices = null;
self.divisionAttackTimer = 0;
self.currentAttackingSlice = 0;
self.takeDamage = function (damage, isIce) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Handle ice bullet freeze effect
if (isIce) {
if (!self.iceHits) self.iceHits = 0;
self.iceHits++;
if (self.iceHits >= 5 && !self.frozen) {
self.frozen = true;
self.freezeTimer = 48; // 0.8 seconds at 60fps
self.originalTint = self.graphics.tint;
tween(self.graphics, {
tint: 0x87ceeb
}, {
duration: 100
});
self.iceHits = 0; // Reset ice hit counter
}
}
// Change phase based on health
if (self.health <= self.maxHealth * 0.66 && self.phase === 1) {
self.phase = 2;
self.attackCooldown = 135; // Faster attacks
self.moveSpeed = 2; // Faster movement in phase 2
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
} else if (self.health <= self.maxHealth * 0.33 && self.phase === 2) {
self.phase = 3;
self.attackCooldown = 90; // Even faster attacks
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
}
if (self.health <= 0) {
if (selectedBoss === 'both') {
// In both bosses mode, no phase 2 - just die
// Check if we should show win condition
var shouldWin = true;
if (pineappleBoss && pineappleBoss.health > 0) {
shouldWin = false; // Don't win until both bosses are defeated
}
if (shouldWin) {
// Unlock Seedy and Juicy achievement
unlockAchievement('seedy_juicy');
// Check for 2-player mode achievement
if (selectedMode === '2player') {
unlockAchievement('power_bananas');
}
// Explosion animation before showing You Win
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
} else {
// Just explosion animation without winning
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Boss is defeated but don't show win yet
}
});
}
} else if (self.phase < 4) {
// If not in final phase yet and not in both bosses mode
// Transition to second phase
self.phase = 4; // Mark as second phase
self.maxHealth = 500;
self.health = 500;
self.attackCooldown = 60; // Much faster attacks
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
// Switch to phase 2 asset
self.removeChild(self.graphics);
self.graphics = self.attachAsset('watermelonPhase2', {
anchorX: 0.5,
anchorY: 0.5
});
// Play faster music for Phase 2
LK.playMusic('Aa', {
fade: {
start: 0,
end: 0.3,
duration: 500
}
});
// Flash effect for phase transition
LK.effects.flashObject(self, 0x00FF00, 1000);
// Add dramatic animation for phase transition
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Keep the bigger size in phase 2, don't scale back down
}
});
// Add rotation animation
tween(self, {
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.rotation = 0;
}
});
} else {
// Check if we should show win condition
var shouldWin = true;
if (selectedBoss === 'both' && pineappleBoss && pineappleBoss.health > 0) {
shouldWin = false; // Don't win until both bosses are defeated
}
if (shouldWin) {
// Unlock Seedy and Juicy achievement
unlockAchievement('seedy_juicy');
// Check for 2-player mode achievement
if (selectedMode === '2player') {
unlockAchievement('power_bananas');
}
// Explosion animation before showing You Win
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
} else {
// Just explosion animation without winning
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Boss is defeated but don't show win yet
}
});
}
}
}
};
self.seedAttack = function () {
var numSeeds;
if (self.phase === 1) {
// Calculate damage percentage (0 to 1, where 1 is most damaged)
var damagePercent = 1 - self.health / self.maxHealth;
// Base seeds + bonus based on damage, with a higher limit in phase 1
var bonusSeeds = Math.floor(damagePercent * 8); // Up to 8 bonus seeds
numSeeds = Math.min(6 + bonusSeeds, 14); // Base 6, max 14 total
} else {
numSeeds = self.phase === 2 ? 5 : self.phase === 3 ? 8 : 10; // More seeds in second phase
}
for (var i = 0; i < numSeeds; i++) {
var seed = new WatermelonSeed();
seed.x = self.x + (Math.random() - 0.5) * 100;
seed.y = self.y + 50;
var angle = Math.random() * Math.PI * 2;
var baseSpeed = self.phase === 4 ? 5 : 2; // Faster in second phase
var speed = baseSpeed + Math.random() * (self.phase === 4 ? 5 : 3); // Higher speed range in second phase
seed.speedX = Math.cos(angle) * speed;
seed.speedY = Math.sin(angle) * speed;
// Make seeds bigger in phase 1 and even bigger in second phase
if (self.phase === 4) {
seed.scaleX = 2.0;
seed.scaleY = 2.0;
} else {
seed.scaleX = 1.5;
seed.scaleY = 1.5;
}
watermelonSeeds.push(seed);
game.addChild(seed);
}
};
self.sliceAttack = function () {
var numSlices = 2; // Only 2 slices in phase 1
for (var i = 0; i < numSlices; i++) {
var slice = new WatermelonSlice();
// Spawn from outside screen edges
var side = Math.random() < 0.5 ? 'left' : 'right';
if (side === 'left') {
slice.x = -100; // Start from left edge
slice.y = Math.random() * 1500 + 400;
} else {
slice.x = 2148; // Start from right edge
slice.y = Math.random() * 1500 + 400;
}
// Calculate angle towards banana
var dx = banana.x - slice.x;
var dy = banana.y - slice.y;
var angle = Math.atan2(dy, dx);
var speed = 3 + Math.random() * 2; // Slower than seeds but still threatening
slice.speedX = Math.cos(angle) * speed;
slice.speedY = Math.sin(angle) * speed;
// Make slices bigger than seeds, even bigger in phase 4
if (self.phase === 4) {
slice.scaleX = 3.0;
slice.scaleY = 3.0;
} else {
slice.scaleX = 2.0;
slice.scaleY = 2.0;
}
watermelonSlices.push(slice);
game.addChild(slice);
}
};
self.divisionAttack = function () {
// Only available in phase 1
if (self.phase !== 1) return;
// Hide the main watermelon temporarily
self.alpha = 0;
self.attacking = true;
self.divisionSlices = [];
// Store the current watermelon position at the time of division
var divisionCenterX = self.x;
var divisionCenterY = self.y;
// Create 4 slices positioned around the watermelon's division position
var slicePositions = [{
x: divisionCenterX - 150,
y: divisionCenterY - 150
},
// Top-left
{
x: divisionCenterX + 150,
y: divisionCenterY - 150
},
// Top-right
{
x: divisionCenterX - 150,
y: divisionCenterY + 150
},
// Bottom-left
{
x: divisionCenterX + 150,
y: divisionCenterY + 150
} // Bottom-right
];
for (var i = 0; i < 4; i++) {
var sliceType = i + 1; // Use slice types 1, 2, 3, 4
var slice = new WatermelonDivisionSlice(sliceType);
slice.x = slicePositions[i].x;
slice.y = slicePositions[i].y;
slice.scaleX = 1.5;
slice.scaleY = 1.5;
slice.alpha = 0;
slice.sliceIndex = i;
slice.isAttacking = false;
slice.hasAttacked = false;
slice.originalX = slice.x;
slice.originalY = slice.y;
self.divisionSlices.push(slice);
game.addChild(slice);
// Fade in each slice with a delay
tween(slice, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
// Start the sequential attack after all slices are visible
self.divisionAttackTimer = 120; // 2 seconds delay
self.currentAttackingSlice = 0;
};
self.updateDivisionAttack = function () {
if (!self.attacking || !self.divisionSlices) return;
if (self.divisionAttackTimer > 0) {
self.divisionAttackTimer--;
return;
}
// Check if current slice should start attacking
if (self.currentAttackingSlice < self.divisionSlices.length) {
var currentSlice = self.divisionSlices[self.currentAttackingSlice];
if (!currentSlice.isAttacking && !currentSlice.hasAttacked) {
// Start attacking with current slice
currentSlice.isAttacking = true;
// Calculate attack trajectory towards banana
var dx = banana.x - currentSlice.x;
var dy = banana.y - currentSlice.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var attackDuration = Math.min(1000, distance * 2); // Dynamic duration based on distance
// Animate slice towards banana
tween(currentSlice, {
x: banana.x,
y: banana.y
}, {
duration: attackDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Check if slice hit banana
if (currentSlice.intersects(banana)) {
banana.takeDamage(25);
// Calculate knockback direction from slice to banana
var knockbackX = banana.x - currentSlice.x;
var knockbackY = banana.y - currentSlice.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
}
// Calculate knockback destination (140 pixels away from slice)
var knockbackDistance = 140;
var targetX = banana.x + knockbackX * knockbackDistance;
var targetY = banana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(50, Math.min(1998, targetX));
targetY = Math.max(50, Math.min(2682, targetY));
// Apply knockback animation using tween
tween(banana, {
x: targetX,
y: targetY
}, {
duration: 230,
easing: tween.easeOut
});
}
// Return slice to original position
tween(currentSlice, {
x: currentSlice.originalX,
y: currentSlice.originalY
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
currentSlice.hasAttacked = true;
currentSlice.isAttacking = false;
}
});
}
});
self.currentAttackingSlice++;
self.divisionAttackTimer = 90; // 1.5 second delay before next slice
}
}
// Check if all slices have finished attacking
var allFinished = true;
for (var i = 0; i < self.divisionSlices.length; i++) {
if (!self.divisionSlices[i].hasAttacked) {
allFinished = false;
break;
}
}
if (allFinished) {
// All slices have attacked, return to original state
for (var j = 0; j < self.divisionSlices.length; j++) {
var slice = self.divisionSlices[j];
tween(slice, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
slice.destroy();
}
});
}
// Return watermelon to the center of where the slices were positioned
var returnX = self.divisionSlices[0].originalX + 150; // Center position
var returnY = self.divisionSlices[0].originalY + 150; // Center position
self.x = returnX;
self.y = returnY;
// Show main watermelon again
tween(self, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.attacking = false;
self.divisionSlices = null;
self.currentAttackingSlice = 0;
}
});
}
};
self.potionAttack = function () {
var numPotions = self.phase === 4 ? 3 : 2; // More potions in second phase
for (var i = 0; i < numPotions; i++) {
var potion = new WatermelonPotion();
potion.x = self.x + (Math.random() - 0.5) * 80;
potion.y = self.y + 50;
// Calculate angle towards banana
var dx = banana.x - potion.x;
var dy = banana.y - potion.y;
var angle = Math.atan2(dy, dx);
var baseSpeed = self.phase === 4 ? 4 : 2;
var speed = baseSpeed + Math.random() * 2;
potion.speedX = Math.cos(angle) * speed;
potion.speedY = Math.sin(angle) * speed;
// Make potions bigger in second phase
if (self.phase === 4) {
potion.scaleX = 3.5;
potion.scaleY = 3.5;
} else {
potion.scaleX = 3.0;
potion.scaleY = 3.0;
}
// Add glowing effect to potions
tween(potion, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(potion, {
alpha: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
watermelonPotions.push(potion);
game.addChild(potion);
}
};
self.update = function () {
// Handle freeze effect
if (self.frozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.frozen = false;
tween(self.graphics, {
tint: self.originalTint
}, {
duration: 100
});
}
return; // Skip all actions while frozen
}
// Movement - both vertical and horizontal
var effectiveMoveSpeed = self.moveSpeed;
if (selectedDifficulty === 'simple') {
effectiveMoveSpeed = self.moveSpeed * 0.7; // 30% slower movement
}
self.y += self.moveDirection * effectiveMoveSpeed;
self.x += self.moveDirection * effectiveMoveSpeed * 0.5; // Horizontal movement at half speed
if (self.y <= 300 || self.y >= 2400) {
self.moveDirection *= -1;
}
// No horizontal boundary restrictions - watermelon can move freely
// Update division attack if active
self.updateDivisionAttack();
// Skip normal attacks if currently performing division attack
if (self.attacking) return;
// Attack logic
self.attackTimer++;
// Apply difficulty modifiers
var effectiveAttackCooldown = self.attackCooldown;
if (selectedDifficulty === 'simple') {
effectiveAttackCooldown = Math.floor(self.attackCooldown * 1.5); // 50% slower attacks
}
if (self.attackTimer >= effectiveAttackCooldown) {
// Check if we need to force a potion drop
var healthPercent = self.health / self.maxHealth;
var shouldDropPotion = false;
// Force potion if we haven't dropped one yet and health is getting low
if (self.potionsDroppedThisPhase < self.minPotionsPerPhase && healthPercent < 0.3) {
self.mustDropPotion = true;
}
// Decide whether to drop potion (only if we haven't dropped one yet)
if (self.potionsDroppedThisPhase < self.maxPotionsPerPhase && (self.mustDropPotion || Math.random() < 0.05)) {
shouldDropPotion = true;
}
if (shouldDropPotion) {
self.potionAttack();
self.potionsDroppedThisPhase++;
self.mustDropPotion = false;
} else if (self.phase === 1 && Math.random() < 0.15) {
// In phase 1, occasionally use division attack
self.divisionAttack();
} else if (self.phase === 1 && Math.random() < 0.25) {
// In phase 1, throw larger watermelon slices more frequently instead of seeds
self.sliceAttack();
} else if (self.phase === 2 && Math.random() < 0.25) {
// In phase 2, also throw watermelon slices frequently
self.sliceAttack();
} else if (self.phase === 4 && Math.random() < 0.1) {
// In phase 4, throw watermelon slices very frequently
self.sliceAttack();
} else {
self.seedAttack();
}
self.attackTimer = 0;
}
};
return self;
});
var WatermelonDivisionSlice = Container.expand(function (sliceType) {
var self = Container.call(this);
// Default to slice 1 if no type specified
var assetName = 'watermelonDivisionSlice' + (sliceType || 1);
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 25; // Division slices do less damage than regular slices
self.sliceType = sliceType || 1;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonPotion = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('potion', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonSeed = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelonSeed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 20;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonSlice = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelonSlice', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 35; // Higher damage than seeds
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WideProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wideProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.damage = 10;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Triangle-shaped wave projectile
// Triangle shape for waves (using triangle approximation)
// Dark Gray
// Purple
// Dark Pink
// Pink
// Yellow
// Mint Green
// Sky Blue
// Teal
// Orange
// Brown
// Music
// Sound effects
// Projectile assets
// Character assets
// Game variables
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
var banana;
var banana2; // Second banana for 2-player mode
var upperBanana; // Reference to upper screen banana
var lowerBanana; // Reference to lower screen banana
var screenDividerY = 1366; // Middle of screen (2732/2)
// Achievements system
var achievements = storage.achievements || {
'seedy_juicy': false,
'horse_pineapple': false,
'power_bananas': false
};
// Unlocked costumes system
var unlockedCostumes = storage.unlockedCostumes || {
'watermelon': false,
'pineapple': false
};
var watermelonBoss;
var pineappleBoss;
var grapesBoss;
var djAppleBoss;
var grapes = [];
var grapeProjectiles = [];
var djAppleProjectiles = [];
var bananaProjectiles = [];
var watermelonSeeds = [];
var watermelonSlices = [];
var watermelonPotions = [];
var pineappleSpears = [];
var thrownPineapples = [];
var pineappleSlices = [];
var horseshoes = [];
var clouds = [];
var dragNode = null;
// Game state variables
var gameState = 'mainMenu'; // 'mainMenu', 'bossSelection', 'bulletSelection', 'difficultySelection', 'playing'
var mainMenu = null;
var bossSelectionScreen = null;
var selectedBoss = 'watermelon'; // 'watermelon', 'boss2', 'boss3', etc.
var selectedSkin = 'regular'; // 'regular', 'tuxedo'
// Bullet selection variables
var gameStarted = false;
var selectedBulletType = 'normal'; // 'normal', 'homing', 'wide', 'laser', or 'spread'
var selectedDifficulty = 'normal'; // 'simple' or 'normal'
var selectedMode = '1player'; // '1player' or '2player'
var selectionScreen = null;
var normalBulletButton = null;
var homingBulletButton = null;
var wideBulletButton = null;
var laserBulletButton = null;
var spreadBulletButton = null;
var selectionTitle = null;
var bulletDescription = null;
// Wide bullet specific cooldown
var wideBulletCooldown = 0;
var laserBulletCooldown = 0;
var spreadBulletCooldown = 0;
var grenadeBulletCooldown = 0;
var mousePressed = false;
var laserUsageTimer = 0; // Timer for 1.5 second intervals
var laserUsageDuration = 0; // Timer for 0.3 second usage
var laserCanUse = true; // Flag to control when laser can be used
var laserPressUsed = false; // Flag to track if current press has been used for laser
var holdTimer = 0; // Timer to track how long mouse has been held down
var miscBulletTypes = ['normal', 'homing', 'wide', 'laser', 'spread', 'ice', 'reverse', 'bouncy', 'grenade']; // Array of bullet types for miscellaneous
var currentMiscBulletIndex = 0; // Index to track current bullet type in miscellaneous mode
// Language system
var currentLanguage = 'english'; // 'english' or 'spanish'
// Bird shooting level variables
var gameInBirdLevel = false;
var currentLevelBirds = [];
var remainingBirdsCount = 0;
var currentBirdNumber = 1;
function spawnNextBird() {
if (remainingBirdsCount > 0) {
var bird = new Bird(currentBirdNumber);
bird.x = 1400 + Math.random() * 400;
bird.y = 400 + Math.random() * 1000;
currentLevelBirds.push(bird);
game.addChild(bird);
currentBirdNumber++;
remainingBirdsCount--;
}
}
var texts = {
english: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'DEFEAT THE MONSTER WATERMELON!',
play: 'PLAY',
skins: 'SKINS',
language: 'LANGUAGE: EN',
languageTitle: 'LANGUAGE',
english: 'ENGLISH ✓',
spanish: 'SPANISH',
french: 'FRENCH',
portuguese: 'PORTUGUESE',
german: 'GERMAN',
russian: 'RUSSIAN',
turkish: 'TURKISH',
moreLangs: 'More languages coming soon!',
back: 'BACK',
skinsTitle: 'SKINS',
comingSoon: 'COMING SOON!',
skinDesc: 'Customize Bananjohn with different\nskins and appearances!',
tuxedoBananjohn: 'TUXEDO BANANJOHN',
clownBananjohn: 'CLOWN BANANJOHN',
studentBananjohn: 'STUDENT BANANJOHN',
watermelonBananjohn: 'WATERMELON BANANJOHN',
pineappleBananjohn: 'PINEAPPLE BANANJOHN',
unlockWatermelon: 'Defeat Monster Watermelon to unlock',
unlockPineapple: 'Defeat Pineapple Horse to unlock',
moreSkins: 'More skins coming soon!',
instructions: 'Drag Bananjohn to move and avoid attacks!\nChoose your weapon wisely!',
selectBoss: 'SELECT BOSS',
monsterWatermelon: 'MONSTER WATERMELON',
watermelonDesc: 'The original menace! Multiple phases and attacks',
pineappleHorse: 'PINEAPPLE HORSE',
pineappleDesc: 'Fast and agile with leaf attacks and charges!',
bothBosses: 'BOTH BOSSES',
bothDesc: 'Ultimate challenge - face both at once!',
zestyPickle: 'ANNOYING GRAPES',
grapesDesc: 'Face 5 annoying grapes with attitude!',
mysteryBoss: 'Coming Soon',
mysteryBossDesc: 'A mysterious boss is coming soon!',
mysteryBossWarnings: ["No.", "You shouldn't.", "Don't even think about it.", "Not yet.", "Stop trying.", "Nice try.", "Nope.", "Access denied."],
selectMode: 'SELECT MODE',
onePlayer: '1 PLAYER',
twoPlayer: '2 PLAYER',
onePlayerDesc: 'Normal boss health',
twoPlayerDesc: 'Two bananas, split screen mode',
selectBullet: 'SELECT BULLET TYPE',
normalBullet: 'NORMAL BULLET',
normalDesc: '5 Damage, Fast Speed',
homingBullet: 'HOMING BULLET',
homingDesc: '3 Damage, Seeks Target',
wideBullet: 'WIDE BULLET',
wideDesc: '10 Damage, Very Slow',
laserBullet: 'LASER BULLET',
laserDesc: '1 damage, hold for attack',
laserCooldown: 'wait 1.5 seconds to fire',
spreadBullet: 'SPREAD BULLET',
spreadDesc: 'Fires 5 bullets, 3 damage each',
iceBullet: 'ICE BULLET',
iceDesc: '4 damage, freezes boss after 5 hits',
miscBullet: 'MISCELLANEOUS BULLET',
miscDesc: 'Cycles through all bullet types',
reverseBullet: 'REVERSE BULLET',
reverseDesc: '8 damage, shoots backwards',
bouncyBullet: 'BOUNCY BULLET',
bouncyDesc: '2 damage, bounces off walls and enemies',
grenadeBullet: 'GRENADE BULLET',
grenadeDesc: '50 damage, large and slow, 5 second cooldown',
selectDifficulty: 'SELECT DIFFICULTY',
simpleDifficulty: 'SIMPLE',
simpleDesc: 'Bosses are slower\nand attack less',
normalDifficulty: 'NORMAL',
achievements: 'ACHIEVEMENTS',
achievementUnlocked: 'Achievements Unlocked: ',
seedyJuicy: 'Seedy and Juicy',
seedyJuicyDesc: 'Defeat the Monster Watermelon',
horsePineapple: 'Horse But Pineapple?',
horsePineappleDesc: 'Defeat the Pineapple Horse',
powerBananas: 'The Power of Bananas!',
powerBananasDesc: 'Defeat a boss in two-player mode',
unlocked: '✓ UNLOCKED',
locked: '✗ LOCKED',
selected: '✓ SELECTED',
health: 'Health: ',
invincible: 'Health: Invincible',
bossHealth: 'Boss Health: ',
watermelon: 'Watermelon: ',
pineapple: 'Pineapple: ',
grapes: 'Grapes: ',
bigGrape: 'Big Grape: ',
phase1: ' (Phase 1)',
phase2: ' (Phase 2)'
}, "normalDesc", 'Original boss\ndifficulty'),
spanish: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: '¡DERROTA AL MONSTRUO SANDÍA!',
play: 'JUGAR',
skins: 'ASPECTOS',
language: 'IDIOMA: ES',
languageTitle: 'IDIOMA',
english: 'ENGLISH',
spanish: 'ESPAÑOL ✓',
french: 'FRANÇAIS',
portuguese: 'PORTUGUÊS',
german: 'DEUTSCH',
russian: 'РУССКИЙ',
turkish: 'TÜRKÇE',
moreLangs: '¡Más idiomas próximamente!',
back: 'VOLVER',
skinsTitle: 'ASPECTOS',
comingSoon: '¡PRÓXIMAMENTE!',
skinDesc: '¡Personaliza a Bananjohn con diferentes\naspectos y apariencias!',
tuxedoBananjohn: 'BANANJOHN ESMOQUIN',
clownBananjohn: 'BANANJOHN PAYASO',
studentBananjohn: 'BANANJOHN ESTUDIANTE',
watermelonBananjohn: 'BANANJOHN SANDÍA',
pineappleBananjohn: 'BANANJOHN PIÑA',
unlockWatermelon: 'Derrota al Monstruo Sandía para desbloquear',
unlockPineapple: 'Derrota al Caballo Piña para desbloquear',
moreSkins: '¡Más aspectos próximamente!',
instructions: '¡Arrastra a Bananjohn para moverte y evitar ataques!\n¡Elige tu arma sabiamente!',
selectBoss: 'SELECCIONAR JEFE',
monsterWatermelon: 'MONSTRUO SANDÍA',
watermelonDesc: '¡La amenaza original! Múltiples fases y ataques',
pineappleHorse: 'CABALLO PIÑA',
pineappleDesc: '¡Rápido y ágil con ataques de hoja y cargas!',
bothBosses: 'AMBOS JEFES',
bothDesc: '¡Desafío supremo - enfréntate a ambos a la vez!',
zestyPickle: 'UVAS MOLESTAS',
grapesDesc: '¡Enfrenta a 5 uvas molestas con actitud!',
mysteryBoss: 'Próximamente',
mysteryBossDesc: '¡Un jefe misterioso llegará pronto!',
mysteryBossWarnings: ["No.", "No deberías.", "Ni lo pienses.", "Aún no.", "Deja de intentarlo.", "Buen intento.", "No.", "Acceso denegado."],
selectMode: 'SELECCIONAR MODO',
onePlayer: '1 JUGADOR',
twoPlayer: '2 JUGADORES',
onePlayerDesc: 'Salud normal del jefe',
twoPlayerDesc: 'Dos bananas, modo pantalla dividida',
selectBullet: 'SELECCIONAR TIPO DE BALA',
normalBullet: 'BALA NORMAL',
normalDesc: '5 Daño, Velocidad Rápida',
homingBullet: 'BALA BUSCADORA',
homingDesc: '3 Daño, Busca Objetivo',
wideBullet: 'BALA ANCHA',
wideDesc: '10 Daño, Muy Lenta',
laserBullet: 'BALA LÁSER',
laserDesc: '1 daño, mantén presionado para atacar',
laserCooldown: 'espera 1.5 segundos para disparar',
spreadBullet: 'BALA DISPERSA',
spreadDesc: 'Dispara 5 balas, 3 daño cada una',
iceBullet: 'BALA DE HIELO',
iceDesc: '4 daño, congela al jefe después de 5 impactos',
miscBullet: 'BALA VARIADA',
miscDesc: 'Cicla entre todos los tipos de bala',
reverseBullet: 'BALA REVERSA',
reverseDesc: '8 daño, dispara hacia atrás',
bouncyBullet: 'BALA REBOTANTE',
bouncyDesc: '2 daño, rebota en paredes y enemigos',
grenadeBullet: 'BALA GRANADA',
grenadeDesc: '50 daño, grande y lenta, 5 segundos de recarga',
selectDifficulty: 'SELECCIONAR DIFICULTAD',
simpleDifficulty: 'SIMPLE',
simpleDesc: 'Los jefes son más lentos\ny atacan menos',
normalDifficulty: 'NORMAL',
achievements: 'LOGROS',
achievementUnlocked: 'Logros Desbloqueados: ',
seedyJuicy: 'Semilloso y Jugoso',
seedyJuicyDesc: 'Derrota al Monstruo Sandía',
horsePineapple: '¿Caballo Pero Piña?',
horsePineappleDesc: 'Derrota al Caballo Piña',
powerBananas: '¡El Poder de las Bananas!',
powerBananasDesc: 'Derrota a un jefe en modo de dos jugadores',
unlocked: '✓ DESBLOQUEADO',
locked: '✗ BLOQUEADO',
selected: '✓ SELECCIONADO',
health: 'Salud: ',
invincible: 'Salud: Invencible',
bossHealth: 'Salud del Jefe: ',
watermelon: 'Sandía: ',
pineapple: 'Piña: ',
grapes: 'Uvas: ',
bigGrape: 'Uva Grande: ',
phase1: ' (Fase 1)',
phase2: ' (Fase 2)'
}, "normalDesc", 'Dificultad original\ndel jefe'),
french: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'VAINCEZ LE MONSTRE PASTÈQUE!',
play: 'JOUER',
skins: 'APPARENCES',
language: 'LANGUE: FR',
languageTitle: 'LANGUE',
english: 'ENGLISH',
spanish: 'ESPAÑOL',
french: 'FRANÇAIS ✓',
portuguese: 'PORTUGUÊS',
german: 'DEUTSCH',
russian: 'РУССКИЙ',
turkish: 'TÜRKÇE',
moreLangs: 'Plus de langues bientôt!',
back: 'RETOUR',
skinsTitle: 'APPARENCES',
comingSoon: 'BIENTÔT DISPONIBLE!',
skinDesc: 'Personnalisez Bananjohn avec différentes\napparences et styles!',
tuxedoBananjohn: 'BANANJOHN SMOKING',
clownBananjohn: 'BANANJOHN CLOWN',
studentBananjohn: 'BANANJOHN ÉTUDIANT',
watermelonBananjohn: 'BANANJOHN PASTÈQUE',
pineappleBananjohn: 'BANANJOHN ANANAS',
unlockWatermelon: 'Vaincre le Monstre Pastèque pour débloquer',
unlockPineapple: 'Vaincre le Cheval Ananas pour débloquer',
moreSkins: 'Plus d\'apparences bientôt!',
instructions: 'Faites glisser Bananjohn pour bouger et éviter les attaques!\nChoisissez votre arme judicieusement!',
selectBoss: 'SÉLECTIONNER LE BOSS',
monsterWatermelon: 'MONSTRE PASTÈQUE',
watermelonDesc: 'La menace originale! Phases et attaques multiples',
pineappleHorse: 'CHEVAL ANANAS',
pineappleDesc: 'Rapide et agile avec des attaques de feuille et charges!',
bothBosses: 'LES DEUX BOSS',
bothDesc: 'Défi ultime - affrontez les deux à la fois!',
zestyPickle: 'RAISINS AGAÇANTS',
grapesDesc: 'Affrontez 5 raisins agaçants avec de l\'attitude!',
mysteryBoss: 'Bientôt disponible',
selectMode: 'SÉLECTIONNER LE MODE',
onePlayer: '1 JOUEUR',
twoPlayer: '2 JOUEURS',
onePlayerDesc: 'Santé normale du boss',
twoPlayerDesc: 'Deux bananes, mode écran partagé',
selectBullet: 'SÉLECTIONNER LE TYPE DE BALLE',
normalBullet: 'BALLE NORMALE',
normalDesc: '5 Dégâts, Vitesse Rapide',
homingBullet: 'BALLE GUIDÉE',
homingDesc: '3 Dégâts, Cherche la Cible',
wideBullet: 'BALLE LARGE',
wideDesc: '10 Dégâts, Très Lente',
laserBullet: 'BALLE LASER',
laserDesc: '1 dégât, maintenez pour attaquer',
laserCooldown: 'attendez 1,5 secondes pour tirer',
spreadBullet: 'BALLE DISPERSÉE',
spreadDesc: 'Tire 5 balles, 3 dégâts chacune',
iceBullet: 'BALLE DE GLACE',
iceDesc: '4 dégâts, gèle le boss après 5 coups',
miscBullet: 'BALLE VARIÉE',
miscDesc: 'Alterne entre tous les types de balles',
reverseBullet: 'BALLE INVERSE',
reverseDesc: '8 dégâts, tire vers l\'arrière',
bouncyBullet: 'BALLE REBONDISSANTE',
bouncyDesc: '2 dégâts, rebondit sur les murs et ennemis',
grenadeBullet: 'BALLE GRENADE',
grenadeDesc: '50 dégâts, grande et lente, 5 secondes de recharge',
selectDifficulty: 'SÉLECTIONNER LA DIFFICULTÉ',
simpleDifficulty: 'FACILE',
simpleDesc: 'Les boss sont plus lents\net attaquent moins',
normalDifficulty: 'NORMAL',
achievements: 'SUCCÈS',
achievementUnlocked: 'Succès Débloqués: ',
seedyJuicy: 'Plein de Pépins et Juteux',
seedyJuicyDesc: 'Vaincre le Monstre Pastèque',
horsePineapple: 'Cheval Mais Ananas?',
horsePineappleDesc: 'Vaincre le Cheval Ananas',
powerBananas: 'Le Pouvoir des Bananes!',
powerBananasDesc: 'Vaincre un boss en mode deux joueurs',
unlocked: '✓ DÉBLOQUÉ',
locked: '✗ VERROUILLÉ',
selected: '✓ SÉLECTIONNÉ',
health: 'Santé: ',
invincible: 'Santé: Invincible',
bossHealth: 'Santé du Boss: ',
watermelon: 'Pastèque: ',
pineapple: 'Ananas: ',
grapes: 'Raisins: ',
bigGrape: 'Gros Raisin: ',
phase1: ' (Phase 1)',
phase2: ' (Phase 2)'
}, "normalDesc", 'Difficulté originale\ndu boss'),
portuguese: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'DERROTE O MONSTRO MELANCIA!',
play: 'JOGAR',
skins: 'SKINS',
language: 'IDIOMA: PT',
languageTitle: 'IDIOMA',
english: 'ENGLISH',
spanish: 'ESPAÑOL',
french: 'FRANÇAIS',
portuguese: 'PORTUGUÊS ✓',
german: 'DEUTSCH',
russian: 'РУССКИЙ',
turkish: 'TÜRKÇE',
moreLangs: 'Mais idiomas em breve!',
back: 'VOLTAR',
skinsTitle: 'SKINS',
comingSoon: 'EM BREVE!',
skinDesc: 'Personalize o Bananjohn com diferentes\nskins e aparências!',
tuxedoBananjohn: 'BANANJOHN SMOKING',
clownBananjohn: 'BANANJOHN PALHAÇO',
studentBananjohn: 'BANANJOHN ESTUDANTE',
watermelonBananjohn: 'BANANJOHN MELANCIA',
pineappleBananjohn: 'BANANJOHN ABACAXI',
unlockWatermelon: 'Derrote o Monstro Melancia para desbloquear',
unlockPineapple: 'Derrote o Cavalo Abacaxi para desbloquear',
moreSkins: 'Mais skins em breve!',
instructions: 'Arraste o Bananjohn para se mover e evitar ataques!\nEscolha sua arma sabiamente!',
selectBoss: 'SELECIONAR CHEFE',
monsterWatermelon: 'MONSTRO MELANCIA',
watermelonDesc: 'A ameaça original! Múltiplas fases e ataques',
pineappleHorse: 'CAVALO ABACAXI',
pineappleDesc: 'Rápido e ágil com ataques de folha e cargas!',
bothBosses: 'AMBOS OS CHEFES',
bothDesc: 'Desafio supremo - enfrente os dois de uma vez!',
zestyPickle: 'UVAS IRRITANTES',
grapesDesc: 'Enfrente 5 uvas irritantes com atitude!',
mysteryBoss: 'Em breve',
selectMode: 'SELECIONAR MODO',
onePlayer: '1 JOGADOR',
twoPlayer: '2 JOGADORES',
onePlayerDesc: 'Vida normal do chefe',
twoPlayerDesc: 'Duas bananas, modo tela dividida',
selectBullet: 'SELECIONAR TIPO DE BALA',
normalBullet: 'BALA NORMAL',
normalDesc: '5 Dano, Velocidade Rápida',
homingBullet: 'BALA TELEGUIADA',
homingDesc: '3 Dano, Busca Alvo',
wideBullet: 'BALA LARGA',
wideDesc: '10 Dano, Muito Lenta',
laserBullet: 'BALA LASER',
laserDesc: '1 dano, segure para atacar',
laserCooldown: 'aguarde 1,5 segundos para atirar',
spreadBullet: 'BALA DISPERSA',
spreadDesc: 'Dispara 5 balas, 3 dano cada',
iceBullet: 'BALA DE GELO',
iceDesc: '4 dano, congela o chefe após 5 acertos',
miscBullet: 'BALA VARIADA',
miscDesc: 'Alterna entre todos os tipos de bala',
reverseBullet: 'BALA REVERSA',
reverseDesc: '8 dano, atira para trás',
bouncyBullet: 'BALA SALTITANTE',
bouncyDesc: '2 dano, ricocheia em paredes e inimigos',
grenadeBullet: 'BALA GRANADA',
grenadeDesc: '50 dano, grande e lenta, 5 segundos de recarga',
selectDifficulty: 'SELECIONAR DIFICULDADE',
simpleDifficulty: 'FÁCIL',
simpleDesc: 'Chefes são mais lentos\ne atacam menos',
normalDifficulty: 'NORMAL',
achievements: 'CONQUISTAS',
achievementUnlocked: 'Conquistas Desbloqueadas: ',
seedyJuicy: 'Sementoso e Suculento',
seedyJuicyDesc: 'Derrote o Monstro Melancia',
horsePineapple: 'Cavalo Mas Abacaxi?',
horsePineappleDesc: 'Derrote o Cavalo Abacaxi',
powerBananas: 'O Poder das Bananas!',
powerBananasDesc: 'Derrote um chefe no modo dois jogadores',
unlocked: '✓ DESBLOQUEADO',
locked: '✗ BLOQUEADO',
selected: '✓ SELECIONADO',
health: 'Vida: ',
invincible: 'Vida: Invencível',
bossHealth: 'Vida do Chefe: ',
watermelon: 'Melancia: ',
pineapple: 'Abacaxi: ',
grapes: 'Uvas: ',
bigGrape: 'Uva Grande: ',
phase1: ' (Fase 1)',
phase2: ' (Fase 2)'
}, "normalDesc", 'Dificuldade original\ndo chefe'),
german: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'BESIEGE DIE MONSTER WASSERMELONE!',
play: 'SPIELEN',
skins: 'SKINS',
language: 'SPRACHE: DE',
languageTitle: 'SPRACHE',
english: 'ENGLISH',
spanish: 'ESPAÑOL',
french: 'FRANÇAIS',
portuguese: 'PORTUGUÊS',
german: 'DEUTSCH ✓',
russian: 'РУССКИЙ',
turkish: 'TÜRKÇE',
moreLangs: 'Weitere Sprachen kommen bald!',
back: 'ZURÜCK',
skinsTitle: 'SKINS',
comingSoon: 'DEMNÄCHST!',
skinDesc: 'Passe Bananjohn mit verschiedenen\nSkins und Aussehen an!',
tuxedoBananjohn: 'BANANJOHN FRACK',
clownBananjohn: 'BANANJOHN CLOWN',
studentBananjohn: 'BANANJOHN STUDENT',
watermelonBananjohn: 'BANANJOHN WASSERMELONE',
pineappleBananjohn: 'BANANJOHN ANANAS',
unlockWatermelon: 'Besiege Monster Wassermelone zum Freischalten',
unlockPineapple: 'Besiege Ananas Pferd zum Freischalten',
moreSkins: 'Mehr Skins kommen bald!',
instructions: 'Ziehe Bananjohn um dich zu bewegen und Angriffen auszuweichen!\nWähle deine Waffe weise!',
selectBoss: 'BOSS WÄHLEN',
monsterWatermelon: 'MONSTER WASSERMELONE',
watermelonDesc: 'Die ursprüngliche Bedrohung! Mehrere Phasen und Angriffe',
pineappleHorse: 'ANANAS PFERD',
pineappleDesc: 'Schnell und wendig mit Blattangriffen und Stürmen!',
bothBosses: 'BEIDE BOSSE',
bothDesc: 'Ultimative Herausforderung - kämpfe gegen beide auf einmal!',
zestyPickle: 'LÄSTIGE TRAUBEN',
grapesDesc: 'Bekämpfe 5 lästige Trauben mit Attitüde!',
mysteryBoss: 'Demnächst',
selectMode: 'MODUS WÄHLEN',
onePlayer: '1 SPIELER',
twoPlayer: '2 SPIELER',
onePlayerDesc: 'Normale Boss-Gesundheit',
twoPlayerDesc: 'Zwei Bananen, geteilter Bildschirm',
selectBullet: 'KUGELTYP WÄHLEN',
normalBullet: 'NORMALE KUGEL',
normalDesc: '5 Schaden, Schnelle Geschwindigkeit',
homingBullet: 'ZIELSUCHENDE KUGEL',
homingDesc: '3 Schaden, Sucht Ziel',
wideBullet: 'BREITE KUGEL',
wideDesc: '10 Schaden, Sehr Langsam',
laserBullet: 'LASER KUGEL',
laserDesc: '1 Schaden, halten zum Angreifen',
laserCooldown: 'warte 1,5 Sekunden zum Feuern',
spreadBullet: 'STREUUNG KUGEL',
spreadDesc: 'Feuert 5 Kugeln, 3 Schaden jede',
iceBullet: 'EIS KUGEL',
iceDesc: '4 Schaden, friert Boss nach 5 Treffern ein',
miscBullet: 'GEMISCHTE KUGEL',
miscDesc: 'Wechselt zwischen allen Kugeltypen',
reverseBullet: 'UMKEHR KUGEL',
reverseDesc: '8 Schaden, schießt rückwärts',
bouncyBullet: 'SPRINGENDE KUGEL',
bouncyDesc: '2 Schaden, prallt von Wänden und Feinden ab',
grenadeBullet: 'GRANATEN KUGEL',
grenadeDesc: '50 Schaden, groß und langsam, 5 Sekunden Abklingzeit',
selectDifficulty: 'SCHWIERIGKEIT WÄHLEN',
simpleDifficulty: 'EINFACH',
simpleDesc: 'Bosse sind langsamer\nund greifen weniger an',
normalDifficulty: 'NORMAL',
achievements: 'ERFOLGE',
achievementUnlocked: 'Erfolge Freigeschaltet: ',
seedyJuicy: 'Kernig und Saftig',
seedyJuicyDesc: 'Besiege die Monster Wassermelone',
horsePineapple: 'Pferd Aber Ananas?',
horsePineappleDesc: 'Besiege das Ananas Pferd',
powerBananas: 'Die Macht der Bananen!',
powerBananasDesc: 'Besiege einen Boss im Zwei-Spieler-Modus',
unlocked: '✓ FREIGESCHALTET',
locked: '✗ GESPERRT',
selected: '✓ AUSGEWÄHLT',
health: 'Leben: ',
invincible: 'Leben: Unverwundbar',
bossHealth: 'Boss Leben: ',
watermelon: 'Wassermelone: ',
pineapple: 'Ananas: ',
grapes: 'Trauben: ',
bigGrape: 'Große Traube: ',
phase1: ' (Phase 1)',
phase2: ' (Phase 2)'
}, "normalDesc", 'Originale Boss\nSchwierigkeit'),
russian: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'ПОБЕДИ МОНСТРА АРБУЗА!',
play: 'ИГРАТЬ',
skins: 'СКИНЫ',
language: 'ЯЗЫК: RU',
languageTitle: 'ЯЗЫК',
english: 'ENGLISH',
spanish: 'ESPAÑOL',
french: 'FRANÇAIS',
portuguese: 'PORTUGUÊS',
german: 'DEUTSCH',
russian: 'РУССКИЙ ✓',
turkish: 'TÜRKÇE',
moreLangs: 'Скоро больше языков!',
back: 'НАЗАД',
skinsTitle: 'СКИНЫ',
comingSoon: 'СКОРО!',
skinDesc: 'Настройте Бананджона с разными\nскинами и внешним видом!',
tuxedoBananjohn: 'БАНАНДЖОН СМОКИНГ',
clownBananjohn: 'БАНАНДЖОН КЛОУН',
studentBananjohn: 'БАНАНДЖОН СТУДЕНТ',
watermelonBananjohn: 'БАНАНДЖОН АРБУЗ',
pineappleBananjohn: 'БАНАНДЖОН АНАНАС',
unlockWatermelon: 'Победите Монстра Арбуза для разблокировки',
unlockPineapple: 'Победите Ананасовую Лошадь для разблокировки',
moreSkins: 'Скоро больше скинов!',
instructions: 'Перетаскивайте Бананджона, чтобы двигаться и избегать атак!\nВыбирайте оружие мудро!',
selectBoss: 'ВЫБРАТЬ БОССА',
monsterWatermelon: 'МОНСТР АРБУЗ',
watermelonDesc: 'Оригинальная угроза! Множество фаз и атак',
pineappleHorse: 'АНАНАСОВАЯ ЛОШАДЬ',
pineappleDesc: 'Быстрая и проворная с атаками листьями и зарядами!',
bothBosses: 'ОБА БОССА',
bothDesc: 'Максимальный вызов - сражайтесь с обоими сразу!',
zestyPickle: 'НАДОЕДЛИВЫЙ ВИНОГРАД',
grapesDesc: 'Сразитесь с 5 надоедливым виноградом с характером!',
mysteryBoss: 'Скоро',
selectMode: 'ВЫБРАТЬ РЕЖИМ',
onePlayer: '1 ИГРОК',
twoPlayer: '2 ИГРОКА',
onePlayerDesc: 'Нормальное здоровье босса',
twoPlayerDesc: 'Две бананы, режим разделённого экрана',
selectBullet: 'ВЫБРАТЬ ТИП ПУЛИ',
normalBullet: 'ОБЫЧНАЯ ПУЛЯ',
normalDesc: '5 Урона, Быстрая Скорость',
homingBullet: 'НАВОДЯЩАЯСЯ ПУЛЯ',
homingDesc: '3 Урона, Ищет Цель',
wideBullet: 'ШИРОКАЯ ПУЛЯ',
wideDesc: '10 Урона, Очень Медленная',
laserBullet: 'ЛАЗЕРНАЯ ПУЛЯ',
laserDesc: '1 урон, удерживайте для атаки',
laserCooldown: 'ждите 1,5 секунды для стрельбы',
spreadBullet: 'РАЗРЫВНАЯ ПУЛЯ',
spreadDesc: 'Стреляет 5 пулями, 3 урона каждая',
iceBullet: 'ЛЕДЯНАЯ ПУЛЯ',
iceDesc: '4 урона, замораживает босса после 5 попаданий',
miscBullet: 'РАЗНООБРАЗНАЯ ПУЛЯ',
miscDesc: 'Переключается между всеми типами пуль',
reverseBullet: 'ОБРАТНАЯ ПУЛЯ',
reverseDesc: '8 урона, стреляет назад',
bouncyBullet: 'ОТСКАКИВАЮЩАЯ ПУЛЯ',
bouncyDesc: '2 урона, отскакивает от стен и врагов',
grenadeBullet: 'ГРАНАТА ПУЛЯ',
grenadeDesc: '50 урона, большая и медленная, 5 секунд перезарядка',
selectDifficulty: 'ВЫБРАТЬ СЛОЖНОСТЬ',
simpleDifficulty: 'ЛЕГКО',
simpleDesc: 'Боссы медленнее\nи атакуют реже',
normalDifficulty: 'ОБЫЧНО',
achievements: 'ДОСТИЖЕНИЯ',
achievementUnlocked: 'Достижений Разблокировано: ',
seedyJuicy: 'Косточковый и Сочный',
seedyJuicyDesc: 'Победите Монстра Арбуза',
horsePineapple: 'Лошадь Но Ананас?',
horsePineappleDesc: 'Победите Ананасовую Лошадь',
powerBananas: 'Сила Бананов!',
powerBananasDesc: 'Победите босса в режиме двух игроков',
unlocked: '✓ РАЗБЛОКИРОВАНО',
locked: '✗ ЗАБЛОКИРОВАНО',
selected: '✓ ВЫБРАНО',
health: 'Здоровье: ',
invincible: 'Здоровье: Неуязвимый',
bossHealth: 'Здоровье Босса: ',
watermelon: 'Арбуз: ',
pineapple: 'Ананас: ',
grapes: 'Виноград: ',
bigGrape: 'Большой Виноград: ',
phase1: ' (Фаза 1)',
phase2: ' (Фаза 2)'
}, "normalDesc", 'Оригинальная\nсложность босса'),
turkish: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'CANAVAR KARPUZU YEN!',
play: 'OYNA',
skins: 'GÖRÜNÜMLER',
language: 'DİL: TR',
languageTitle: 'DİL',
english: 'ENGLISH',
spanish: 'ESPAÑOL',
french: 'FRANÇAIS',
portuguese: 'PORTUGUÊS',
german: 'DEUTSCH',
russian: 'РУССКИЙ',
turkish: 'TÜRKÇE ✓',
moreLangs: 'Yakında daha fazla dil!',
back: 'GERİ',
skinsTitle: 'GÖRÜNÜMLER',
comingSoon: 'YAKINDA!',
skinDesc: 'Bananjohn\'u farklı görünümler\nve stil ile özelleştir!',
tuxedoBananjohn: 'SMOKIN BANANJOHN',
clownBananjohn: 'PALYAÇO BANANJOHN',
studentBananjohn: 'ÖĞRENCİ BANANJOHN',
watermelonBananjohn: 'KARPUZ BANANJOHN',
pineappleBananjohn: 'ANANAS BANANJOHN',
unlockWatermelon: 'Kilidini açmak için Canavar Karpuzu yen',
unlockPineapple: 'Kilidini açmak için Ananas Atı yen',
moreSkins: 'Yakında daha fazla görünüm!',
instructions: 'Bananjohn\'u hareket ettirmek ve saldırıları kaçınmak için sürükle!\nSilahını akıllıca seç!',
selectBoss: 'PATRON SEÇ',
monsterWatermelon: 'CANAVAR KARPUZ',
watermelonDesc: 'Orijinal tehdit! Çoklu evre ve saldırılar',
pineappleHorse: 'ANANAS ATI',
pineappleDesc: 'Yaprak saldırıları ve hücumlarla hızlı ve çevik!',
bothBosses: 'HER İKİ PATRON',
bothDesc: 'Nihai meydan okuma - ikisiyle aynı anda savaş!',
zestyPickle: 'SINIR BOZUCU ÜZÜMLER',
grapesDesc: 'Tavırlı 5 sinir bozucu üzümle savaş!',
mysteryBoss: 'Yakında',
selectMode: 'MOD SEÇ',
onePlayer: '1 OYUNCU',
twoPlayer: '2 OYUNCU',
onePlayerDesc: 'Normal patron canı',
twoPlayerDesc: 'İki muz, bölünmüş ekran modu',
selectBullet: 'MERMI TÜRÜ SEÇ',
normalBullet: 'NORMAL MERMİ',
normalDesc: '5 Hasar, Hızlı Sürat',
homingBullet: 'TAKİP EDİCİ MERMİ',
homingDesc: '3 Hasar, Hedefi Arar',
wideBullet: 'GENİŞ MERMİ',
wideDesc: '10 Hasar, Çok Yavaş',
laserBullet: 'LAZER MERMİ',
laserDesc: '1 hasar, saldırmak için basılı tut',
laserCooldown: 'ateş etmek için 1,5 saniye bekle',
spreadBullet: 'BÖLÜNEN MERMİ',
spreadDesc: '5 mermi atar, her biri 3 hasar',
iceBullet: 'BUZ MERMİ',
iceDesc: '4 hasar, 5 isabetten sonra patronu dondurur',
miscBullet: 'ÇEŞİTLİ MERMİ',
miscDesc: 'Tüm mermi türleri arasında geçiş yapar',
reverseBullet: 'TERS MERMİ',
reverseDesc: '8 hasar, geriye doğru atar',
bouncyBullet: 'ZIPLAYAN MERMİ',
bouncyDesc: '2 hasar, duvarlardan ve düşmanlardan sekiyor',
grenadeBullet: 'BOMBA MERMİ',
grenadeDesc: '50 hasar, büyük ve yavaş, 5 saniye bekleme',
selectDifficulty: 'ZORLUK SEÇ',
simpleDifficulty: 'KOLAY',
simpleDesc: 'Patronlar daha yavaş\nve daha az saldırır',
normalDifficulty: 'NORMAL',
achievements: 'BAŞARILAR',
achievementUnlocked: 'Başarılar Kilidi Açıldı: ',
seedyJuicy: 'Çekirdekli ve Sulu',
seedyJuicyDesc: 'Canavar Karpuzu yen',
horsePineapple: 'At Ama Ananas?',
horsePineappleDesc: 'Ananas Atı yen',
powerBananas: 'Muzların Gücü!',
powerBananasDesc: 'İki oyuncu modunda bir patronu yen',
unlocked: '✓ KİLİDİ AÇILDI',
locked: '✗ KİLİTLİ',
selected: '✓ SEÇİLDİ',
health: 'Can: ',
invincible: 'Can: Yenilmez',
bossHealth: 'Patron Canı: ',
watermelon: 'Karpuz: ',
pineapple: 'Ananas: ',
grapes: 'Üzümler: ',
bigGrape: 'Büyük Üzüm: ',
phase1: ' (Evre 1)',
phase2: ' (Evre 2)'
}, "normalDesc", 'Orijinal patron\nzorluğu')
};
function getText(key) {
return texts[currentLanguage][key] || texts.english[key];
}
// Create language screen
function createLanguageScreen() {
var languageScreen = new Container();
game.addChild(languageScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.9
});
background.tint = 0x001122;
languageScreen.addChild(background);
// Title
var languageTitle = new Text2(getText('languageTitle'), {
size: 150,
fill: 0x4444FF
});
languageTitle.anchor.set(0.5, 0.5);
languageTitle.x = 1024;
languageTitle.y = 600;
languageScreen.addChild(languageTitle);
// English button
var englishButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
englishButton.tint = currentLanguage === 'english' ? 0xFFFF00 : 0xAAAA00;
englishButton.x = 1024;
englishButton.y = 1000;
languageScreen.addChild(englishButton);
var englishText = new Text2('ENGLISH' + (currentLanguage === 'english' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
englishText.anchor.set(0.5, 0.5);
englishText.x = 1024;
englishText.y = 1000;
languageScreen.addChild(englishText);
// Spanish button
var spanishButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
spanishButton.tint = currentLanguage === 'spanish' ? 0xFFFF00 : 0xAAAA00;
spanishButton.x = 1024;
spanishButton.y = 1200;
languageScreen.addChild(spanishButton);
var spanishText = new Text2('ESPAÑOL' + (currentLanguage === 'spanish' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
spanishText.anchor.set(0.5, 0.5);
spanishText.x = 1024;
spanishText.y = 1200;
languageScreen.addChild(spanishText);
// French button
var frenchButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
frenchButton.tint = currentLanguage === 'french' ? 0xFFFF00 : 0xAAAA00;
frenchButton.x = 1024;
frenchButton.y = 1400;
languageScreen.addChild(frenchButton);
var frenchText = new Text2('FRANÇAIS' + (currentLanguage === 'french' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
frenchText.anchor.set(0.5, 0.5);
frenchText.x = 1024;
frenchText.y = 1400;
languageScreen.addChild(frenchText);
// Portuguese button
var portugueseButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
portugueseButton.tint = currentLanguage === 'portuguese' ? 0xFFFF00 : 0xAAAA00;
portugueseButton.x = 1024;
portugueseButton.y = 1600;
languageScreen.addChild(portugueseButton);
var portugueseText = new Text2('PORTUGUÊS' + (currentLanguage === 'portuguese' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
portugueseText.anchor.set(0.5, 0.5);
portugueseText.x = 1024;
portugueseText.y = 1600;
languageScreen.addChild(portugueseText);
// German button
var germanButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
germanButton.tint = currentLanguage === 'german' ? 0xFFFF00 : 0xAAAA00;
germanButton.x = 1024;
germanButton.y = 1800;
languageScreen.addChild(germanButton);
var germanText = new Text2('DEUTSCH' + (currentLanguage === 'german' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
germanText.anchor.set(0.5, 0.5);
germanText.x = 1024;
germanText.y = 1800;
languageScreen.addChild(germanText);
// Russian button
var russianButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
russianButton.tint = currentLanguage === 'russian' ? 0xFFFF00 : 0xAAAA00;
russianButton.x = 1024;
russianButton.y = 2000;
languageScreen.addChild(russianButton);
var russianText = new Text2('РУССКИЙ' + (currentLanguage === 'russian' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
russianText.anchor.set(0.5, 0.5);
russianText.x = 1024;
russianText.y = 2000;
languageScreen.addChild(russianText);
// Turkish button
var turkishButton = LK.getAsset('shape', {
width: 600,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
turkishButton.tint = currentLanguage === 'turkish' ? 0xFFFF00 : 0xAAAA00;
turkishButton.x = 1024;
turkishButton.y = 2200;
languageScreen.addChild(turkishButton);
var turkishText = new Text2('TÜRKÇE' + (currentLanguage === 'turkish' ? ' ✓' : ''), {
size: 80,
fill: 0x000000
});
turkishText.anchor.set(0.5, 0.5);
turkishText.x = 1024;
turkishText.y = 2200;
languageScreen.addChild(turkishText);
// Coming soon message for other languages
var comingSoonText = new Text2(getText('moreLangs'), {
size: 60,
fill: 0xCCCCCC
});
comingSoonText.anchor.set(0.5, 0.5);
comingSoonText.x = 1024;
comingSoonText.y = 2400;
languageScreen.addChild(comingSoonText);
// Back button
var backButton = LK.getAsset('shape', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
backButton.tint = 0x666666;
backButton.x = 1024;
backButton.y = 2600;
languageScreen.addChild(backButton);
var backText = new Text2(getText('back'), {
size: 80,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 2600;
languageScreen.addChild(backText);
// English button event handler
englishButton.down = function (x, y, obj) {
currentLanguage = 'english';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// Spanish button event handler
spanishButton.down = function (x, y, obj) {
currentLanguage = 'spanish';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// French button event handler
frenchButton.down = function (x, y, obj) {
currentLanguage = 'french';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// Portuguese button event handler
portugueseButton.down = function (x, y, obj) {
currentLanguage = 'portuguese';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// German button event handler
germanButton.down = function (x, y, obj) {
currentLanguage = 'german';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// Russian button event handler
russianButton.down = function (x, y, obj) {
currentLanguage = 'russian';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// Turkish button event handler
turkishButton.down = function (x, y, obj) {
currentLanguage = 'turkish';
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
// Back button event handler
backButton.down = function (x, y, obj) {
languageScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
}
// Create achievements screen
function createAchievementsScreen() {
var achievementsScreen = new Container();
game.addChild(achievementsScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.9
});
background.tint = 0x001122;
achievementsScreen.addChild(background);
// Title
var achievementsTitle = new Text2(getText('achievements'), {
size: 150,
fill: 0xFFAA00
});
achievementsTitle.anchor.set(0.5, 0.5);
achievementsTitle.x = 1024;
achievementsTitle.y = 600;
achievementsScreen.addChild(achievementsTitle);
// Achievement 1: Seedy and Juicy
var achievement1Button = LK.getAsset('shape', {
width: 900,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
achievement1Button.tint = achievements.seedy_juicy ? 0x44AA44 : 0x666666;
achievement1Button.x = 1024;
achievement1Button.y = 1000;
achievementsScreen.addChild(achievement1Button);
var achievement1Title = new Text2(getText('seedyJuicy'), {
size: 80,
fill: achievements.seedy_juicy ? 0xFFFFFF : 0xAAAAAA
});
achievement1Title.anchor.set(0.5, 0.5);
achievement1Title.x = 1024;
achievement1Title.y = 970;
achievementsScreen.addChild(achievement1Title);
var achievement1Desc = new Text2(getText('seedyJuicyDesc'), {
size: 50,
fill: achievements.seedy_juicy ? 0xCCCCCC : 0x888888
});
achievement1Desc.anchor.set(0.5, 0.5);
achievement1Desc.x = 1024;
achievement1Desc.y = 1020;
achievementsScreen.addChild(achievement1Desc);
var achievement1Status = new Text2(achievements.seedy_juicy ? getText('unlocked') : getText('locked'), {
size: 40,
fill: achievements.seedy_juicy ? 0x00FF00 : 0xFF4444
});
achievement1Status.anchor.set(0.5, 0.5);
achievement1Status.x = 1024;
achievement1Status.y = 1050;
achievementsScreen.addChild(achievement1Status);
// Achievement 2: Horse But Pineapple?
var achievement2Button = LK.getAsset('shape', {
width: 900,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
achievement2Button.tint = achievements.horse_pineapple ? 0x44AA44 : 0x666666;
achievement2Button.x = 1024;
achievement2Button.y = 1350;
achievementsScreen.addChild(achievement2Button);
var achievement2Title = new Text2(getText('horsePineapple'), {
size: 80,
fill: achievements.horse_pineapple ? 0xFFFFFF : 0xAAAAAA
});
achievement2Title.anchor.set(0.5, 0.5);
achievement2Title.x = 1024;
achievement2Title.y = 1320;
achievementsScreen.addChild(achievement2Title);
var achievement2Desc = new Text2(getText('horsePineappleDesc'), {
size: 50,
fill: achievements.horse_pineapple ? 0xCCCCCC : 0x888888
});
achievement2Desc.anchor.set(0.5, 0.5);
achievement2Desc.x = 1024;
achievement2Desc.y = 1370;
achievementsScreen.addChild(achievement2Desc);
var achievement2Status = new Text2(achievements.horse_pineapple ? getText('unlocked') : getText('locked'), {
size: 40,
fill: achievements.horse_pineapple ? 0x00FF00 : 0xFF4444
});
achievement2Status.anchor.set(0.5, 0.5);
achievement2Status.x = 1024;
achievement2Status.y = 1400;
achievementsScreen.addChild(achievement2Status);
// Achievement 3: The Power of Bananas!
var achievement3Button = LK.getAsset('shape', {
width: 900,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
achievement3Button.tint = achievements.power_bananas ? 0x44AA44 : 0x666666;
achievement3Button.x = 1024;
achievement3Button.y = 1700;
achievementsScreen.addChild(achievement3Button);
var achievement3Title = new Text2(getText('powerBananas'), {
size: 80,
fill: achievements.power_bananas ? 0xFFFFFF : 0xAAAAAA
});
achievement3Title.anchor.set(0.5, 0.5);
achievement3Title.x = 1024;
achievement3Title.y = 1670;
achievementsScreen.addChild(achievement3Title);
var achievement3Desc = new Text2(getText('powerBananasDesc'), {
size: 50,
fill: achievements.power_bananas ? 0xCCCCCC : 0x888888
});
achievement3Desc.anchor.set(0.5, 0.5);
achievement3Desc.x = 1024;
achievement3Desc.y = 1720;
achievementsScreen.addChild(achievement3Desc);
var achievement3Status = new Text2(achievements.power_bananas ? getText('unlocked') : getText('locked'), {
size: 40,
fill: achievements.power_bananas ? 0x00FF00 : 0xFF4444
});
achievement3Status.anchor.set(0.5, 0.5);
achievement3Status.x = 1024;
achievement3Status.y = 1750;
achievementsScreen.addChild(achievement3Status);
// Stats text
var unlockedCount = (achievements.seedy_juicy ? 1 : 0) + (achievements.horse_pineapple ? 1 : 0) + (achievements.power_bananas ? 1 : 0);
var statsText = new Text2(getText('achievementUnlocked') + unlockedCount + '/3', {
size: 60,
fill: 0xFFFFFF
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 1024;
statsText.y = 2000;
achievementsScreen.addChild(statsText);
// Back button
var backButton = LK.getAsset('shape', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
backButton.tint = 0x666666;
backButton.x = 1024;
backButton.y = 2300;
achievementsScreen.addChild(backButton);
var backText = new Text2(getText('back'), {
size: 80,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 2300;
achievementsScreen.addChild(backText);
// Back button event handler
backButton.down = function (x, y, obj) {
achievementsScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
}
// Create skins screen
function createSkinsComingSoonScreen() {
var skinsScreen = new Container();
game.addChild(skinsScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.9
});
background.tint = 0x001122;
skinsScreen.addChild(background);
// Title
var skinsTitle = new Text2(getText('skinsTitle'), {
size: 150,
fill: 0xFF6600
});
skinsTitle.anchor.set(0.5, 0.5);
skinsTitle.x = 1024;
skinsTitle.y = 600;
skinsScreen.addChild(skinsTitle);
// Description
var descriptionText = new Text2(getText('skinDesc'), {
size: 60,
fill: 0xCCCCCC
});
descriptionText.anchor.set(0.5, 0.5);
descriptionText.x = 1024;
descriptionText.y = 800;
skinsScreen.addChild(descriptionText);
// Bananjohn skin button (default/selected)
var bananjohnSkinButton = LK.getAsset('shape', {
width: 600,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
bananjohnSkinButton.tint = 0x4444FF; // Blue for selected
bananjohnSkinButton.x = 1024;
bananjohnSkinButton.y = 1100;
skinsScreen.addChild(bananjohnSkinButton);
// Bananjohn image preview
var bananjohnPreview = LK.getAsset('banana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
bananjohnPreview.x = 1024;
bananjohnPreview.y = 1060;
skinsScreen.addChild(bananjohnPreview);
// Bananjohn name text
var bananjohnText = new Text2('BANANJOHN', {
size: 70,
fill: 0x000000
});
bananjohnText.anchor.set(0.5, 0.5);
bananjohnText.x = 1024;
bananjohnText.y = 1120;
skinsScreen.addChild(bananjohnText);
// Selected indicator
var selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 1150;
skinsScreen.addChild(selectedIndicator);
// Tuxedo Bananjohn skin button
var tuxedoBananjohnSkinButton = LK.getAsset('shape', {
width: 600,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
tuxedoBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
tuxedoBananjohnSkinButton.x = 1024;
tuxedoBananjohnSkinButton.y = 1400;
skinsScreen.addChild(tuxedoBananjohnSkinButton);
// Tuxedo Bananjohn image preview
var tuxedoBananjohnPreview = LK.getAsset('tuxedoBanana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
tuxedoBananjohnPreview.x = 1024;
tuxedoBananjohnPreview.y = 1360;
skinsScreen.addChild(tuxedoBananjohnPreview);
// Tuxedo Bananjohn name text
var tuxedoBananjohnText = new Text2(getText('tuxedoBananjohn'), {
size: 70,
fill: 0x000000
});
tuxedoBananjohnText.anchor.set(0.5, 0.5);
tuxedoBananjohnText.x = 1024;
tuxedoBananjohnText.y = 1420;
skinsScreen.addChild(tuxedoBananjohnText);
// Clown Bananjohn skin button
var clownBananjohnSkinButton = LK.getAsset('shape', {
width: 600,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
clownBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
clownBananjohnSkinButton.x = 1024;
clownBananjohnSkinButton.y = 1700;
skinsScreen.addChild(clownBananjohnSkinButton);
// Clown Bananjohn image preview
var clownBananjohnPreview = LK.getAsset('clownBanana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
clownBananjohnPreview.x = 1024;
clownBananjohnPreview.y = 1660;
skinsScreen.addChild(clownBananjohnPreview);
// Clown Bananjohn name text
var clownBananjohnText = new Text2(getText('clownBananjohn'), {
size: 70,
fill: 0x000000
});
clownBananjohnText.anchor.set(0.5, 0.5);
clownBananjohnText.x = 1024;
clownBananjohnText.y = 1720;
skinsScreen.addChild(clownBananjohnText);
// Student Bananjohn skin button
var studentBananjohnSkinButton = LK.getAsset('shape', {
width: 600,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
studentBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
studentBananjohnSkinButton.x = 1024;
studentBananjohnSkinButton.y = 2000;
skinsScreen.addChild(studentBananjohnSkinButton);
// Student Bananjohn image preview
var studentBananjohnPreview = LK.getAsset('studentBanana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
studentBananjohnPreview.x = 1024;
studentBananjohnPreview.y = 1960;
skinsScreen.addChild(studentBananjohnPreview);
// Student Bananjohn name text
var studentBananjohnText = new Text2(getText('studentBananjohn'), {
size: 70,
fill: 0x000000
});
studentBananjohnText.anchor.set(0.5, 0.5);
studentBananjohnText.x = 1024;
studentBananjohnText.y = 2020;
skinsScreen.addChild(studentBananjohnText);
// Watermelon Bananjohn skin button
var watermelonBananjohnSkinButton = LK.getAsset('shape', {
width: 600,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
watermelonBananjohnSkinButton.tint = unlockedCostumes.watermelon ? 0x2222AA : 0x444444; // Blue if unlocked, gray if locked
watermelonBananjohnSkinButton.x = 1024;
watermelonBananjohnSkinButton.y = 2300;
skinsScreen.addChild(watermelonBananjohnSkinButton);
// Watermelon Bananjohn image preview
var watermelonBananjohnPreview = LK.getAsset('watermelonBanana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
watermelonBananjohnPreview.x = 1024;
watermelonBananjohnPreview.y = 2260;
watermelonBananjohnPreview.tint = unlockedCostumes.watermelon ? 0xFFFFFF : 0x666666; // Gray out if locked
skinsScreen.addChild(watermelonBananjohnPreview);
// Watermelon Bananjohn name text
var watermelonBananjohnText = new Text2('WATERMELON BANANJOHN', {
size: 70,
fill: unlockedCostumes.watermelon ? 0x000000 : 0x666666
});
watermelonBananjohnText.anchor.set(0.5, 0.5);
watermelonBananjohnText.x = 1024;
watermelonBananjohnText.y = 2320;
skinsScreen.addChild(watermelonBananjohnText);
// Watermelon unlock status
var watermelonUnlockText = new Text2(unlockedCostumes.watermelon ? '' : '🔒 Defeat Monster Watermelon to unlock', {
size: 40,
fill: 0xFF4444
});
watermelonUnlockText.anchor.set(0.5, 0.5);
watermelonUnlockText.x = 1024;
watermelonUnlockText.y = 2350;
skinsScreen.addChild(watermelonUnlockText);
// Pineapple Bananjohn skin button
var pineappleBananjohnSkinButton = LK.getAsset('shape', {
width: 600,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
pineappleBananjohnSkinButton.tint = unlockedCostumes.pineapple ? 0x2222AA : 0x444444; // Blue if unlocked, gray if locked
pineappleBananjohnSkinButton.x = 1024;
pineappleBananjohnSkinButton.y = 2600;
skinsScreen.addChild(pineappleBananjohnSkinButton);
// Pineapple Bananjohn image preview
var pineappleBananjohnPreview = LK.getAsset('pineappleBanana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
pineappleBananjohnPreview.x = 1024;
pineappleBananjohnPreview.y = 2560;
pineappleBananjohnPreview.tint = unlockedCostumes.pineapple ? 0xFFFFFF : 0x666666; // Gray out if locked
skinsScreen.addChild(pineappleBananjohnPreview);
// Pineapple Bananjohn name text
var pineappleBananjohnText = new Text2('PINEAPPLE BANANJOHN', {
size: 70,
fill: unlockedCostumes.pineapple ? 0x000000 : 0x666666
});
pineappleBananjohnText.anchor.set(0.5, 0.5);
pineappleBananjohnText.x = 1024;
pineappleBananjohnText.y = 2620;
skinsScreen.addChild(pineappleBananjohnText);
// Pineapple unlock status
var pineappleUnlockText = new Text2(unlockedCostumes.pineapple ? '' : '🔒 Defeat Pineapple Horse to unlock', {
size: 40,
fill: 0xFF4444
});
pineappleUnlockText.anchor.set(0.5, 0.5);
pineappleUnlockText.x = 1024;
pineappleUnlockText.y = 2650;
skinsScreen.addChild(pineappleUnlockText);
// Coming soon skins placeholder
var comingSoonText = new Text2('More skins coming soon!', {
size: 60,
fill: 0x888888
});
comingSoonText.anchor.set(0.5, 0.5);
comingSoonText.x = 1024;
comingSoonText.y = 2700;
skinsScreen.addChild(comingSoonText);
// Back button
var backButton = LK.getAsset('shape', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
backButton.tint = 0x666666;
backButton.x = 1024;
backButton.y = 2680;
skinsScreen.addChild(backButton);
var backText = new Text2(getText('back'), {
size: 80,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 2680;
skinsScreen.addChild(backText);
// Bananjohn skin button event handler (already selected, but can still click)
bananjohnSkinButton.down = function (x, y, obj) {
// Select regular Bananjohn skin
selectedSkin = 'regular';
// Update visual feedback
bananjohnSkinButton.tint = 0x4444FF; // Blue for selected
tuxedoBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
clownBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
studentBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
watermelonBananjohnSkinButton.tint = unlockedCostumes.watermelon ? 0x2222AA : 0x444444;
pineappleBananjohnSkinButton.tint = unlockedCostumes.pineapple ? 0x2222AA : 0x444444;
// Update text indicators
selectedIndicator.destroy();
selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 1150;
skinsScreen.addChild(selectedIndicator);
};
// Tuxedo Bananjohn skin button event handler
tuxedoBananjohnSkinButton.down = function (x, y, obj) {
// Select Tuxedo Bananjohn skin
selectedSkin = 'tuxedo';
// Update visual feedback
bananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
tuxedoBananjohnSkinButton.tint = 0x4444FF; // Blue for selected
clownBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
studentBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
watermelonBananjohnSkinButton.tint = unlockedCostumes.watermelon ? 0x2222AA : 0x444444;
pineappleBananjohnSkinButton.tint = unlockedCostumes.pineapple ? 0x2222AA : 0x444444;
// Update text indicators
selectedIndicator.destroy();
selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 1450;
skinsScreen.addChild(selectedIndicator);
};
// Clown Bananjohn skin button event handler
clownBananjohnSkinButton.down = function (x, y, obj) {
// Select Clown Bananjohn skin
selectedSkin = 'clown';
// Update visual feedback
bananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
tuxedoBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
clownBananjohnSkinButton.tint = 0x4444FF; // Blue for selected
studentBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
watermelonBananjohnSkinButton.tint = unlockedCostumes.watermelon ? 0x2222AA : 0x444444;
pineappleBananjohnSkinButton.tint = unlockedCostumes.pineapple ? 0x2222AA : 0x444444;
// Update text indicators
selectedIndicator.destroy();
selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 1750;
skinsScreen.addChild(selectedIndicator);
};
// Student Bananjohn skin button event handler
studentBananjohnSkinButton.down = function (x, y, obj) {
// Select Student Bananjohn skin
selectedSkin = 'student';
// Update visual feedback
bananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
tuxedoBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
clownBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
studentBananjohnSkinButton.tint = 0x4444FF; // Blue for selected
watermelonBananjohnSkinButton.tint = unlockedCostumes.watermelon ? 0x2222AA : 0x444444;
pineappleBananjohnSkinButton.tint = unlockedCostumes.pineapple ? 0x2222AA : 0x444444;
// Update text indicators
selectedIndicator.destroy();
selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 2050;
skinsScreen.addChild(selectedIndicator);
};
// Watermelon Bananjohn skin button event handler
watermelonBananjohnSkinButton.down = function (x, y, obj) {
if (unlockedCostumes.watermelon) {
// Select Watermelon Bananjohn skin
selectedSkin = 'watermelon';
// Update visual feedback
bananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
tuxedoBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
clownBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
studentBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
watermelonBananjohnSkinButton.tint = 0x4444FF; // Blue for selected
pineappleBananjohnSkinButton.tint = unlockedCostumes.pineapple ? 0x2222AA : 0x444444;
// Update text indicators
selectedIndicator.destroy();
selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 2350;
skinsScreen.addChild(selectedIndicator);
}
};
// Pineapple Bananjohn skin button event handler
pineappleBananjohnSkinButton.down = function (x, y, obj) {
if (unlockedCostumes.pineapple) {
// Select Pineapple Bananjohn skin
selectedSkin = 'pineapple';
// Update visual feedback
bananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
tuxedoBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
clownBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
studentBananjohnSkinButton.tint = 0x2222AA; // Dark blue for unselected
watermelonBananjohnSkinButton.tint = unlockedCostumes.watermelon ? 0x2222AA : 0x444444;
pineappleBananjohnSkinButton.tint = 0x4444FF; // Blue for selected
// Update text indicators
selectedIndicator.destroy();
selectedIndicator = new Text2('✓ SELECTED', {
size: 40,
fill: 0x00FF00
});
selectedIndicator.anchor.set(0.5, 0.5);
selectedIndicator.x = 1024;
selectedIndicator.y = 2650;
skinsScreen.addChild(selectedIndicator);
}
};
// Back button event handler
backButton.down = function (x, y, obj) {
skinsScreen.destroy();
if (gameState === 'mainMenu') {
createMainMenu();
}
};
}
// Create main menu screen
function createMainMenu() {
// Stop any playing music when returning to main menu
LK.stopMusic();
// Play 'Bj' music for main menu directly without any delay
LK.playMusic('Bj');
mainMenu = new Container();
game.addChild(mainMenu);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.9
});
background.tint = 0x001122;
mainMenu.addChild(background);
// Game Title
var gameTitle = new Text2(getText('gameTitle'), {
size: 150,
fill: 0xFFE135
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = 1024;
gameTitle.y = 600;
mainMenu.addChild(gameTitle);
// Subtitle
var subtitle = new Text2(getText('subtitle'), {
size: 80,
fill: 0xFFFFFF
});
subtitle.anchor.set(0.5, 0.5);
subtitle.x = 1024;
subtitle.y = 800;
mainMenu.addChild(subtitle);
// Play Button
var playButton = LK.getAsset('shape', {
width: 500,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
playButton.tint = 0x44FF44;
playButton.x = 1024;
playButton.y = 1200;
mainMenu.addChild(playButton);
var playText = new Text2(getText('play'), {
size: 100,
fill: 0x000000
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 1200;
mainMenu.addChild(playText);
// Instructions
var instructions = new Text2(getText('instructions'), {
size: 60,
fill: 0xCCCCCC
});
instructions.anchor.set(0.5, 0.5);
instructions.x = 1024;
instructions.y = 2100;
mainMenu.addChild(instructions);
// Skins Button
var skinsButton = LK.getAsset('shape', {
width: 500,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
skinsButton.tint = 0x4444FF;
skinsButton.x = 1024;
skinsButton.y = 1400;
mainMenu.addChild(skinsButton);
var skinsText = new Text2(getText('skins'), {
size: 100,
fill: 0x000000
});
skinsText.anchor.set(0.5, 0.5);
skinsText.x = 1024;
skinsText.y = 1400;
mainMenu.addChild(skinsText);
// Achievements Button
var achievementsButton = LK.getAsset('shape', {
width: 500,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
achievementsButton.tint = 0xFFAA00;
achievementsButton.x = 1024;
achievementsButton.y = 1600;
mainMenu.addChild(achievementsButton);
var achievementsText = new Text2(getText('achievements'), {
size: 90,
fill: 0x000000
});
achievementsText.anchor.set(0.5, 0.5);
achievementsText.x = 1024;
achievementsText.y = 1600;
mainMenu.addChild(achievementsText);
// Language Button
var languageButton = LK.getAsset('shape', {
width: 500,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
languageButton.tint = 0xFFFF00;
languageButton.x = 1024;
languageButton.y = 1800;
mainMenu.addChild(languageButton);
var languageText = new Text2(getText('language'), {
size: 80,
fill: 0x000000
});
languageText.anchor.set(0.5, 0.5);
languageText.x = 1024;
languageText.y = 1800;
mainMenu.addChild(languageText);
// Play button event handler
playButton.down = function (x, y, obj) {
gameState = 'bossSelection';
mainMenu.destroy();
mainMenu = null;
createBossSelectionScreen();
};
// Skins button event handler
skinsButton.down = function (x, y, obj) {
// Show coming soon screen for skins
mainMenu.destroy();
mainMenu = null;
createSkinsComingSoonScreen();
};
// Achievements button event handler
achievementsButton.down = function (x, y, obj) {
// Show achievements screen
mainMenu.destroy();
mainMenu = null;
createAchievementsScreen();
};
// Language button event handler
languageButton.down = function (x, y, obj) {
// Show language selection screen
mainMenu.destroy();
mainMenu = null;
createLanguageScreen();
};
}
// Create boss selection screen
function createBossSelectionScreen() {
bossSelectionScreen = new Container();
game.addChild(bossSelectionScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
background.tint = 0x001122;
bossSelectionScreen.addChild(background);
// Title
var bossSelectionTitle = new Text2(getText('selectBoss'), {
size: 120,
fill: 0xFFFFFF
});
bossSelectionTitle.anchor.set(0.5, 0.5);
bossSelectionTitle.x = 1024;
bossSelectionTitle.y = 600;
bossSelectionScreen.addChild(bossSelectionTitle);
// Watermelon Boss button
var watermelonBossButton = LK.getAsset('shape', {
width: 600,
height: 220,
anchorX: 0.5,
anchorY: 0.5
});
watermelonBossButton.tint = 0xFF4444;
watermelonBossButton.x = 1024;
watermelonBossButton.y = 950;
bossSelectionScreen.addChild(watermelonBossButton);
var watermelonText = new Text2(getText('monsterWatermelon'), {
size: 70,
fill: 0xFFFFFF
});
watermelonText.anchor.set(0.5, 0.5);
watermelonText.x = 1024;
watermelonText.y = 925;
bossSelectionScreen.addChild(watermelonText);
var watermelonDesc = new Text2(getText('watermelonDesc'), {
size: 45,
fill: 0xCCCCCC
});
watermelonDesc.anchor.set(0.5, 0.5);
watermelonDesc.x = 1024;
watermelonDesc.y = 975;
bossSelectionScreen.addChild(watermelonDesc);
// Pineapple Horse Boss button
var boss2Button = LK.getAsset('shape', {
width: 600,
height: 220,
anchorX: 0.5,
anchorY: 0.5
});
boss2Button.tint = 0xFFD700;
boss2Button.x = 1024;
boss2Button.y = 1220;
bossSelectionScreen.addChild(boss2Button);
var boss2Text = new Text2(getText('pineappleHorse'), {
size: 70,
fill: 0xFFFFFF
});
boss2Text.anchor.set(0.5, 0.5);
boss2Text.x = 1024;
boss2Text.y = 1195;
bossSelectionScreen.addChild(boss2Text);
var boss2Desc = new Text2(getText('pineappleDesc'), {
size: 45,
fill: 0xCCCCCC
});
boss2Desc.anchor.set(0.5, 0.5);
boss2Desc.x = 1024;
boss2Desc.y = 1245;
bossSelectionScreen.addChild(boss2Desc);
// Annoying Grapes Boss button
var boss3Button = LK.getAsset('shape', {
width: 600,
height: 220,
anchorX: 0.5,
anchorY: 0.5
});
boss3Button.tint = 0x9932CC;
boss3Button.x = 1024;
boss3Button.y = 1490;
bossSelectionScreen.addChild(boss3Button);
var boss3Text = new Text2(getText('zestyPickle'), {
size: 70,
fill: 0xFFFFFF
});
boss3Text.anchor.set(0.5, 0.5);
boss3Text.x = 1024;
boss3Text.y = 1465;
bossSelectionScreen.addChild(boss3Text);
var boss3Desc = new Text2(getText('grapesDesc'), {
size: 45,
fill: 0xCCCCCC
});
boss3Desc.anchor.set(0.5, 0.5);
boss3Desc.x = 1024;
boss3Desc.y = 1515;
bossSelectionScreen.addChild(boss3Desc);
// DJ Apple Boss button
var djAppleButton = LK.getAsset('shape', {
width: 600,
height: 220,
anchorX: 0.5,
anchorY: 0.5
});
djAppleButton.tint = 0xFFD700; // Gold button for DJ Apple
djAppleButton.x = 1024;
djAppleButton.y = 1760;
bossSelectionScreen.addChild(djAppleButton);
var djAppleText = new Text2('DJ APPLE', {
size: 70,
fill: 0xFFFFFF
});
djAppleText.anchor.set(0.5, 0.5);
djAppleText.x = 1024;
djAppleText.y = 1735;
bossSelectionScreen.addChild(djAppleText);
var djAppleDesc = new Text2('3 phases of musical mayhem with disco attacks!', {
size: 45,
fill: 0xCCCCCC
});
djAppleDesc.anchor.set(0.5, 0.5);
djAppleDesc.x = 1024;
djAppleDesc.y = 1785;
bossSelectionScreen.addChild(djAppleDesc);
// DJ Apple button event handler
djAppleButton.down = function (x, y, obj) {
selectedBoss = 'djapple';
gameState = 'bulletSelection';
bossSelectionScreen.destroy();
bossSelectionScreen = null;
createBulletSelectionScreen();
};
// ??? Boss button (mystery boss)
var mysteryBossButton = LK.getAsset('shape', {
width: 600,
height: 220,
anchorX: 0.5,
anchorY: 0.5
});
mysteryBossButton.tint = 0x000000; // Black button
mysteryBossButton.x = 1024;
mysteryBossButton.y = 2030;
bossSelectionScreen.addChild(mysteryBossButton);
var mysteryBossText = new Text2('???', {
size: 100,
fill: 0xFFFFFF
});
mysteryBossText.anchor.set(0.5, 0.5);
mysteryBossText.x = 1024;
mysteryBossText.y = 2005;
bossSelectionScreen.addChild(mysteryBossText);
var mysteryBossDesc = new Text2(getText('mysteryBossDesc') || getText('comingSoon'), {
size: 45,
fill: 0xCCCCCC
});
mysteryBossDesc.anchor.set(0.5, 0.5);
mysteryBossDesc.x = 1024;
mysteryBossDesc.y = 2055;
bossSelectionScreen.addChild(mysteryBossDesc);
// Button event handlers
watermelonBossButton.down = function (x, y, obj) {
selectedBoss = 'watermelon';
gameState = 'bulletSelection';
bossSelectionScreen.destroy();
bossSelectionScreen = null;
createBulletSelectionScreen();
};
boss2Button.down = function (x, y, obj) {
selectedBoss = 'pineapple';
gameState = 'bulletSelection';
bossSelectionScreen.destroy();
bossSelectionScreen = null;
createBulletSelectionScreen();
};
boss3Button.down = function (x, y, obj) {
selectedBoss = 'grapes';
gameState = 'bulletSelection';
bossSelectionScreen.destroy();
bossSelectionScreen = null;
createBulletSelectionScreen();
};
// ??? Boss button event handler - currently unplayable
mysteryBossButton.down = function (x, y, obj) {
// Use translated warning messages if available
var warningMessages = getText('mysteryBossWarnings') || ["No.", "You shouldn't.", "Don't even think about it.", "Not yet.", "Stop trying.", "Nice try.", "Nope.", "Access denied."];
// Get a random warning message
var randomMessage = warningMessages[Math.floor(Math.random() * warningMessages.length)];
// Show warning flash effect with red color
LK.effects.flashScreen(0xFF0000, 1200);
// Create semi-transparent background for better visibility
var warningBackground = LK.getAsset('shape', {
width: 1200,
height: 300,
anchorX: 0.5,
anchorY: 0.5
});
warningBackground.tint = 0x000000;
warningBackground.alpha = 0;
warningBackground.x = 1024;
warningBackground.y = 1366;
bossSelectionScreen.addChild(warningBackground);
// Create warning text that appears on screen
var warningText = new Text2(randomMessage, {
size: 200,
fill: 0xFF0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
warningText.alpha = 0;
bossSelectionScreen.addChild(warningText);
// Animate background appearing
tween(warningBackground, {
alpha: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
// Animate warning text appearing and disappearing
tween(warningText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hold for a moment then fade out
LK.setTimeout(function () {
// Fade out background
tween(warningBackground, {
alpha: 0,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
warningBackground.destroy();
}
});
// Fade out text
tween(warningText, {
alpha: 0,
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
warningText.destroy();
}
});
}, 1500);
}
});
};
}
// Create bullet selection screen
function createBulletSelectionScreen() {
selectionScreen = new Container();
game.addChild(selectionScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
background.tint = 0x000000;
selectionScreen.addChild(background);
// Title
selectionTitle = new Text2(getText('selectBullet'), {
size: 120,
fill: 0xFFFFFF
});
selectionTitle.anchor.set(0.5, 0.5);
selectionTitle.x = 1024;
selectionTitle.y = 400;
selectionScreen.addChild(selectionTitle);
// Normal bullet button
normalBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
normalBulletButton.tint = 0x4444FF;
normalBulletButton.x = 400; // Left side positioning
normalBulletButton.y = 900;
selectionScreen.addChild(normalBulletButton);
var normalText = new Text2(getText('normalBullet'), {
size: 80,
fill: 0xFFFFFF
});
normalText.anchor.set(0.5, 0.5);
normalText.x = 400;
normalText.y = 870;
selectionScreen.addChild(normalText);
var normalDesc = new Text2(getText('normalDesc'), {
size: 50,
fill: 0xCCCCCC
});
normalDesc.anchor.set(0.5, 0.5);
normalDesc.x = 400;
normalDesc.y = 930;
selectionScreen.addChild(normalDesc);
// Homing bullet button
homingBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
homingBulletButton.tint = 0xFF4444;
homingBulletButton.x = 400; // Left side positioning
homingBulletButton.y = 1200;
selectionScreen.addChild(homingBulletButton);
var homingText = new Text2(getText('homingBullet'), {
size: 80,
fill: 0xFFFFFF
});
homingText.anchor.set(0.5, 0.5);
homingText.x = 400;
homingText.y = 1170;
selectionScreen.addChild(homingText);
var homingDesc = new Text2(getText('homingDesc'), {
size: 50,
fill: 0xCCCCCC
});
homingDesc.anchor.set(0.5, 0.5);
homingDesc.x = 400;
homingDesc.y = 1230;
selectionScreen.addChild(homingDesc);
// Wide bullet button
wideBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
wideBulletButton.tint = 0x44FF44;
wideBulletButton.x = 400; // Left side positioning
wideBulletButton.y = 1500;
selectionScreen.addChild(wideBulletButton);
var wideText = new Text2(getText('wideBullet'), {
size: 80,
fill: 0xFFFFFF
});
wideText.anchor.set(0.5, 0.5);
wideText.x = 400;
wideText.y = 1470;
selectionScreen.addChild(wideText);
var wideDesc = new Text2(getText('wideDesc'), {
size: 50,
fill: 0xCCCCCC
});
wideDesc.anchor.set(0.5, 0.5);
wideDesc.x = 400;
wideDesc.y = 1530;
selectionScreen.addChild(wideDesc);
// Button event handlers
normalBulletButton.down = function (x, y, obj) {
selectedBulletType = 'normal';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
homingBulletButton.down = function (x, y, obj) {
selectedBulletType = 'homing';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
wideBulletButton.down = function (x, y, obj) {
selectedBulletType = 'wide';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Laser bullet button
laserBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
laserBulletButton.tint = 0xFF0080;
laserBulletButton.x = 400; // Left side positioning
laserBulletButton.y = 1800;
selectionScreen.addChild(laserBulletButton);
var laserText = new Text2(getText('laserBullet'), {
size: 80,
fill: 0xFFFFFF
});
laserText.anchor.set(0.5, 0.5);
laserText.x = 400;
laserText.y = 1770;
selectionScreen.addChild(laserText);
var laserDesc = new Text2(getText('laserDesc'), {
size: 50,
fill: 0xCCCCCC
});
laserDesc.anchor.set(0.5, 0.5);
laserDesc.x = 400;
laserDesc.y = 1820;
selectionScreen.addChild(laserDesc);
var laserCooldownDesc = new Text2(getText('laserCooldown'), {
size: 40,
fill: 0xFFFFFF
});
laserCooldownDesc.anchor.set(0.5, 0.5);
laserCooldownDesc.x = 400;
laserCooldownDesc.y = 1860;
selectionScreen.addChild(laserCooldownDesc);
laserBulletButton.down = function (x, y, obj) {
selectedBulletType = 'laser';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Spread bullet button
spreadBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
spreadBulletButton.tint = 0xFFAA00;
spreadBulletButton.x = 400; // Left side positioning
spreadBulletButton.y = 2100;
selectionScreen.addChild(spreadBulletButton);
var spreadText = new Text2(getText('spreadBullet'), {
size: 80,
fill: 0xFFFFFF
});
spreadText.anchor.set(0.5, 0.5);
spreadText.x = 400;
spreadText.y = 2070;
selectionScreen.addChild(spreadText);
var spreadDesc = new Text2(getText('spreadDesc'), {
size: 50,
fill: 0xCCCCCC
});
spreadDesc.anchor.set(0.5, 0.5);
spreadDesc.x = 400;
spreadDesc.y = 2130;
selectionScreen.addChild(spreadDesc);
spreadBulletButton.down = function (x, y, obj) {
selectedBulletType = 'spread';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Ice bullet button
var iceBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
iceBulletButton.tint = 0x191970;
iceBulletButton.x = 400; // Left side positioning
iceBulletButton.y = 2400;
selectionScreen.addChild(iceBulletButton);
var iceText = new Text2(getText('iceBullet'), {
size: 80,
fill: 0xFFFFFF
});
iceText.anchor.set(0.5, 0.5);
iceText.x = 400;
iceText.y = 2370;
selectionScreen.addChild(iceText);
var iceDesc = new Text2(getText('iceDesc'), {
size: 50,
fill: 0xCCCCCC
});
iceDesc.anchor.set(0.5, 0.5);
iceDesc.x = 400;
iceDesc.y = 2430;
selectionScreen.addChild(iceDesc);
iceBulletButton.down = function (x, y, obj) {
selectedBulletType = 'ice';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Miscellaneous bullet button
var miscBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
miscBulletButton.tint = 0x9932CC;
miscBulletButton.x = 400; // Left side positioning
miscBulletButton.y = 2700;
selectionScreen.addChild(miscBulletButton);
var miscText = new Text2(getText('miscBullet'), {
size: 70,
fill: 0xFFFFFF
});
miscText.anchor.set(0.5, 0.5);
miscText.x = 400;
miscText.y = 2670;
selectionScreen.addChild(miscText);
var miscDesc = new Text2(getText('miscDesc'), {
size: 50,
fill: 0xCCCCCC
});
miscDesc.anchor.set(0.5, 0.5);
miscDesc.x = 400;
miscDesc.y = 2730;
selectionScreen.addChild(miscDesc);
miscBulletButton.down = function (x, y, obj) {
selectedBulletType = 'miscellaneous';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Reverse bullet button (positioned on the right side)
var reverseBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
reverseBulletButton.tint = 0x800080;
reverseBulletButton.x = 1648; // Right side positioning
reverseBulletButton.y = 900;
selectionScreen.addChild(reverseBulletButton);
var reverseText = new Text2(getText('reverseBullet'), {
size: 70,
fill: 0xFFFFFF
});
reverseText.anchor.set(0.5, 0.5);
reverseText.x = 1648;
reverseText.y = 870;
selectionScreen.addChild(reverseText);
var reverseDesc = new Text2(getText('reverseDesc'), {
size: 45,
fill: 0xCCCCCC
});
reverseDesc.anchor.set(0.5, 0.5);
reverseDesc.x = 1648;
reverseDesc.y = 930;
selectionScreen.addChild(reverseDesc);
reverseBulletButton.down = function (x, y, obj) {
selectedBulletType = 'reverse';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Bouncy bullet button (positioned on the right side)
var bouncyBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
bouncyBulletButton.tint = 0x00FF80;
bouncyBulletButton.x = 1648; // Right side positioning
bouncyBulletButton.y = 1200;
selectionScreen.addChild(bouncyBulletButton);
var bouncyText = new Text2(getText('bouncyBullet'), {
size: 70,
fill: 0xFFFFFF
});
bouncyText.anchor.set(0.5, 0.5);
bouncyText.x = 1648;
bouncyText.y = 1170;
selectionScreen.addChild(bouncyText);
var bouncyDesc = new Text2('2 damage, bounces off walls and enemies', {
size: 45,
fill: 0xCCCCCC
});
bouncyDesc.anchor.set(0.5, 0.5);
bouncyDesc.x = 1648;
bouncyDesc.y = 1230;
selectionScreen.addChild(bouncyDesc);
bouncyBulletButton.down = function (x, y, obj) {
selectedBulletType = 'bouncy';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
// Grenade bullet button (positioned on the right side)
var grenadeBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
grenadeBulletButton.tint = 0x2d4a2d;
grenadeBulletButton.x = 1648; // Right side positioning
grenadeBulletButton.y = 1500;
selectionScreen.addChild(grenadeBulletButton);
var grenadeText = new Text2(getText('grenadeBullet'), {
size: 70,
fill: 0xFFFFFF
});
grenadeText.anchor.set(0.5, 0.5);
grenadeText.x = 1648;
grenadeText.y = 1470;
selectionScreen.addChild(grenadeText);
var grenadeDesc = new Text2(getText('grenadeDesc'), {
size: 45,
fill: 0xCCCCCC
});
grenadeDesc.anchor.set(0.5, 0.5);
grenadeDesc.x = 1648;
grenadeDesc.y = 1530;
selectionScreen.addChild(grenadeDesc);
grenadeBulletButton.down = function (x, y, obj) {
selectedBulletType = 'grenade';
gameState = 'modeSelection';
selectionScreen.destroy();
selectionScreen = null;
createModeSelectionScreen();
};
}
// Create mode selection screen
function createModeSelectionScreen() {
var modeScreen = new Container();
game.addChild(modeScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
background.tint = 0x000000;
modeScreen.addChild(background);
// Title
var modeTitle = new Text2('SELECT MODE', {
size: 120,
fill: 0xFFFF00
});
modeTitle.anchor.set(0.5, 0.5);
modeTitle.x = 1024;
modeTitle.y = 800;
modeScreen.addChild(modeTitle);
// 1 Player button
var onePlayerButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
onePlayerButton.tint = 0x44FF44;
onePlayerButton.x = 1024;
onePlayerButton.y = 1200;
modeScreen.addChild(onePlayerButton);
var onePlayerText = new Text2('1 PLAYER', {
size: 100,
fill: 0x000000
});
onePlayerText.anchor.set(0.5, 0.5);
onePlayerText.x = 1024;
onePlayerText.y = 1170;
modeScreen.addChild(onePlayerText);
var onePlayerDesc = new Text2('Normal boss health', {
size: 60,
fill: 0xCCCCCC
});
onePlayerDesc.anchor.set(0.5, 0.5);
onePlayerDesc.x = 1024;
onePlayerDesc.y = 1230;
modeScreen.addChild(onePlayerDesc);
// 2 Player button
var twoPlayerButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
twoPlayerButton.tint = 0xFF4444;
twoPlayerButton.x = 1024;
twoPlayerButton.y = 1600;
modeScreen.addChild(twoPlayerButton);
var twoPlayerText = new Text2('2 PLAYER', {
size: 100,
fill: 0x000000
});
twoPlayerText.anchor.set(0.5, 0.5);
twoPlayerText.x = 1024;
twoPlayerText.y = 1570;
modeScreen.addChild(twoPlayerText);
var twoPlayerDesc = new Text2('Two bananas, split screen mode', {
size: 60,
fill: 0xCCCCCC
});
twoPlayerDesc.anchor.set(0.5, 0.5);
twoPlayerDesc.x = 1024;
twoPlayerDesc.y = 1630;
modeScreen.addChild(twoPlayerDesc);
// Back button
var backButton = LK.getAsset('shape', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
backButton.tint = 0x666666;
backButton.x = 1024;
backButton.y = 2200;
modeScreen.addChild(backButton);
var backText = new Text2(getText('back'), {
size: 80,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 2200;
modeScreen.addChild(backText);
// Mode button event handlers
onePlayerButton.down = function (x, y, obj) {
selectedMode = '1player';
modeScreen.destroy();
createDifficultySelectionScreen();
};
twoPlayerButton.down = function (x, y, obj) {
selectedMode = '2player';
modeScreen.destroy();
createDifficultySelectionScreen();
};
// Back button event handler
backButton.down = function (x, y, obj) {
gameState = 'bulletSelection';
modeScreen.destroy();
createBulletSelectionScreen();
};
}
// Create difficulty selection screen
function createDifficultySelectionScreen() {
var difficultyScreen = new Container();
game.addChild(difficultyScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
background.tint = 0x000000;
difficultyScreen.addChild(background);
// Title
var difficultyTitle = new Text2(getText('selectDifficulty'), {
size: 120,
fill: 0xFFFF00
});
difficultyTitle.anchor.set(0.5, 0.5);
difficultyTitle.x = 1024;
difficultyTitle.y = 800;
difficultyScreen.addChild(difficultyTitle);
// Simple difficulty button
var simpleButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
simpleButton.tint = 0x44FF44;
simpleButton.x = 1024;
simpleButton.y = 1200;
difficultyScreen.addChild(simpleButton);
var simpleText = new Text2(getText('simpleDifficulty'), {
size: 100,
fill: 0x000000
});
simpleText.anchor.set(0.5, 0.5);
simpleText.x = 1024;
simpleText.y = 1170;
difficultyScreen.addChild(simpleText);
var simpleDesc = new Text2(getText('simpleDesc'), {
size: 60,
fill: 0xCCCCCC
});
simpleDesc.anchor.set(0.5, 0.5);
simpleDesc.x = 1024;
simpleDesc.y = 1230;
difficultyScreen.addChild(simpleDesc);
// Normal difficulty button
var normalButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
normalButton.tint = 0xFF4444;
normalButton.x = 1024;
normalButton.y = 1600;
difficultyScreen.addChild(normalButton);
var normalText = new Text2(getText('normalDifficulty'), {
size: 100,
fill: 0x000000
});
normalText.anchor.set(0.5, 0.5);
normalText.x = 1024;
normalText.y = 1570;
difficultyScreen.addChild(normalText);
var normalDesc = new Text2(getText('normalDesc'), {
size: 60,
fill: 0xCCCCCC
});
normalDesc.anchor.set(0.5, 0.5);
normalDesc.x = 1024;
normalDesc.y = 1630;
difficultyScreen.addChild(normalDesc);
// Back button
var backButton = LK.getAsset('shape', {
width: 400,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
backButton.tint = 0x666666;
backButton.x = 1024;
backButton.y = 2200;
difficultyScreen.addChild(backButton);
var backText = new Text2(getText('back'), {
size: 80,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 2200;
difficultyScreen.addChild(backText);
// Difficulty button event handlers
simpleButton.down = function (x, y, obj) {
selectedDifficulty = 'simple';
difficultyScreen.destroy();
startGame();
};
normalButton.down = function (x, y, obj) {
selectedDifficulty = 'normal';
difficultyScreen.destroy();
startGame();
};
// Back button event handler
backButton.down = function (x, y, obj) {
gameState = 'modeSelection';
difficultyScreen.destroy();
createModeSelectionScreen();
};
}
// Function to unlock achievements
function unlockAchievement(achievementId) {
if (!achievements[achievementId]) {
achievements[achievementId] = true;
storage.achievements = achievements;
// Unlock corresponding costumes
if (achievementId === 'seedy_juicy') {
unlockedCostumes.watermelon = true;
storage.unlockedCostumes = unlockedCostumes;
} else if (achievementId === 'horse_pineapple') {
unlockedCostumes.pineapple = true;
storage.unlockedCostumes = unlockedCostumes;
}
// Show achievement unlocked notification
LK.effects.flashScreen(0xFFD700, 1000);
}
}
function startGame() {
// Stop any currently playing music to prevent carryover
LK.stopMusic();
gameStarted = true;
gameState = 'playing';
if (selectionScreen) {
selectionScreen.destroy();
selectionScreen = null;
}
// Create initial clouds
for (var c = 0; c < 8; c++) {
var cloud = new Cloud();
cloud.x = Math.random() * 2048;
cloud.y = Math.random() * 1000 + 200;
clouds.push(cloud);
game.addChild(cloud);
}
// Initialize game objects
if (selectedMode === '2player') {
// Create two bananas for 2-player mode
banana = game.addChild(new Banana());
banana.x = 200;
banana.y = 683; // Upper half center (2732/4)
upperBanana = banana;
banana2 = game.addChild(new Banana());
banana2.x = 200;
banana2.y = 2049; // Lower half center (3*2732/4)
lowerBanana = banana2;
// Make second banana use a different skin (tuxedo for differentiation)
var currentSkinAsset = lowerBanana.children[0]; // Get the current skin graphic
lowerBanana.removeChild(currentSkinAsset);
var newSkinAsset = lowerBanana.attachAsset('tuxedoBanana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Add visual divider line
var dividerLine = LK.getAsset('shape', {
width: 2048,
height: 4,
anchorX: 0,
anchorY: 0.5
});
dividerLine.tint = 0xFFFFFF;
dividerLine.x = 0;
dividerLine.y = screenDividerY;
game.addChild(dividerLine);
} else {
// Single player mode
banana = game.addChild(new Banana());
banana.x = 200;
banana.y = 1366;
}
// Banana event handler assignment will be added after banana creation
if (selectedBoss === 'watermelon') {
watermelonBoss = game.addChild(new WatermelonBoss());
watermelonBoss.x = 1600;
watermelonBoss.y = 1366;
// Play "Aa" music for Monster Watermelon boss fight
LK.playMusic('Aa');
} else if (selectedBoss === 'pineapple') {
pineappleBoss = game.addChild(new PineappleHorseBoss());
pineappleBoss.x = 1600;
pineappleBoss.y = 1366;
// Play "M3" music for Pineapple Horse boss fight
LK.playMusic('M3');
} else if (selectedBoss === 'grapes') {
grapesBoss = game.addChild(new GrapesBoss());
// Create 5 individual grapes for phase 1
for (var g = 1; g <= 5; g++) {
var grape = new Grape(g);
grape.x = 1400 + (g - 3) * 150; // Spread them out horizontally
grape.y = 1000 + Math.random() * 600; // Random vertical positions
grapes.push(grape);
game.addChild(grape);
}
// Play battle music for grapes
LK.playMusic('battle');
} else if (selectedBoss === 'birds') {
// Initialize bird shooting level
gameInBirdLevel = true;
currentLevelBirds = [];
remainingBirdsCount = 10;
currentBirdNumber = 1;
// Spawn first bird
spawnNextBird();
// Play battle music for bird level
LK.playMusic('battle');
} else if (selectedBoss === 'djapple') {
djAppleBoss = game.addChild(new DJAppleBoss());
djAppleBoss.x = 1600;
djAppleBoss.y = 1366;
// Play DJ song for DJ Apple boss fight
LK.playMusic('DJ');
} else if (selectedBoss === 'both') {
watermelonBoss = game.addChild(new WatermelonBoss());
watermelonBoss.x = 1400;
watermelonBoss.y = 1000;
pineappleBoss = game.addChild(new PineappleHorseBoss());
pineappleBoss.x = 1700;
pineappleBoss.y = 1700;
}
}
// Show main menu screen
createMainMenu();
// UI Elements
var healthBar = new Text2('Health: 100', {
size: 80,
fill: 0xFFFFFF
});
healthBar.anchor.set(0.5, 0);
healthBar.y = 0;
LK.gui.top.addChild(healthBar);
var bossHealthBar = new Text2('Boss Health: 500', {
size: 80,
fill: 0xFF0000
});
bossHealthBar.anchor.set(0.5, 0);
bossHealthBar.y = 90;
LK.gui.top.addChild(bossHealthBar);
var secondBossHealthBar = new Text2('', {
size: 80,
fill: 0xFFD700
});
secondBossHealthBar.anchor.set(0.5, 0);
secondBossHealthBar.y = 180;
LK.gui.top.addChild(secondBossHealthBar);
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
if (selectedMode === '2player') {
// Check if barrier still exists (both players alive)
var barrierExists = upperBanana && lowerBanana && upperBanana.health > 0 && lowerBanana.health > 0;
if (barrierExists) {
// Restrict movement based on which banana is being moved
if (dragNode === upperBanana) {
// Upper banana can only move in upper half (y: 0 to screenDividerY)
dragNode.y = Math.max(50, Math.min(screenDividerY - 50, y));
} else if (dragNode === lowerBanana) {
// Lower banana can only move in lower half (y: screenDividerY to 2732)
dragNode.y = Math.max(screenDividerY + 50, Math.min(2682, y));
} else {
// Fallback to single player behavior
dragNode.y = y;
}
} else {
// Barrier removed - allow full screen movement like single player
dragNode.y = Math.max(50, Math.min(2682, y));
}
} else {
// Single player mode - no restrictions
dragNode.y = y;
}
}
}
game.move = function (x, y, obj) {
if (gameState !== 'playing') return;
handleMove(x, y, obj);
};
game.down = function (x, y, obj) {
if (gameState !== 'playing') return;
mousePressed = true;
if (selectedMode === '2player') {
// Determine which banana to control based on touch position
if (y < screenDividerY) {
// Upper screen touch - control upper banana
if (upperBanana && upperBanana.health > 0) {
dragNode = upperBanana;
}
} else {
// Lower screen touch - control lower banana
if (lowerBanana && lowerBanana.health > 0) {
dragNode = lowerBanana;
}
}
} else {
// Single player mode
dragNode = banana;
}
handleMove(x, y, obj);
holdTimer = 0; // Reset hold timer when mouse is pressed
// Laser activation will be handled in update loop after 1 second hold requirement
// Handle miscellaneous bullet type - determine current bullet type
var actualBulletType = selectedBulletType;
if (selectedBulletType === 'miscellaneous') {
actualBulletType = miscBulletTypes[currentMiscBulletIndex];
// Cycle to next bullet type for next shot
currentMiscBulletIndex = (currentMiscBulletIndex + 1) % miscBulletTypes.length;
}
// Only shoot non-laser bullets on down event
if (actualBulletType !== 'laser') {
// Shoot projectile using the correct banana
var shootingBanana = dragNode || banana;
var canShoot = false;
// Check if the shooting banana is alive
if (shootingBanana && shootingBanana.health > 0) {
if (actualBulletType === 'wide') {
canShoot = wideBulletCooldown <= 0;
} else if (actualBulletType === 'spread') {
canShoot = spreadBulletCooldown <= 0;
} else if (actualBulletType === 'grenade') {
canShoot = grenadeBulletCooldown <= 0;
} else {
canShoot = shootingBanana.shootCooldown <= 0;
}
}
if (canShoot) {
if (actualBulletType === 'spread') {
// Fire 5 spread bullets
for (var spreadIndex = 0; spreadIndex < 5; spreadIndex++) {
var spreadProjectile = new SpreadProjectile();
spreadProjectile.x = shootingBanana.x + 70;
spreadProjectile.y = shootingBanana.y;
// Calculate spread angles: -30, -15, 0, 15, 30 degrees
var spreadAngle = (spreadIndex - 2) * (Math.PI / 6); // 30 degrees in radians
spreadProjectile.angle = spreadAngle;
// Double damage if potion effect is active
if (shootingBanana.potionEffectActive) {
spreadProjectile.damage *= 2;
}
bananaProjectiles.push(spreadProjectile);
game.addChild(spreadProjectile);
}
spreadBulletCooldown = 45; // 0.75 seconds cooldown for spread bullets
} else {
var projectile;
if (actualBulletType === 'homing') {
projectile = new HomingProjectile();
if (selectedBoss === 'watermelon') {
projectile.target = watermelonBoss;
} else if (selectedBoss === 'pineapple') {
projectile.target = pineappleBoss;
} else if (selectedBoss === 'grapes') {
// Target the big grape in phase 2, or find a grape in phase 1
if (grapesBoss && grapesBoss.phase === 2) {
projectile.target = grapesBoss;
} else if (grapes.length > 0) {
// Target the grape with the lowest health for strategic targeting
var targetGrape = grapes[0];
for (var g = 1; g < grapes.length; g++) {
if (grapes[g].health < targetGrape.health) {
targetGrape = grapes[g];
}
}
projectile.target = targetGrape;
}
} else if (selectedBoss === 'both') {
// Target the boss with higher health, or watermelon if equal
if (watermelonBoss.health >= pineappleBoss.health) {
projectile.target = watermelonBoss;
} else {
projectile.target = pineappleBoss;
}
}
} else if (actualBulletType === 'wide') {
projectile = new WideProjectile();
} else if (actualBulletType === 'ice') {
projectile = new IceProjectile();
} else if (actualBulletType === 'reverse') {
projectile = new ReverseProjectile();
} else if (actualBulletType === 'bouncy') {
projectile = new BouncyProjectile();
} else if (actualBulletType === 'grenade') {
projectile = new GrenadeProjectile();
} else {
projectile = new BananaProjectile();
}
// Double damage if potion effect is active
if (shootingBanana.potionEffectActive) {
projectile.damage *= 2;
}
projectile.x = shootingBanana.x + 70;
projectile.y = shootingBanana.y;
bananaProjectiles.push(projectile);
game.addChild(projectile);
if (actualBulletType === 'wide') {
wideBulletCooldown = 60; // 1 second for wide bullets
} else if (actualBulletType === 'grenade') {
grenadeBulletCooldown = 300; // 5 seconds for grenade bullets
} else {
shootingBanana.shootCooldown = 15; // 0.25 seconds for other bullets
}
}
LK.getSound('shoot').play();
}
}
};
game.up = function (x, y, obj) {
if (gameState !== 'playing') return;
mousePressed = false;
dragNode = null;
laserPressUsed = false; // Reset laser press flag when mouse is released
holdTimer = 0; // Reset hold timer when mouse is released
};
// Main game loop
game.update = function () {
if (gameState !== 'playing') return;
// Update wide bullet cooldown
if (wideBulletCooldown > 0) {
wideBulletCooldown--;
}
// Update laser bullet cooldown
if (laserBulletCooldown > 0) {
laserBulletCooldown--;
}
// Update spread bullet cooldown
if (spreadBulletCooldown > 0) {
spreadBulletCooldown--;
}
// Update grenade bullet cooldown
if (grenadeBulletCooldown > 0) {
grenadeBulletCooldown--;
}
// Update laser usage timers
if (laserUsageTimer > 0) {
laserUsageTimer--;
if (laserUsageTimer <= 0) {
laserCanUse = true; // Reset ability to use laser after 1.5 seconds
laserPressUsed = false; // Reset press flag to allow firing again while holding
}
}
if (laserUsageDuration > 0) {
laserUsageDuration--;
if (laserUsageDuration <= 0) {
laserCanUse = false; // Stop laser usage after 0.2 seconds
laserUsageTimer = 90; // Start 1.5 second cooldown (90 ticks at 60fps)
}
}
// Update hold timer when mouse is pressed
if (mousePressed) {
holdTimer++;
// Start laser usage duration when hold timer reaches 1 second (60 ticks) or when laser becomes available again
var shouldActivateLaser = false;
if (selectedBulletType === 'laser') {
shouldActivateLaser = true;
} else if (selectedBulletType === 'miscellaneous' && miscBulletTypes[currentMiscBulletIndex] === 'laser') {
shouldActivateLaser = true;
}
if (shouldActivateLaser && holdTimer >= 60 && laserCanUse && !laserPressUsed) {
laserUsageDuration = 12; // 0.2 seconds at 60fps
laserPressUsed = true; // Mark this press as used
}
}
// Handle laser shooting while mouse is pressed and within usage window (requires 1 second hold)
var shouldFireLaser = false;
if (selectedBulletType === 'laser') {
shouldFireLaser = true;
} else if (selectedBulletType === 'miscellaneous' && miscBulletTypes[currentMiscBulletIndex] === 'laser') {
shouldFireLaser = true;
}
if (shouldFireLaser && mousePressed && holdTimer >= 60 && laserBulletCooldown <= 0 && laserCanUse && laserUsageDuration > 0) {
var shootingBanana = dragNode || banana;
// Only shoot if the banana is alive
if (shootingBanana && shootingBanana.health > 0) {
var projectile = new LaserProjectile();
// Double damage if potion effect is active
if (shootingBanana.potionEffectActive) {
projectile.damage *= 2;
}
projectile.x = shootingBanana.x + 70;
projectile.y = shootingBanana.y;
bananaProjectiles.push(projectile);
game.addChild(projectile);
laserBulletCooldown = 1; // 50 bullets per second (60 FPS / 1 tick = 60 bullets per second, close to 50)
LK.getSound('shoot').play();
}
}
// Update UI - only show health bars when playing
if (gameState === 'playing') {
if (selectedMode === '2player') {
// Show both banana healths
var upperHealth = upperBanana.horseshoeInvincible ? getText('invincible') : getText('health') + upperBanana.health;
var lowerHealth = lowerBanana.horseshoeInvincible ? getText('invincible') : getText('health') + lowerBanana.health;
healthBar.setText('P1: ' + upperHealth + ' | P2: ' + lowerHealth);
} else {
if (banana.horseshoeInvincible) {
healthBar.setText(getText('invincible'));
} else {
healthBar.setText(getText('health') + banana.health);
}
}
if (selectedBoss === 'watermelon') {
var phaseText = watermelonBoss.phase === 4 ? getText('phase2') : '';
bossHealthBar.setText(getText('bossHealth') + watermelonBoss.health + phaseText);
secondBossHealthBar.setText('');
} else if (selectedBoss === 'pineapple') {
var phaseText = pineappleBoss.phase === 2 ? getText('phase2') : '';
bossHealthBar.setText(getText('bossHealth') + pineappleBoss.health + phaseText);
secondBossHealthBar.setText('');
} else if (selectedBoss === 'grapes') {
if (grapesBoss.phase === 1) {
var totalGrapeHealth = 0;
for (var g = 0; g < grapes.length; g++) {
totalGrapeHealth += grapes[g].health;
}
bossHealthBar.setText('Grapes: ' + totalGrapeHealth + ' (Phase 1)');
} else {
var phaseText = grapesBoss.phase === 2 ? ' (Phase 2)' : '';
bossHealthBar.setText('Big Grape: ' + grapesBoss.health + phaseText);
}
secondBossHealthBar.setText('');
} else if (selectedBoss === 'birds') {
if (currentLevelBirds.length > 0) {
var currentBird = currentLevelBirds[0];
bossHealthBar.setText('Bird ' + currentBird.birdNumber + ': ' + currentBird.health);
} else {
bossHealthBar.setText('No bird active');
}
secondBossHealthBar.setText('Birds remaining: ' + (remainingBirdsCount + currentLevelBirds.length));
} else if (selectedBoss === 'djapple') {
var phaseText = ' (Phase ' + djAppleBoss.phase + ')';
bossHealthBar.setText('DJ Apple: ' + djAppleBoss.health + '/' + djAppleBoss.maxHealth + phaseText);
secondBossHealthBar.setText('');
} else if (selectedBoss === 'both') {
var watermelonPhaseText = watermelonBoss.phase === 4 ? getText('phase2') : '';
var pineapplePhaseText = pineappleBoss.phase === 2 ? getText('phase2') : '';
bossHealthBar.setText(getText('watermelon') + watermelonBoss.health + watermelonPhaseText);
secondBossHealthBar.setText(getText('pineapple') + pineappleBoss.health + pineapplePhaseText);
}
} else {
// Hide health bars in main menu
healthBar.setText('');
bossHealthBar.setText('');
secondBossHealthBar.setText('');
}
// Handle banana projectiles
for (var i = bananaProjectiles.length - 1; i >= 0; i--) {
var projectile = bananaProjectiles[i];
// Remove if off screen (check both left and right sides for reverse bullets)
if (projectile.x > 2098 || projectile.x < -50) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
continue;
}
// Check collision with bosses
var hitBoss = false;
if (selectedBoss === 'birds') {
// Check collision with current birds
for (var b = currentLevelBirds.length - 1; b >= 0; b--) {
var bird = currentLevelBirds[b];
if (projectile.intersects(bird)) {
var isIce = projectile instanceof IceProjectile;
bird.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect on bird
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to bird
var knockbackX = bird.x - projectile.x;
var knockbackY = bird.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (120 pixels away from grenade)
var knockbackDistance = 120;
var targetX = bird.x + knockbackX * knockbackDistance;
var targetY = bird.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(100, Math.min(1948, targetX));
targetY = Math.max(100, Math.min(2632, targetY));
// Apply knockback animation using tween
tween(bird, {
x: targetX,
y: targetY
}, {
duration: 250,
easing: tween.easeOut
});
}
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
break;
}
}
} else if (selectedBoss === 'grapes') {
// Check collision with individual grapes in phase 1
for (var g = grapes.length - 1; g >= 0; g--) {
var grape = grapes[g];
if (projectile.intersects(grape)) {
var isIce = projectile instanceof IceProjectile;
grape.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect on individual grape
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to grape
var knockbackX = grape.x - projectile.x;
var knockbackY = grape.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (160 pixels away from grenade)
var knockbackDistance = 160;
var targetX = grape.x + knockbackX * knockbackDistance;
var targetY = grape.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(100, Math.min(1948, targetX));
targetY = Math.max(100, Math.min(2632, targetY));
// Apply knockback animation using tween
tween(grape, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
}
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
break;
}
}
// Check collision with big grape in phase 2
if (!hitBoss && grapesBoss && grapesBoss.phase === 2 && grapesBoss.bigGrapeGraphics && projectile.intersects(grapesBoss)) {
var isIce = projectile instanceof IceProjectile;
grapesBoss.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect on big grape
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to big grape
var knockbackX = grapesBoss.x - projectile.x;
var knockbackY = grapesBoss.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (180 pixels away from grenade)
var knockbackDistance = 180;
var targetX = grapesBoss.x + knockbackX * knockbackDistance;
var targetY = grapesBoss.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(200, Math.min(1848, targetX));
targetY = Math.max(400, Math.min(2300, targetY));
// Apply knockback animation using tween
tween(grapesBoss, {
x: targetX,
y: targetY
}, {
duration: 350,
easing: tween.easeOut
});
}
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else if (selectedBoss === 'watermelon' && projectile.intersects(watermelonBoss)) {
var isIce = projectile instanceof IceProjectile;
watermelonBoss.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to boss
var knockbackX = watermelonBoss.x - projectile.x;
var knockbackY = watermelonBoss.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from grenade)
var knockbackDistance = 200;
var targetX = watermelonBoss.x + knockbackX * knockbackDistance;
var targetY = watermelonBoss.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(150, Math.min(1898, targetX));
targetY = Math.max(300, Math.min(2400, targetY));
// Apply knockback animation using tween
tween(watermelonBoss, {
x: targetX,
y: targetY
}, {
duration: 400,
easing: tween.easeOut
});
}
// Handle bouncy bullet bouncing off boss
if (projectile instanceof BouncyProjectile) {
// Calculate bounce direction
var dx = projectile.x - watermelonBoss.x;
var dy = projectile.y - watermelonBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Reverse direction based on collision angle
if (Math.abs(dx) > Math.abs(dy)) {
projectile.speedX *= -1; // Horizontal bounce
} else {
projectile.speedY *= -1; // Vertical bounce
}
projectile.bounces++;
if (projectile.bounces >= projectile.maxBounces) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else if (selectedBoss === 'pineapple' && projectile.intersects(pineappleBoss)) {
var isIce = projectile instanceof IceProjectile;
pineappleBoss.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to boss
var knockbackX = pineappleBoss.x - projectile.x;
var knockbackY = pineappleBoss.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from grenade)
var knockbackDistance = 200;
var targetX = pineappleBoss.x + knockbackX * knockbackDistance;
var targetY = pineappleBoss.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(150, Math.min(1898, targetX));
targetY = Math.max(300, Math.min(2400, targetY));
// Apply knockback animation using tween
tween(pineappleBoss, {
x: targetX,
y: targetY
}, {
duration: 400,
easing: tween.easeOut
});
}
// Handle bouncy bullet bouncing off boss
if (projectile instanceof BouncyProjectile) {
// Calculate bounce direction
var dx = projectile.x - pineappleBoss.x;
var dy = projectile.y - pineappleBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Reverse direction based on collision angle
if (Math.abs(dx) > Math.abs(dy)) {
projectile.speedX *= -1; // Horizontal bounce
} else {
projectile.speedY *= -1; // Vertical bounce
}
projectile.bounces++;
if (projectile.bounces >= projectile.maxBounces) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else if (selectedBoss === 'djapple' && projectile.intersects(djAppleBoss)) {
var isIce = projectile instanceof IceProjectile;
djAppleBoss.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect
if (projectile instanceof GrenadeProjectile) {
var knockbackX = djAppleBoss.x - projectile.x;
var knockbackY = djAppleBoss.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
var knockbackDistance = 200;
var targetX = djAppleBoss.x + knockbackX * knockbackDistance;
var targetY = djAppleBoss.y + knockbackY * knockbackDistance;
targetX = Math.max(200, Math.min(1848, targetX));
targetY = Math.max(300, Math.min(2400, targetY));
tween(djAppleBoss, {
x: targetX,
y: targetY
}, {
duration: 400,
easing: tween.easeOut
});
}
// Handle bouncy bullet bouncing off boss
if (projectile instanceof BouncyProjectile) {
var dx = projectile.x - djAppleBoss.x;
var dy = projectile.y - djAppleBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
if (Math.abs(dx) > Math.abs(dy)) {
projectile.speedX *= -1; // Horizontal bounce
} else {
projectile.speedY *= -1; // Vertical bounce
}
projectile.bounces++;
if (projectile.bounces >= projectile.maxBounces) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else if (selectedBoss === 'both') {
if (projectile.intersects(watermelonBoss)) {
var isIce = projectile instanceof IceProjectile;
watermelonBoss.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect on watermelon boss
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to watermelon boss
var knockbackX = watermelonBoss.x - projectile.x;
var knockbackY = watermelonBoss.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from grenade)
var knockbackDistance = 200;
var targetX = watermelonBoss.x + knockbackX * knockbackDistance;
var targetY = watermelonBoss.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(150, Math.min(1898, targetX));
targetY = Math.max(300, Math.min(1900, targetY));
// Apply knockback animation using tween
tween(watermelonBoss, {
x: targetX,
y: targetY
}, {
duration: 400,
easing: tween.easeOut
});
}
// Handle bouncy bullet bouncing off boss
if (projectile instanceof BouncyProjectile) {
// Calculate bounce direction
var dx = projectile.x - watermelonBoss.x;
var dy = projectile.y - watermelonBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Reverse direction based on collision angle
if (Math.abs(dx) > Math.abs(dy)) {
projectile.speedX *= -1; // Horizontal bounce
} else {
projectile.speedY *= -1; // Vertical bounce
}
projectile.bounces++;
if (projectile.bounces >= projectile.maxBounces) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else if (projectile.intersects(pineappleBoss)) {
var isIce = projectile instanceof IceProjectile;
pineappleBoss.takeDamage(projectile.damage, isIce);
// Handle grenade knockback effect on pineapple boss
if (projectile instanceof GrenadeProjectile) {
// Calculate knockback direction from grenade to pineapple boss
var knockbackX = pineappleBoss.x - projectile.x;
var knockbackY = pineappleBoss.y - projectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from grenade)
var knockbackDistance = 200;
var targetX = pineappleBoss.x + knockbackX * knockbackDistance;
var targetY = pineappleBoss.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(150, Math.min(1898, targetX));
targetY = Math.max(1800, Math.min(2400, targetY));
// Apply knockback animation using tween
tween(pineappleBoss, {
x: targetX,
y: targetY
}, {
duration: 400,
easing: tween.easeOut
});
}
// Handle bouncy bullet bouncing off boss
if (projectile instanceof BouncyProjectile) {
// Calculate bounce direction
var dx = projectile.x - pineappleBoss.x;
var dy = projectile.y - pineappleBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx = dx / distance;
dy = dy / distance;
}
// Reverse direction based on collision angle
if (Math.abs(dx) > Math.abs(dy)) {
projectile.speedX *= -1; // Horizontal bounce
} else {
projectile.speedY *= -1; // Vertical bounce
}
projectile.bounces++;
if (projectile.bounces >= projectile.maxBounces) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
} else {
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitBoss = true;
}
}
}
if (hitBoss) continue;
// Check collision with thrown pineapples (only for pineapple boss)
if (selectedBoss === 'pineapple') {
var hitPineapple = false;
for (var tp = thrownPineapples.length - 1; tp >= 0; tp--) {
var thrownPineapple = thrownPineapples[tp];
if (projectile.intersects(thrownPineapple)) {
thrownPineapple.takeDamage(projectile.damage);
projectile.destroy();
bananaProjectiles.splice(i, 1);
hitPineapple = true;
break;
}
}
if (hitPineapple) continue;
}
}
// Handle watermelon seeds
for (var j = watermelonSeeds.length - 1; j >= 0; j--) {
var seed = watermelonSeeds[j];
// Remove if off screen
if (seed.x < -50 || seed.x > 2098 || seed.y < -50 || seed.y > 2782) {
seed.destroy();
watermelonSeeds.splice(j, 1);
continue;
}
// Check collision with bananas
var hitBanana = false;
var bananaTargets = selectedMode === '2player' ? [upperBanana, lowerBanana] : [banana];
for (var bt = 0; bt < bananaTargets.length; bt++) {
var currentBanana = bananaTargets[bt];
if (seed.intersects(currentBanana)) {
currentBanana.takeDamage(seed.damage);
// Calculate knockback direction from seed to banana
var knockbackX = currentBanana.x - seed.x;
var knockbackY = currentBanana.y - seed.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (100 pixels away from seed)
var knockbackDistance = 100;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds and banana's allowed area
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
// Apply knockback animation using tween
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 200,
easing: tween.easeOut
});
hitBanana = true;
break;
}
}
if (hitBanana) {
seed.destroy();
watermelonSeeds.splice(j, 1);
continue;
}
}
// Handle watermelon slices
for (var s = watermelonSlices.length - 1; s >= 0; s--) {
var slice = watermelonSlices[s];
// Remove if off screen
if (slice.x < -100 || slice.x > 2148 || slice.y < -100 || slice.y > 2832) {
slice.destroy();
watermelonSlices.splice(s, 1);
continue;
}
// Check collision with bananas
var hitBanana = false;
var bananaTargets = selectedMode === '2player' ? [upperBanana, lowerBanana] : [banana];
for (var bt = 0; bt < bananaTargets.length; bt++) {
var currentBanana = bananaTargets[bt];
if (slice.intersects(currentBanana)) {
currentBanana.takeDamage(slice.damage);
// Calculate knockback direction from slice to banana
var knockbackX = currentBanana.x - slice.x;
var knockbackY = currentBanana.y - slice.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (150 pixels away from slice)
var knockbackDistance = 150;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds and banana's allowed area
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
// Apply knockback animation using tween
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 250,
easing: tween.easeOut
});
hitBanana = true;
break;
}
}
if (hitBanana) {
slice.destroy();
watermelonSlices.splice(s, 1);
continue;
}
}
// Handle watermelon potions
for (var p = watermelonPotions.length - 1; p >= 0; p--) {
var potion = watermelonPotions[p];
// Remove if off screen
if (potion.x < -50 || potion.x > 2098 || potion.y < -50 || potion.y > 2782) {
potion.destroy();
watermelonPotions.splice(p, 1);
continue;
}
// Check collision with bananas
var hitBanana = false;
var bananaTargets = selectedMode === '2player' ? [upperBanana, lowerBanana] : [banana];
for (var bt = 0; bt < bananaTargets.length; bt++) {
var currentBanana = bananaTargets[bt];
if (currentBanana && currentBanana.health > 0 && potion.intersects(currentBanana)) {
currentBanana.activatePotionEffect();
hitBanana = true;
break;
}
}
if (hitBanana) {
potion.destroy();
watermelonPotions.splice(p, 1);
continue;
}
}
// Handle pineapple spears
for (var sp = pineappleSpears.length - 1; sp >= 0; sp--) {
var spear = pineappleSpears[sp];
// Remove if off screen
if (spear.x < -100 || spear.x > 2148 || spear.y < -100 || spear.y > 2832) {
spear.destroy();
pineappleSpears.splice(sp, 1);
continue;
}
// Check collision with banana
if (spear.intersects(banana)) {
banana.takeDamage(spear.damage);
// Calculate knockback direction from spear to banana
var knockbackX = banana.x - spear.x;
var knockbackY = banana.y - spear.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (120 pixels away from spear)
var knockbackDistance = 120;
var targetX = banana.x + knockbackX * knockbackDistance;
var targetY = banana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(50, Math.min(1998, targetX));
targetY = Math.max(50, Math.min(2682, targetY));
// Apply knockback animation using tween
tween(banana, {
x: targetX,
y: targetY
}, {
duration: 220,
easing: tween.easeOut
});
spear.destroy();
pineappleSpears.splice(sp, 1);
continue;
}
}
// Handle thrown pineapples
for (var tp = thrownPineapples.length - 1; tp >= 0; tp--) {
var thrownPineapple = thrownPineapples[tp];
// Remove if off screen
if (thrownPineapple.x < -100 || thrownPineapple.x > 2148 || thrownPineapple.y < -100 || thrownPineapple.y > 2832) {
thrownPineapple.destroy();
thrownPineapples.splice(tp, 1);
continue;
}
// Check collision with banana (if pineapple hits banana directly)
if (thrownPineapple.intersects(banana)) {
banana.takeDamage(25); // Direct pineapple hit damage
// Calculate knockback direction from thrown pineapple to banana
var knockbackX = banana.x - thrownPineapple.x;
var knockbackY = banana.y - thrownPineapple.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (180 pixels away from pineapple)
var knockbackDistance = 180;
var targetX = banana.x + knockbackX * knockbackDistance;
var targetY = banana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(50, Math.min(1998, targetX));
targetY = Math.max(50, Math.min(2682, targetY));
// Apply knockback animation using tween
tween(banana, {
x: targetX,
y: targetY
}, {
duration: 280,
easing: tween.easeOut
});
thrownPineapple.explode(); // Still explode into slices
continue;
}
}
// Handle pineapple slices
for (var ps = pineappleSlices.length - 1; ps >= 0; ps--) {
var slice = pineappleSlices[ps];
// Remove if off screen
if (slice.x < -100 || slice.x > 2148 || slice.y < -100 || slice.y > 2832) {
slice.destroy();
pineappleSlices.splice(ps, 1);
continue;
}
// Check collision with banana
if (slice.intersects(banana)) {
banana.takeDamage(slice.damage);
// Calculate knockback direction from slice to banana
var knockbackX = banana.x - slice.x;
var knockbackY = banana.y - slice.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = 1;
knockbackY = 0;
}
// Calculate knockback destination (130 pixels away from slice)
var knockbackDistance = 130;
var targetX = banana.x + knockbackX * knockbackDistance;
var targetY = banana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds
targetX = Math.max(50, Math.min(1998, targetX));
targetY = Math.max(50, Math.min(2682, targetY));
// Apply knockback animation using tween
tween(banana, {
x: targetX,
y: targetY
}, {
duration: 240,
easing: tween.easeOut
});
slice.destroy();
pineappleSlices.splice(ps, 1);
continue;
}
}
// Handle DJ Apple projectiles
for (var dj = djAppleProjectiles.length - 1; dj >= 0; dj--) {
var djProjectile = djAppleProjectiles[dj];
// Remove if off screen
if (djProjectile.x < -100 || djProjectile.x > 2148 || djProjectile.y < -100 || djProjectile.y > 2832) {
djProjectile.destroy();
djAppleProjectiles.splice(dj, 1);
continue;
}
// Check collision with bananas
var hitBanana = false;
var bananaTargets = selectedMode === '2player' ? [upperBanana, lowerBanana] : [banana];
for (var bt = 0; bt < bananaTargets.length; bt++) {
var currentBanana = bananaTargets[bt];
if (currentBanana && currentBanana.health > 0 && djProjectile.intersects(currentBanana)) {
currentBanana.takeDamage(djProjectile.damage);
// Calculate knockback
var knockbackX = currentBanana.x - djProjectile.x;
var knockbackY = currentBanana.y - djProjectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
var knockbackDistance = djProjectile instanceof DiscoBall ? 150 : 100;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: djProjectile instanceof DiscoBall ? 250 : 180,
easing: tween.easeOut
});
hitBanana = true;
break;
}
}
if (hitBanana) {
djProjectile.destroy();
djAppleProjectiles.splice(dj, 1);
continue;
}
}
// Handle grape projectiles
for (var gp = grapeProjectiles.length - 1; gp >= 0; gp--) {
var grapeProjectile = grapeProjectiles[gp];
// Remove if off screen
if (grapeProjectile.x < -50 || grapeProjectile.x > 2098 || grapeProjectile.y < -50 || grapeProjectile.y > 2782) {
grapeProjectile.destroy();
grapeProjectiles.splice(gp, 1);
continue;
}
// Check collision with bananas
var hitBanana = false;
var bananaTargets = selectedMode === '2player' ? [upperBanana, lowerBanana] : [banana];
for (var bt = 0; bt < bananaTargets.length; bt++) {
var currentBanana = bananaTargets[bt];
if (currentBanana && currentBanana.health > 0 && grapeProjectile.intersects(currentBanana)) {
currentBanana.takeDamage(grapeProjectile.damage);
// Calculate knockback
var knockbackX = currentBanana.x - grapeProjectile.x;
var knockbackY = currentBanana.y - grapeProjectile.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = 1;
knockbackY = 0;
}
var knockbackDistance = 80;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 180,
easing: tween.easeOut
});
hitBanana = true;
break;
}
}
if (hitBanana) {
grapeProjectile.destroy();
grapeProjectiles.splice(gp, 1);
continue;
}
}
// Handle horseshoes
for (var hs = horseshoes.length - 1; hs >= 0; hs--) {
var horseshoe = horseshoes[hs];
// Remove if off screen
if (horseshoe.x < -100 || horseshoe.x > 2148 || horseshoe.y < -100 || horseshoe.y > 2832) {
horseshoe.destroy();
horseshoes.splice(hs, 1);
continue;
}
// Check collision with banana
if (horseshoe.intersects(banana)) {
banana.activateHorseshoeInvincibility();
// Add sparkle effect with tween animation
tween(horseshoe, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
horseshoe.destroy();
}
});
horseshoes.splice(hs, 1);
continue;
}
}
// Check collision between bananas and bosses
var bananaTargets = selectedMode === '2player' ? [upperBanana, lowerBanana] : [banana];
for (var bt = 0; bt < bananaTargets.length; bt++) {
var currentBanana = bananaTargets[bt];
if (selectedBoss === 'watermelon' && currentBanana.intersects(watermelonBoss)) {
currentBanana.takeDamage(30);
// Calculate knockback direction from boss to banana
var knockbackX = currentBanana.x - watermelonBoss.x;
var knockbackY = currentBanana.y - watermelonBoss.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = -1; // Push away from boss (towards left)
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from boss)
var knockbackDistance = 200;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds and banana's allowed area
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
// Apply knockback animation using tween
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
} else if (selectedBoss === 'pineapple' && currentBanana.intersects(pineappleBoss)) {
currentBanana.takeDamage(35);
// Calculate knockback direction from boss to banana
var knockbackX = currentBanana.x - pineappleBoss.x;
var knockbackY = currentBanana.y - pineappleBoss.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = -1; // Push away from boss (towards left)
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from boss)
var knockbackDistance = 200;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds and banana's allowed area
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
// Apply knockback animation using tween
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
} else if (selectedBoss === 'birds') {
// Check collision with current birds
for (var b = 0; b < currentLevelBirds.length; b++) {
var bird = currentLevelBirds[b];
if (currentBanana.intersects(bird)) {
currentBanana.takeDamage(20 + bird.birdNumber * 2); // Damage increases with bird number
// Calculate knockback from bird to banana
var knockbackX = currentBanana.x - bird.x;
var knockbackY = currentBanana.y - bird.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = -1;
knockbackY = 0;
}
var knockbackDistance = 130 + bird.birdNumber * 10; // Knockback increases with bird number
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 200 + bird.birdNumber * 10,
easing: tween.easeOut
});
}
}
} else if (selectedBoss === 'grapes') {
// Check collision with individual grapes
for (var g = 0; g < grapes.length; g++) {
var grape = grapes[g];
if (currentBanana.intersects(grape)) {
currentBanana.takeDamage(25);
// Calculate knockback
var knockbackX = currentBanana.x - grape.x;
var knockbackY = currentBanana.y - grape.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = -1;
knockbackY = 0;
}
var knockbackDistance = 150;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 280,
easing: tween.easeOut
});
}
}
// Check collision with big grape in phase 2
if (grapesBoss && grapesBoss.phase === 2 && grapesBoss.bigGrapeGraphics && currentBanana.intersects(grapesBoss)) {
currentBanana.takeDamage(40);
// Calculate knockback from big grape
var knockbackX = currentBanana.x - grapesBoss.x;
var knockbackY = currentBanana.y - grapesBoss.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = -1;
knockbackY = 0;
}
var knockbackDistance = 250;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 350,
easing: tween.easeOut
});
}
} else if (selectedBoss === 'djapple' && currentBanana.intersects(djAppleBoss)) {
currentBanana.takeDamage(25 + djAppleBoss.phase * 5); // More damage in later phases
// Calculate knockback direction from DJ Apple to banana
var knockbackX = currentBanana.x - djAppleBoss.x;
var knockbackY = currentBanana.y - djAppleBoss.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
knockbackX = -1; // Push away from boss (towards left)
knockbackY = 0;
}
var knockbackDistance = 180 + djAppleBoss.phase * 20; // More knockback in later phases
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 280,
easing: tween.easeOut
});
} else if (selectedBoss === 'both') {
if (currentBanana.intersects(watermelonBoss)) {
currentBanana.takeDamage(30);
// Calculate knockback direction from watermelon boss to banana
var knockbackX = currentBanana.x - watermelonBoss.x;
var knockbackY = currentBanana.y - watermelonBoss.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = -1; // Push away from boss (towards left)
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from boss)
var knockbackDistance = 200;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds and banana's allowed area
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
// Apply knockback animation using tween
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
} else if (currentBanana.intersects(pineappleBoss)) {
currentBanana.takeDamage(35);
// Calculate knockback direction from pineapple boss to banana
var knockbackX = currentBanana.x - pineappleBoss.x;
var knockbackY = currentBanana.y - pineappleBoss.y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
// Normalize the knockback vector
if (distance > 0) {
knockbackX = knockbackX / distance;
knockbackY = knockbackY / distance;
} else {
// Default direction if objects are at exact same position
knockbackX = -1; // Push away from boss (towards left)
knockbackY = 0;
}
// Calculate knockback destination (200 pixels away from boss)
var knockbackDistance = 200;
var targetX = currentBanana.x + knockbackX * knockbackDistance;
var targetY = currentBanana.y + knockbackY * knockbackDistance;
// Clamp target position within screen bounds and banana's allowed area
targetX = Math.max(50, Math.min(1998, targetX));
if (selectedMode === '2player') {
if (currentBanana === upperBanana) {
targetY = Math.max(50, Math.min(screenDividerY - 50, targetY));
} else {
targetY = Math.max(screenDividerY + 50, Math.min(2682, targetY));
}
} else {
targetY = Math.max(50, Math.min(2682, targetY));
}
// Apply knockback animation using tween
tween(currentBanana, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
}
}
}
// Check bird level victory condition
if (selectedBoss === 'birds' && gameInBirdLevel) {
if (currentLevelBirds.length === 0 && remainingBirdsCount === 0) {
// All birds defeated - show victory
gameInBirdLevel = false;
LK.stopMusic();
tween(banana, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
}
}
// Spawn new clouds occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
var newCloud = new Cloud();
newCloud.x = 2248;
newCloud.y = Math.random() * 1000 + 200;
clouds.push(newCloud);
game.addChild(newCloud);
}
// Clean up clouds that are too far off screen
for (var k = clouds.length - 1; k >= 0; k--) {
var cloud = clouds[k];
if (cloud.x < -300) {
cloud.destroy();
clouds.splice(k, 1);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -3011,25 +3011,25 @@
/****
* Game Code
****/
-// Game variables
-// Character assets
-// Projectile assets
-// Sound effects
-// Music
-// Brown
-// Orange
-// Teal
-// Sky Blue
-// Mint Green
-// Yellow
-// Pink
-// Dark Pink
-// Purple
-// Dark Gray
-// Triangle shape for waves (using triangle approximation)
// Triangle-shaped wave projectile
+// Triangle shape for waves (using triangle approximation)
+// Dark Gray
+// Purple
+// Dark Pink
+// Pink
+// Yellow
+// Mint Green
+// Sky Blue
+// Teal
+// Orange
+// Brown
+// Music
+// Sound effects
+// Projectile assets
+// Character assets
+// Game variables
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
@@ -4610,9 +4610,9 @@
// Create main menu screen
function createMainMenu() {
// Stop any playing music when returning to main menu
LK.stopMusic();
- // Play 'Bj' music for main menu
+ // Play 'Bj' music for main menu directly without any delay
LK.playMusic('Bj');
mainMenu = new Container();
game.addChild(mainMenu);
// Semi-transparent background