User prompt
??? Fix boss and DJ Apple's buttons getting mixed up for a better look Arrange the boss buttons one under the other so none of them touch each other but there are no long gaps between them.
User prompt
Delete Bird shooting from the boss selection menu.
User prompt
Delete bird shooting
User prompt
BOSS NAME: DJ Apple PHASES: 3 HP PER PHASE: 300 (Total 900) ⸻ PHASE 1 — Warm-Up Attacks • Slow straight music note bullets • Small low-damage sound wave circles Visuals • Calm face • Soft colored DJ lights (blue/pink) • Turntable spinning at normal speed ⸻ PHASE 2 — Remix Mode Attacks • Fast and denser note bullets • Vinyl discs that can bounce from walls • Medium-radius sound waves • Small speaker minions spawn Visuals • Headband lights brighter • Cracked shell details • Background lights shift to purple/green tones ⸻ PHASE 3 — Final Drop Attacks • Huge disco ball attack (slow, large hitbox, high damage) • Fast multi-directional bullet hell note rain • Wide-area high-power sound blast • Chaotic bouncing vinyl discs Visuals • Strong red/black lights and sparks • Turntable spinning at extreme speed • Angry facial expression • Chaotic animated background ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Boss buttons should be far away from each other and not touch each other
User prompt
Birds should have their own private assets and not use Annoying Grapes' assets.
User prompt
Annoying Grapes and ??? The buttons should not touch each other and create a bird asset, also the birds should shoot triangle shaped waves instead of bullets and as the birds get closer to the end it should be much harder and faster. Additionally, birds should be able to make a dash attack starting from the 3rd bird. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Annoying Grapes and ??? The buttons should not touch each other and create a bird asset, also the birds should shoot triangle shaped waves instead of bullets and as the birds get closer to the end it should be much harder and faster. Additionally, birds should be able to make a dash attack starting from the 3rd bird. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Boss buttons should be far away from each other and not touch each other.
User prompt
Add a new level. Unlike the boss, in this level 10 different birds come in a row and each bird has a different attack and the next bird cannot come until one bird dies and how many birds are left is shown on the screen, the birds become more difficult until the last bird. So the birds are getting more and more difficult. The name of the level is bird shooting and each bird has 100 lives, and again before the level the bullet selection screen appears. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Translate missing translations in all available languages: (Achievements, Annoying Grapes' description, ??? boss's "coming soon" text, ??? boss's button-pressing warnings.)
User prompt
Translate everything that is not translated into all languages.
User prompt
The "Bj" music should play when you're in the main menu.
User prompt
When the player takes Monster Watermelon's potions, its damage is doubled.
User prompt
Fix a bug that Monster Watermelon’s potions are not working.
User prompt
Warnings must be visible to the user
User prompt
"???" When the boss's button is pressed, "No." appears on the screen. "You shouldn't." Warnings like this should appear.
User prompt
Add a boss named “???” and make the button black. It is currently unplayable and it says "coming soon" underneath.
User prompt
Make it 500 again.
User prompt
Make Big Grape harder and stronger.
User prompt
Fix a bug that Homing bullet is not working on Annoying Grapes.
User prompt
Make granade bigger ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Grenade should knockback the enemies. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Craft a new bullet called Grenade, this bullet is large and deals 50 damage and can be used every 5 seconds
User prompt
Craft a new bullet called Grenade, this bullet is large and deals 50 damage and can be used every 5 seconds
/****
* 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 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 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 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 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 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
****/
// 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 grapes = [];
var grapeProjectiles = [];
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'
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',
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',
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',
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',
health: 'Health: ',
invincible: 'Health: Invincible',
bossHealth: 'Boss Health: ',
watermelon: 'Watermelon: ',
pineapple: 'Pineapple: ',
phase2: ' (Phase 2)',
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'
}, "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: 'SPANISH ✓',
french: 'FRENCH',
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',
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',
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',
health: 'Salud: ',
invincible: 'Salud: Invencible',
bossHealth: 'Salud del Jefe: ',
watermelon: 'Sandía: ',
pineapple: 'Piña: ',
phase2: ' (Fase 2)',
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'
}, "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: 'SPANISH',
french: 'FRENCH ✓',
portuguese: 'PORTUGUESE',
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',
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',
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',
health: 'Santé: ',
invincible: 'Santé: Invincible',
bossHealth: 'Santé du Boss: ',
watermelon: 'Pastèque: ',
pineapple: 'Ananas: ',
phase2: ' (Phase 2)',
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'
}, "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: 'SPANISH',
french: 'FRENCH',
portuguese: 'PORTUGUESE ✓',
german: 'GERMAN',
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',
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últiples 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',
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',
health: 'Vida: ',
invincible: 'Vida: Invencível',
bossHealth: 'Vida do Chefe: ',
watermelon: 'Melancia: ',
pineapple: 'Abacaxi: ',
phase2: ' (Fase 2)',
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'
}, "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: 'SPANISH',
french: 'FRENCH',
portuguese: 'PORTUGUESE',
german: 'DEUTSCH ✓',
russian: 'RUSSIAN',
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',
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',
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',
health: 'Leben: ',
invincible: 'Leben: Unverwundbar',
bossHealth: 'Boss Leben: ',
watermelon: 'Wassermelone: ',
pineapple: 'Ananas: ',
phase2: ' (Phase 2)',
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'
}, "normalDesc", 'Originale Boss\nSchwierigkeit'),
russian: _defineProperty({
gameTitle: 'BANANJOHN',
subtitle: 'ПОБЕДИ МОНСТРА АРБУЗА!',
play: 'ИГРАТЬ',
skins: 'СКИНЫ',
language: 'ЯЗЫК: RU',
languageTitle: 'ЯЗЫК',
english: 'ENGLISH',
spanish: 'SPANISH',
french: 'FRENCH',
portuguese: 'PORTUGUESE',
german: 'GERMAN',
russian: 'РУССКИЙ ✓',
turkish: 'TURKISH',
moreLangs: 'Скоро больше языков!',
back: 'НАЗАД',
skinsTitle: 'СКИНЫ',
comingSoon: 'СКОРО!',
skinDesc: 'Настройте Бананджона с разными\nскинами и внешним видом!',
tuxedoBananjohn: 'БАНАНДЖОН СМОКИНГ',
clownBananjohn: 'БАНАНДЖОН КЛОУН',
studentBananjohn: 'БАНАНДЖОН СТУДЕНТ',
instructions: 'Перетаскивайте Бананджона, чтобы двигаться и избегать атак!\nВыбирайте оружие мудро!',
selectBoss: 'ВЫБРАТЬ БОССА',
monsterWatermelon: 'МОНСТР АРБУЗ',
watermelonDesc: 'Оригинальная угроза! Множество фаз и атак',
pineappleHorse: 'АНАНАСОВАЯ ЛОШАДЬ',
pineappleDesc: 'Быстрая и проворная с атаками листьями и зарядами!',
bothBosses: 'ОБА БОССА',
bothDesc: 'Максимальный вызов - сражайтесь с обоими сразу!',
zestyPickle: 'НАДОЕДЛИВЫЙ ВИНОГРАД',
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: 'Переключается между всеми типами пуль',
health: 'Здоровье: ',
invincible: 'Здоровье: Неуязвимый',
bossHealth: 'Здоровье Босса: ',
watermelon: 'Арбуз: ',
pineapple: 'Ананас: ',
phase2: ' (Фаза 2)',
reverseBullet: 'ОБРАТНАЯ ПУЛЯ',
reverseDesc: '8 урона, стреляет назад',
bouncyBullet: 'ОТСКАКИВАЮЩАЯ ПУЛЯ',
bouncyDesc: '2 урона, отскакивает от стен и врагов',
grenadeBullet: 'ГРАНАТА ПУЛЯ',
grenadeDesc: '50 урона, большая и медленная, 5 секунд перезарядка',
selectDifficulty: 'ВЫБРАТЬ СЛОЖНОСТЬ',
simpleDifficulty: 'ЛЕГКО',
simpleDesc: 'Боссы медленнее\nи атакуют реже',
normalDifficulty: 'ОБЫЧНО',
achievements: 'ДОСТИЖЕНИЯ'
}, "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: 'SPANISH',
french: 'FRENCH',
portuguese: 'PORTUGUESE',
german: 'GERMAN',
russian: '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',
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',
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',
health: 'Can: ',
invincible: 'Can: Yenilmez',
bossHealth: 'Patron Canı: ',
watermelon: 'Karpuz: ',
pineapple: 'Ananas: ',
phase2: ' (Evre 2)',
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'
}, "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('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('Seedy and Juicy', {
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('Defeat the Monster Watermelon', {
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 ? '✓ UNLOCKED' : '✗ 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('Horse But Pineapple?', {
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('Defeat the Pineapple Horse', {
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 ? '✓ UNLOCKED' : '✗ 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('The Power of Bananas!', {
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('Defeat a boss in two-player mode', {
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 ? '✓ UNLOCKED' : '✗ 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('Achievements Unlocked: ' + 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();
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: 700,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
watermelonBossButton.tint = 0xFF4444;
watermelonBossButton.x = 1024;
watermelonBossButton.y = 1000;
bossSelectionScreen.addChild(watermelonBossButton);
var watermelonText = new Text2(getText('monsterWatermelon'), {
size: 80,
fill: 0xFFFFFF
});
watermelonText.anchor.set(0.5, 0.5);
watermelonText.x = 1024;
watermelonText.y = 970;
bossSelectionScreen.addChild(watermelonText);
var watermelonDesc = new Text2(getText('watermelonDesc'), {
size: 50,
fill: 0xCCCCCC
});
watermelonDesc.anchor.set(0.5, 0.5);
watermelonDesc.x = 1024;
watermelonDesc.y = 1030;
bossSelectionScreen.addChild(watermelonDesc);
// Coming Soon Boss 2 button
var boss2Button = LK.getAsset('shape', {
width: 700,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
boss2Button.tint = 0xFFD700;
boss2Button.x = 1024;
boss2Button.y = 1400;
bossSelectionScreen.addChild(boss2Button);
var boss2Text = new Text2(getText('pineappleHorse'), {
size: 80,
fill: 0xFFFFFF
});
boss2Text.anchor.set(0.5, 0.5);
boss2Text.x = 1024;
boss2Text.y = 1370;
bossSelectionScreen.addChild(boss2Text);
var boss2Desc = new Text2(getText('pineappleDesc'), {
size: 50,
fill: 0xCCCCCC
});
boss2Desc.anchor.set(0.5, 0.5);
boss2Desc.x = 1024;
boss2Desc.y = 1430;
bossSelectionScreen.addChild(boss2Desc);
// Coming Soon Boss 3 button
var boss3Button = LK.getAsset('shape', {
width: 700,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
boss3Button.tint = 0x9932CC;
boss3Button.x = 1024;
boss3Button.y = 1800;
bossSelectionScreen.addChild(boss3Button);
var boss3Text = new Text2(getText('zestyPickle'), {
size: 80,
fill: 0xFFFFFF
});
boss3Text.anchor.set(0.5, 0.5);
boss3Text.x = 1024;
boss3Text.y = 1770;
bossSelectionScreen.addChild(boss3Text);
var boss3Desc = new Text2('Face 5 annoying grapes with attitude!', {
size: 50,
fill: 0xCCCCCC
});
boss3Desc.anchor.set(0.5, 0.5);
boss3Desc.x = 1024;
boss3Desc.y = 1830;
bossSelectionScreen.addChild(boss3Desc);
// ??? Boss button (black)
var mysteryBossButton = LK.getAsset('shape', {
width: 700,
height: 250,
anchorX: 0.5,
anchorY: 0.5
});
mysteryBossButton.tint = 0x000000; // Black button
mysteryBossButton.x = 1024;
mysteryBossButton.y = 2200;
bossSelectionScreen.addChild(mysteryBossButton);
var mysteryBossText = new Text2('???', {
size: 120,
fill: 0xFFFFFF
});
mysteryBossText.anchor.set(0.5, 0.5);
mysteryBossText.x = 1024;
mysteryBossText.y = 2170;
bossSelectionScreen.addChild(mysteryBossText);
var mysteryBossDesc = new Text2('Coming Soon', {
size: 50,
fill: 0xCCCCCC
});
mysteryBossDesc.anchor.set(0.5, 0.5);
mysteryBossDesc.x = 1024;
mysteryBossDesc.y = 2230;
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) {
// Array of warning messages
var warningMessages = ["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 === '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;
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();
}
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();
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 === '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 === '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 === '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 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 === '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 === '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
});
}
}
}
// 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
@@ -2094,13 +2094,13 @@
/****
* Game Code
****/
-// Game variables
-// Character assets
-// Projectile assets
-// Sound effects
// 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;
@@ -3774,42 +3774,74 @@
var warningMessages = ["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, 800);
+ 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: 150,
+ 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.2,
- scaleY: 1.2
+ scaleX: 1.3,
+ scaleY: 1.3
}, {
- duration: 300,
+ 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.8,
- scaleY: 0.8
+ scaleX: 0.7,
+ scaleY: 0.7
}, {
- duration: 500,
+ duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
warningText.destroy();
}
});
- }, 1000);
+ }, 1500);
}
});
};
}