User prompt
The fake Bananjohn should not attack itself, but should be facing the player.
User prompt
Create a new boss called Fake Banajohn, which attacks with existing weapons in the game and looks the same as Bananjohn.
User prompt
Make a new boss named Fake Bananjohn this boss looks the same as Bananjohn and has the same attacks.
User prompt
Horseshoes should be rarer.
User prompt
As long as the Banana is invincible, the Banana's health should read "Invincible".
User prompt
The banana must be blue in color while it is immortal. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
The Pineapple Horse throws a horseshoe as a new attack type. This horseshoe renders the player invincible for 5 seconds. However, the Pineapple Horse rarely uses this attack. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Fix the bug where the Pineapple Horse reverted to its previous size in phase 2. (It should be larger in the 2nd phase.)
User prompt
Fix a bug where the Pineapple Horse was red in Phase 2.
User prompt
Pineapple Horse should be a new asset when it moves to Phase 2
User prompt
Ice bullet should be give 3 damage
User prompt
Froze should be 0,80 sec. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
MakeMake the bullet selection buttons far away from each other. And make Ice bullet dark blue.
User prompt
Add a new bullet called Ice bullet, this bullet freezes a boss by 0.5 for 5 shots. (All 5 of the 5 fires must touch the boss.) The frozen boss turns blue. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make it 1,7 seconds
User prompt
Pineapple Throw must make a spear attack every 2 seconds in Phase 2
User prompt
Make it 10 on the phase 2
User prompt
Make it 5.5
User prompt
Pineapple Horse's Spears should be slower
User prompt
Make spread bullets bigger
User prompt
Make homing bullet's size same as normal bullet
User prompt
It doesn't work.
User prompt
Make it for all divided slices. βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Do it
User prompt
Slices from a watermelon's splitting attack should also knockbacked βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Banana = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('banana', {
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.takeDamage = function (damage) {
if (self.invulnerable) 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) {
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.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
self.tint = 0xFFFFFF;
}
}
};
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 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 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 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) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
if (self.health <= 0) {
if (self.phase < 2) {
// If not in final phase yet, 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 = 60; // 1 second at 60fps for faster spear attacks
self.moveSpeed = 3.5; // Even faster movement
// Change tint to indicate phase change - darker orange for phase 2
graphics.tint = 0xFF4500; // Red-orange for phase 2
// 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 {
// 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();
}
});
}
}
};
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.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 () {
// Only move when not charging
if (!self.isCharging) {
// Circular movement pattern
self.y += self.moveDirection * self.moveSpeed;
if (self.y <= 300 || self.y >= 2400) {
self.moveDirection *= -1;
}
// Add horizontal movement in figure-8 pattern
self.x += Math.sin(LK.ticks * 0.02) * 1.5;
}
// Update charge cooldown
if (self.chargeAttackCooldown > 0) {
self.chargeAttackCooldown--;
}
// Attack logic
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
var attackChoice = Math.random();
if (attackChoice < 0.2 && self.chargeAttackCooldown <= 0) {
// Charge attack (20% chance)
self.chargeAttack();
} else if (attackChoice < 0.3) {
// Pineapple throw attack (10% chance - reduced from 30%)
self.pineappleThrowAttack();
} else {
// Spear attack (70% chance - increased from 50%)
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 = 8; // 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;
self.x += dirX * self.seekSpeed;
self.y += dirY * self.seekSpeed;
// 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 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) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// 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 (self.phase < 4) {
// If not in final phase yet
// 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 {
// 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();
}
});
}
}
};
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 () {
// Movement - both vertical and horizontal
self.y += self.moveDirection * self.moveSpeed;
self.x += self.moveDirection * self.moveSpeed * 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++;
if (self.attackTimer >= self.attackCooldown) {
// 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
****/
// Game variables
// Character assets
// Projectile assets
// Sound effects
// Music
var banana;
var watermelonBoss;
var pineappleBoss;
var bananaProjectiles = [];
var watermelonSeeds = [];
var watermelonSlices = [];
var watermelonPotions = [];
var pineappleSpears = [];
var thrownPineapples = [];
var pineappleSlices = [];
var clouds = [];
var dragNode = null;
// Game state variables
var gameState = 'mainMenu'; // 'mainMenu', 'bossSelection', 'bulletSelection', 'playing'
var mainMenu = null;
var bossSelectionScreen = null;
var selectedBoss = 'watermelon'; // 'watermelon', 'boss2', 'boss3', etc.
// Bullet selection variables
var gameStarted = false;
var selectedBulletType = 'normal'; // 'normal', 'homing', 'wide', 'laser', or 'spread'
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 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']; // Array of bullet types for miscellaneous
var currentMiscBulletIndex = 0; // Index to track current bullet type in miscellaneous mode
// Create main menu screen
function createMainMenu() {
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('BANANJOHN', {
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('DEFEAT THE MONSTER WATERMELON!', {
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('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('Drag Bananjohn to move and avoid attacks!\nChoose your weapon wisely!', {
size: 60,
fill: 0xCCCCCC
});
instructions.anchor.set(0.5, 0.5);
instructions.x = 1024;
instructions.y = 1500;
mainMenu.addChild(instructions);
// Play button event handler
playButton.down = function (x, y, obj) {
gameState = 'bossSelection';
mainMenu.destroy();
mainMenu = null;
createBossSelectionScreen();
};
}
// 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('SELECT BOSS', {
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('MONSTER WATERMELON', {
size: 80,
fill: 0xFFFFFF
});
watermelonText.anchor.set(0.5, 0.5);
watermelonText.x = 1024;
watermelonText.y = 970;
bossSelectionScreen.addChild(watermelonText);
var watermelonDesc = new Text2('The original menace! Multiple phases and attacks', {
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('PINEAPPLE HORSE', {
size: 80,
fill: 0xFFFFFF
});
boss2Text.anchor.set(0.5, 0.5);
boss2Text.x = 1024;
boss2Text.y = 1370;
bossSelectionScreen.addChild(boss2Text);
var boss2Desc = new Text2('Fast and agile with spear attacks and charges!', {
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 = 0x666666;
boss3Button.x = 1024;
boss3Button.y = 1800;
bossSelectionScreen.addChild(boss3Button);
var boss3Text = new Text2('MEGA ORANGE', {
size: 80,
fill: 0x888888
});
boss3Text.anchor.set(0.5, 0.5);
boss3Text.x = 1024;
boss3Text.y = 1770;
bossSelectionScreen.addChild(boss3Text);
var boss3Desc = new Text2('Coming Soon!', {
size: 50,
fill: 0x888888
});
boss3Desc.anchor.set(0.5, 0.5);
boss3Desc.x = 1024;
boss3Desc.y = 1830;
bossSelectionScreen.addChild(boss3Desc);
// 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) {
// Do nothing - coming soon
};
}
// 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('SELECT BULLET TYPE', {
size: 120,
fill: 0xFFFFFF
});
selectionTitle.anchor.set(0.5, 0.5);
selectionTitle.x = 1024;
selectionTitle.y = 600;
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 = 1024;
normalBulletButton.y = 1000;
selectionScreen.addChild(normalBulletButton);
var normalText = new Text2('NORMAL BULLET', {
size: 80,
fill: 0xFFFFFF
});
normalText.anchor.set(0.5, 0.5);
normalText.x = 1024;
normalText.y = 970;
selectionScreen.addChild(normalText);
var normalDesc = new Text2('5 Damage, Fast Speed', {
size: 50,
fill: 0xCCCCCC
});
normalDesc.anchor.set(0.5, 0.5);
normalDesc.x = 1024;
normalDesc.y = 1030;
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 = 1024;
homingBulletButton.y = 1300;
selectionScreen.addChild(homingBulletButton);
var homingText = new Text2('HOMING BULLET', {
size: 80,
fill: 0xFFFFFF
});
homingText.anchor.set(0.5, 0.5);
homingText.x = 1024;
homingText.y = 1270;
selectionScreen.addChild(homingText);
var homingDesc = new Text2('3 Damage, Seeks Target', {
size: 50,
fill: 0xCCCCCC
});
homingDesc.anchor.set(0.5, 0.5);
homingDesc.x = 1024;
homingDesc.y = 1360;
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 = 1024;
wideBulletButton.y = 1600;
selectionScreen.addChild(wideBulletButton);
var wideText = new Text2('WIDE BULLET', {
size: 80,
fill: 0xFFFFFF
});
wideText.anchor.set(0.5, 0.5);
wideText.x = 1024;
wideText.y = 1570;
selectionScreen.addChild(wideText);
var wideDesc = new Text2('10 Damage, Very Slow', {
size: 50,
fill: 0xCCCCCC
});
wideDesc.anchor.set(0.5, 0.5);
wideDesc.x = 1024;
wideDesc.y = 1630;
selectionScreen.addChild(wideDesc);
// Button event handlers
normalBulletButton.down = function (x, y, obj) {
selectedBulletType = 'normal';
startGame();
};
homingBulletButton.down = function (x, y, obj) {
selectedBulletType = 'homing';
startGame();
};
wideBulletButton.down = function (x, y, obj) {
selectedBulletType = 'wide';
startGame();
};
// Laser bullet button
laserBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
laserBulletButton.tint = 0xFF0080;
laserBulletButton.x = 1024;
laserBulletButton.y = 1900;
selectionScreen.addChild(laserBulletButton);
var laserText = new Text2('LASER BULLET', {
size: 80,
fill: 0xFFFFFF
});
laserText.anchor.set(0.5, 0.5);
laserText.x = 1024;
laserText.y = 1870;
selectionScreen.addChild(laserText);
var laserDesc = new Text2('1 damage, hold for attack', {
size: 50,
fill: 0xCCCCCC
});
laserDesc.anchor.set(0.5, 0.5);
laserDesc.x = 1024;
laserDesc.y = 1920;
selectionScreen.addChild(laserDesc);
var laserCooldownDesc = new Text2('wait 1.5 seconds to fire', {
size: 40,
fill: 0xFFFFFF
});
laserCooldownDesc.anchor.set(0.5, 0.5);
laserCooldownDesc.x = 1024;
laserCooldownDesc.y = 1960;
selectionScreen.addChild(laserCooldownDesc);
laserBulletButton.down = function (x, y, obj) {
selectedBulletType = 'laser';
startGame();
};
// Spread bullet button
spreadBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
spreadBulletButton.tint = 0xFFAA00;
spreadBulletButton.x = 1024;
spreadBulletButton.y = 2200;
selectionScreen.addChild(spreadBulletButton);
var spreadText = new Text2('SPREAD BULLET', {
size: 80,
fill: 0xFFFFFF
});
spreadText.anchor.set(0.5, 0.5);
spreadText.x = 1024;
spreadText.y = 2170;
selectionScreen.addChild(spreadText);
var spreadDesc = new Text2('Fires 5 bullets, 3 damage each', {
size: 50,
fill: 0xCCCCCC
});
spreadDesc.anchor.set(0.5, 0.5);
spreadDesc.x = 1024;
spreadDesc.y = 2230;
selectionScreen.addChild(spreadDesc);
spreadBulletButton.down = function (x, y, obj) {
selectedBulletType = 'spread';
startGame();
};
// Miscellaneous bullet button
var miscBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
miscBulletButton.tint = 0x9932CC;
miscBulletButton.x = 1024;
miscBulletButton.y = 2500;
selectionScreen.addChild(miscBulletButton);
var miscText = new Text2('MISCELLANEOUS BULLET', {
size: 70,
fill: 0xFFFFFF
});
miscText.anchor.set(0.5, 0.5);
miscText.x = 1024;
miscText.y = 2470;
selectionScreen.addChild(miscText);
var miscDesc = new Text2('Cycles through all bullet types', {
size: 50,
fill: 0xCCCCCC
});
miscDesc.anchor.set(0.5, 0.5);
miscDesc.x = 1024;
miscDesc.y = 2530;
selectionScreen.addChild(miscDesc);
miscBulletButton.down = function (x, y, obj) {
selectedBulletType = 'miscellaneous';
startGame();
};
}
function startGame() {
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
banana = game.addChild(new Banana());
banana.x = 200;
banana.y = 1366;
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 "Aa" music for Pineapple Horse boss fight
LK.playMusic('Aa');
}
}
// 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);
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// No movement restrictions - banana can move freely anywhere
}
}
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;
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
var canShoot = false;
if (actualBulletType === 'wide') {
canShoot = wideBulletCooldown <= 0;
} else if (actualBulletType === 'spread') {
canShoot = spreadBulletCooldown <= 0;
} else {
canShoot = banana.shootCooldown <= 0;
}
if (canShoot) {
if (actualBulletType === 'spread') {
// Fire 5 spread bullets
for (var spreadIndex = 0; spreadIndex < 5; spreadIndex++) {
var spreadProjectile = new SpreadProjectile();
spreadProjectile.x = banana.x + 70;
spreadProjectile.y = banana.y;
// Calculate spread angles: -30, -15, 0, 15, 30 degrees
var spreadAngle = (spreadIndex - 2) * (Math.PI / 6); // 30 degrees in radians
spreadProjectile.angle = spreadAngle;
// Check if potion effect is active
if (banana.potionEffectActive) {
spreadProjectile.enhanced = true;
spreadProjectile.damage = spreadProjectile.damage * 3; // Enhanced damage
spreadProjectile.scaleX = 1.5; // Make projectile bigger
spreadProjectile.scaleY = 1.5;
spreadProjectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
bananaProjectiles.push(spreadProjectile);
game.addChild(spreadProjectile);
}
spreadBulletCooldown = 45; // 0.75 seconds cooldown for spread bullets
} else {
var projectile;
if (actualBulletType === 'homing') {
projectile = new HomingProjectile();
projectile.target = selectedBoss === 'watermelon' ? watermelonBoss : pineappleBoss;
} else if (actualBulletType === 'wide') {
projectile = new WideProjectile();
} else {
projectile = new BananaProjectile();
}
projectile.x = banana.x + 70;
projectile.y = banana.y;
// Check if potion effect is active
if (banana.potionEffectActive) {
projectile.enhanced = true;
projectile.damage = projectile.damage * 3; // Enhanced damage
projectile.scaleX = 1.5; // Make projectile bigger
projectile.scaleY = 1.5;
projectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
bananaProjectiles.push(projectile);
game.addChild(projectile);
if (actualBulletType === 'wide') {
wideBulletCooldown = 60; // 1 second for wide bullets
} else {
banana.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 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 projectile = new LaserProjectile();
projectile.x = banana.x + 70;
projectile.y = banana.y;
// Check if potion effect is active
if (banana.potionEffectActive) {
projectile.enhanced = true;
projectile.damage = projectile.damage * 3; // Enhanced damage
projectile.scaleX = 1.5; // Make projectile bigger
projectile.scaleY = 1.5;
projectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
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
healthBar.setText('Health: ' + banana.health);
if (selectedBoss === 'watermelon') {
var phaseText = watermelonBoss.phase === 4 ? ' (Phase 2)' : '';
bossHealthBar.setText('Boss Health: ' + watermelonBoss.health + phaseText);
} else if (selectedBoss === 'pineapple') {
var phaseText = pineappleBoss.phase === 2 ? ' (Phase 2)' : '';
bossHealthBar.setText('Boss Health: ' + pineappleBoss.health + phaseText);
}
// Handle banana projectiles
for (var i = bananaProjectiles.length - 1; i >= 0; i--) {
var projectile = bananaProjectiles[i];
// Remove if off screen
if (projectile.x > 2098) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
continue;
}
// Check collision with boss
var currentBoss = selectedBoss === 'watermelon' ? watermelonBoss : pineappleBoss;
if (projectile.intersects(currentBoss)) {
currentBoss.takeDamage(projectile.damage);
projectile.destroy();
bananaProjectiles.splice(i, 1);
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 banana
if (seed.intersects(banana)) {
banana.takeDamage(seed.damage);
// Calculate knockback direction from seed to banana
var knockbackX = banana.x - seed.x;
var knockbackY = banana.y - seed.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 (100 pixels away from seed)
var knockbackDistance = 100;
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: 200,
easing: tween.easeOut
});
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 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;
}
// Calculate knockback destination (150 pixels away from slice)
var knockbackDistance = 150;
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: 250,
easing: tween.easeOut
});
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 banana
if (potion.intersects(banana)) {
banana.activatePotionEffect();
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;
}
// 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;
}
// 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;
}
// 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;
}
}
// Check collision between banana and current boss
var currentBoss = selectedBoss === 'watermelon' ? watermelonBoss : pineappleBoss;
if (banana.intersects(currentBoss)) {
// Deal damage to banana
var damage = selectedBoss === 'watermelon' ? 30 : 35;
banana.takeDamage(damage);
// Calculate knockback direction from boss to banana
var knockbackX = banana.x - currentBoss.x;
var knockbackY = banana.y - currentBoss.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 (200 pixels away from boss)
var knockbackDistance = 200;
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: 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);
}
}
};
// Start battle music
LK.playMusic('battle'); ===================================================================
--- original.js
+++ change.js
@@ -1085,13 +1085,13 @@
/****
* Game Code
****/
-// Music
-// Sound effects
-// Projectile assets
-// Character assets
// Game variables
+// Character assets
+// Projectile assets
+// Sound effects
+// Music
var banana;
var watermelonBoss;
var pineappleBoss;
var bananaProjectiles = [];