User prompt
Add soda
User prompt
Add energy drinks
User prompt
The boombox music constantly gets replaced by the default music whenever a new boss spawns.
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'gameInventory[itemId] = {' Line Number: 908 โช๐ก Consider importing and using the following plugins: @upit/storage.v1
User prompt
They spawn just out of reach
User prompt
Spawn them into the next boss instead of the current to ensure availability
User prompt
Add a inventory system โช๐ก Consider importing and using the following plugins: @upit/storage.v1
User prompt
Fix Goosandra spawning to always spawn when Glen is above 0 health and the spawner is clicked
User prompt
The basic Battle theme keeps playing
User prompt
Add new music. You choose what and where.
User prompt
Add a starting cutscene โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now add a guide button which tells you how to play, each boss and subtle hints for Easter eggs.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
self.maxHealth = 100;
self.health = self.maxHealth;
self.attackCooldown = 0;
self.movePattern = 0;
self.speed = 2;
self.damage = 10;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
LK.getSound('bossHit').play();
if (self.health <= 0) {
self.health = 0;
self.onDefeat();
}
};
self.onDefeat = function () {
LK.getSound('bossDefeat').play();
bossDefeated = true;
LK.setScore(LK.getScore() + 100 * currentBossLevel);
};
return self;
});
var Goosandra = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('viggen', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x800080; // Purple tint for Goosandra
graphics.scaleX = 8; // Make Goosandra much larger
graphics.scaleY = 8; // Make Goosandra much larger
self.maxHealth = 1000;
self.health = self.maxHealth;
self.speed = 4;
self.secretPhase = 1;
self.phaseTimer = 0;
self.update = function () {
self.phaseTimer++;
if (self.secretPhase == 1) {
// Phase 1: Chaotic movement
self.x += Math.sin(self.phaseTimer * 0.03) * 4;
self.y += Math.cos(self.phaseTimer * 0.02) * 2;
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.chaosAttack();
self.attackCooldown = 25;
}
if (self.health < self.maxHealth * 0.6) {
self.secretPhase = 2;
self.phaseTimer = 0;
}
} else if (self.secretPhase == 2) {
// Phase 2: Ultimate chaos
self.x += Math.sin(self.phaseTimer * 0.05) * 6;
self.y += Math.cos(self.phaseTimer * 0.04) * 3;
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.ultimateAttack();
self.attackCooldown = 25;
}
}
};
self.chaosAttack = function () {
// Spiral chaos shot
for (var i = 0; i < 6; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 6 * Math.PI * 2 + self.phaseTimer * 0.1;
bullet.targetX = self.x + Math.cos(angle) * 800;
bullet.targetY = self.y + Math.sin(angle) * 800;
bossBullets.push(bullet);
game.addChild(bullet);
}
// Add 1 Viggen every chaos attack
for (var j = 0; j < 1; j++) {
var viggen = getPooledViggen();
viggen.x = self.x + (j - 0.5) * 100;
viggen.y = self.y + 80;
viggen.velocityX = (Math.random() - 0.5) * 2;
viggen.velocityY = Math.random() * 2 + 1;
viggen.lifetime = 300;
viggens.push(viggen);
game.addChild(viggen);
}
};
self.ultimateAttack = function () {
// Ultimate chaos burst
for (var i = 0; i < 12; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 12 * Math.PI * 2 + self.phaseTimer * 0.2;
bullet.targetX = self.x + Math.cos(angle) * 900;
bullet.targetY = self.y + Math.sin(angle) * 900;
bossBullets.push(bullet);
game.addChild(bullet);
}
// Random laser bursts
if (self.phaseTimer % 120 == 0) {
for (var j = 0; j < 2; j++) {
var laser = new BossLaser();
laser.x = 200 + Math.random() * 1648;
laser.y = 0;
bossLasers.push(laser);
game.addChild(laser);
}
}
// Add 2 Viggens during ultimate attack
for (var k = 0; k < 2; k++) {
var viggen = getPooledViggen();
viggen.x = self.x + (k - 0.5) * 80;
viggen.y = self.y + 100;
viggen.velocityX = (Math.random() - 0.5) * 3;
viggen.velocityY = Math.random() * 3 + 2;
viggen.lifetime = 300;
viggens.push(viggen);
game.addChild(viggen);
}
};
self.onDefeat = function () {
LK.getSound('bossDefeat').play();
LK.setScore(LK.getScore() + 2000);
secretBossDefeated = true;
storage.secretBossDefeated = true;
// Update Glen's lore text if currently viewing boss 2
if (currentBossLevel == 2) {
bossLoreText.setText(getBossLore(2));
}
// Dramatic defeat cutscene
LK.effects.flashScreen(0x800080, 2000);
// Spin and shrink effect
tween(self, {
rotation: Math.PI * 8,
scaleX: 0,
scaleY: 0
}, {
duration: 2000,
easing: tween.easeIn
});
// Fade out all UI elements dramatically
tween(levelText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossNameText, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossHealthBar, {
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 1500,
easing: tween.easeIn
});
tween(healthBar, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 1500,
easing: tween.easeIn
});
tween(instructionText, {
alpha: 0,
y: instructionText.y + 100
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossGuideText, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossLoreText, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeIn
});
// Restore UI after 2 seconds
LK.setTimeout(function () {
// Restore all UI elements with bounce-in effect
tween(levelText, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossNameText, {
alpha: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossHealthBar, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(healthBar, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(instructionText, {
alpha: 1,
y: instructionText.y - 100
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossGuideText, {
alpha: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossLoreText, {
alpha: 1
}, {
duration: 800,
easing: tween.bounceOut
});
}, 2000);
// Wait for dramatic effect before showing win
LK.setTimeout(function () {
LK.showYouWin();
}, 2500);
};
return self;
});
var FinalBoss = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('finalBoss', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 800;
self.health = self.maxHealth;
self.phase = 1;
self.phaseTimer = 0;
self.speed = 2;
self.update = function () {
self.phaseTimer++;
if (self.phase == 1) {
// Phase 1: Slow movement, regular attacks
self.x += Math.sin(self.phaseTimer * 0.01) * 2;
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.phase1Attack();
self.attackCooldown = 60;
}
if (self.health < self.maxHealth * 0.5) {
self.phase = 2;
self.phaseTimer = 0;
}
} else if (self.phase == 2) {
// Phase 2: Aggressive attacks
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.phase2Attack();
self.attackCooldown = 30;
}
}
};
self.phase1Attack = function () {
// Triple spread shot
for (var i = -2; i <= 2; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 150;
bullet.targetX = player.x + i * 100;
bullet.targetY = player.y;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.phase2Attack = function () {
// Radial burst + laser
for (var i = 0; i < 12; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 12 * Math.PI * 2;
bullet.targetX = self.x + Math.cos(angle) * 600;
bullet.targetY = self.y + Math.sin(angle) * 600;
bossBullets.push(bullet);
game.addChild(bullet);
}
if (self.phaseTimer % 120 == 0) {
var laser = new BossLaser();
laser.x = player.x;
laser.y = 0;
bossLasers.push(laser);
game.addChild(laser);
}
};
self.onDefeat = function () {
LK.getSound('bossDefeat').play();
LK.setScore(LK.getScore() + 1000);
LK.showYouWin();
};
return self;
});
var Boss5 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss2', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.scaleX = 1.5;
graphics.scaleY = 1.5;
self.maxHealth = 750;
self.health = self.maxHealth;
self.speed = 3;
self.teleportTimer = 0;
self.laserWaveTimer = 0;
self.update = function () {
self.teleportTimer++;
self.laserWaveTimer++;
// Teleport movement
if (self.teleportTimer % 120 == 0) {
var newX = 300 + Math.random() * 1448;
var newY = 300 + Math.random() * 400;
tween(self, {
x: newX,
y: newY
}, {
duration: 300
});
LK.effects.flashObject(self, 0xffffff, 300);
}
// Attack patterns
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 35;
}
// Laser wave attack
if (self.laserWaveTimer % 240 == 0) {
self.laserWave();
}
};
self.attack = function () {
// Homing missiles
for (var i = 0; i < 4; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 1.5) * 80;
bullet.y = self.y + 100;
bullet.targetX = player.x + (Math.random() - 0.5) * 200;
bullet.targetY = player.y + (Math.random() - 0.5) * 200;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.laserWave = function () {
// Create multiple lasers across the screen
for (var i = 0; i < 5; i++) {
var laser = new BossLaser();
laser.x = 200 + i * 400;
laser.y = 0;
bossLasers.push(laser);
game.addChild(laser);
}
};
return self;
});
var Boss4 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss3', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 600;
self.health = self.maxHealth;
self.speed = 5;
self.spiralAngle = 0;
self.burstTimer = 0;
self.update = function () {
// Spiral movement pattern
self.spiralAngle += 0.05;
self.x = 1024 + Math.cos(self.spiralAngle) * 400;
self.y = 500 + Math.sin(self.spiralAngle * 0.7) * 150;
// Multiple attack patterns
self.attackCooldown--;
self.burstTimer++;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 40;
}
// Burst attack every 3 seconds
if (self.burstTimer % 180 == 0) {
self.burstAttack();
}
};
self.attack = function () {
// Spiral shot pattern
for (var i = 0; i < 6; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 6 * Math.PI * 2 + self.spiralAngle * 2;
bullet.targetX = self.x + Math.cos(angle) * 600;
bullet.targetY = self.y + Math.sin(angle) * 600;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.burstAttack = function () {
// Massive radial burst
for (var i = 0; i < 16; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 16 * Math.PI * 2;
bullet.targetX = self.x + Math.cos(angle) * 700;
bullet.targetY = self.y + Math.sin(angle) * 700;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var Boss3 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss3', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 400;
self.health = self.maxHealth;
self.speed = 4;
self.laserCooldown = 0;
self.update = function () {
// Aggressive movement toward player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared > 0) {
var distance = Math.sqrt(distanceSquared);
self.x += dx / distance * self.speed * 0.5;
self.y += dy / distance * self.speed * 0.3;
}
// Multiple attack patterns
self.attackCooldown--;
self.laserCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 45;
}
if (self.laserCooldown <= 0) {
self.laserAttack();
self.laserCooldown = 180;
}
};
self.attack = function () {
// Radial shot
for (var i = 0; i < 8; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 8 * Math.PI * 2;
bullet.targetX = self.x + Math.cos(angle) * 500;
bullet.targetY = self.y + Math.sin(angle) * 500;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.laserAttack = function () {
var laser = new BossLaser();
laser.x = self.x;
laser.y = self.y + 100;
bossLasers.push(laser);
game.addChild(laser);
};
return self;
});
var Boss2 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss2', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 250;
self.health = self.maxHealth;
self.speed = 3;
self.angle = 0;
self.update = function () {
// Circular movement
self.angle += 0.02;
self.x = 1024 + Math.cos(self.angle) * 300;
self.y = 600 + Math.sin(self.angle) * 200;
// Faster shooting
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 60;
}
};
self.attack = function () {
// Spread shot
for (var i = -1; i <= 1; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 90;
bullet.targetX = player.x + i * 150;
bullet.targetY = player.y;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var Boss1 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss1', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 150;
self.health = self.maxHealth;
self.moveDirection = 1;
self.update = function () {
// Simple horizontal movement
self.x += self.speed * self.moveDirection;
if (self.x > 1800 || self.x < 250) {
self.moveDirection *= -1;
}
// Simple shooting pattern
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 90;
}
};
self.attack = function () {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 75;
bullet.targetX = player.x;
bullet.targetY = player.y;
bossBullets.push(bullet);
game.addChild(bullet);
};
return self;
});
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.targetX = 0;
self.targetY = 0;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
if (self.velocityX == 0 && self.velocityY == 0) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var BossLaser = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 120;
self.update = function () {
self.lifetime--;
graphics.alpha = self.lifetime / 120;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootCooldown = 0;
self.speed = 8;
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 300);
LK.getSound('hit').play();
if (self.health <= 0) {
self.health = 0;
isGameOver = true;
}
};
self.shoot = function () {
if (self.shootCooldown <= 0) {
var bullet = getPooledPlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 50;
playerBullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 10;
LK.getSound('shoot').play();
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Viggen = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('viggen', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x00ffff; // Cyan tint for Viggens
self.speed = 4;
self.homingForce = 0.2;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 300; // 5 seconds at 60fps
self.update = function () {
self.lifetime--;
// Homing behavior toward player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX += dx / distance * self.homingForce;
self.velocityY += dy / distance * self.homingForce;
}
// Apply velocity with speed limit
var currentSpeed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (currentSpeed > self.speed) {
self.velocityX = self.velocityX / currentSpeed * self.speed;
self.velocityY = self.velocityY / currentSpeed * self.speed;
}
self.x += self.velocityX;
self.y += self.velocityY;
// Fade out as lifetime decreases
graphics.alpha = Math.min(1, self.lifetime / 60);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
var player;
var currentBoss;
var currentBossLevel = 1;
var playerBullets = [];
var bossBullets = [];
var bossLasers = [];
var viggens = [];
// Object pools for performance optimization
var playerBulletPool = [];
var bossBulletPool = [];
var bossLaserPool = [];
var viggenPool = [];
function getPooledPlayerBullet() {
if (playerBulletPool.length > 0) {
return playerBulletPool.pop();
}
return new PlayerBullet();
}
function getPooledBossBullet() {
if (bossBulletPool.length > 0) {
return bossBulletPool.pop();
}
return new BossBullet();
}
function getPooledBossLaser() {
if (bossLaserPool.length > 0) {
return bossLaserPool.pop();
}
return new BossLaser();
}
function getPooledViggen() {
if (viggenPool.length > 0) {
return viggenPool.pop();
}
return new Viggen();
}
function returnToPool(bullet, pool) {
bullet.x = 0;
bullet.y = 0;
bullet.velocityX = 0;
bullet.velocityY = 0;
bullet.targetX = 0;
bullet.targetY = 0;
pool.push(bullet);
}
var bossDefeated = false;
var isGameOver = false;
var transitionTimer = 0;
var dragNode = null;
var bossNames = ['Shant', 'Glen', 'Octo', 'Benjaminsen', 'Upit Developer', 'The Upit Collective'];
var secretBossUnlocked = false;
var secretBossDefeated = storage.secretBossDefeated || false;
var sparklingWaterUnlocked = storage.sparklingWaterUnlocked || false;
// Music unlocking system
var unlockedMusic = storage.unlockedMusic || {
battleMusic: false,
goosandraTheme: false
};
var currentlyPlayingMusic = 'battleMusic';
// Easter egg variables
var konamiCode = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]; // Up Up Down Down Left Right Left Right B A
var konamiProgress = 0;
var rapidFireUnlocked = storage.rapidFireUnlocked || false;
var rainbowModeUnlocked = storage.rainbowModeUnlocked || false;
var clickCounter = 0;
var lastClickTime = 0;
var easterEggTimer = 0;
// UI Elements
var healthBar;
var bossHealthBar;
var levelText;
var instructionText;
// Initialize UI
healthBar = new Text2('Health: 100', {
size: 60,
fill: 0x00FF00
});
healthBar.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthBar);
bossHealthBar = new Text2('Boss Health: 0', {
size: 60,
fill: 0xFF0000
});
bossHealthBar.anchor.set(0.5, 0);
LK.gui.top.addChild(bossHealthBar);
// Add click handler to boss health bar for secret boss
bossHealthBar.down = function (x, y, obj) {
if (currentBossLevel == 3 && currentBoss && !sparklingWaterUnlocked) {
// Special Easter egg: Sparkling water gift during Octo fight
sparklingWaterUnlocked = true;
storage.sparklingWaterUnlocked = true;
// Create sparkling water gift effect
LK.effects.flashScreen(0x87CEEB, 1500);
// Show sparkling water message
var sparklingMsg = new Text2('๐ง SPARKLING WATER GIFTED! ๐ง\n\nA refreshing reward for your\nexceptional Easter egg hunting!', {
size: 50,
fill: 0x87CEEB
});
sparklingMsg.anchor.set(0.5, 0.5);
sparklingMsg.x = 1024;
sparklingMsg.y = 1366;
game.addChild(sparklingMsg);
// Animate sparkling water message
tween(sparklingMsg, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
sparklingMsg.destroy();
}
});
// Create bubbling particle effect
for (var i = 0; i < 15; i++) {
var bubble = LK.getAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + (Math.random() - 0.5) * 600,
y: 1366 + (Math.random() - 0.5) * 200,
scaleX: 0.5,
scaleY: 0.5
});
bubble.tint = 0x87CEEB; // Sky blue for water bubbles
game.addChild(bubble);
// Animate bubbles floating up
tween(bubble, {
y: bubble.y - 400 - Math.random() * 200,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 3000 + Math.random() * 1000,
onFinish: function onFinish() {
bubble.destroy();
}
});
}
}
if (currentBossLevel == 2 && currentBoss && currentBoss.health <= 0 && !secretBossUnlocked) {
secretBossUnlocked = true;
// Spawn secret boss Goosandra
currentBoss.destroy();
currentBoss = game.addChild(new Goosandra());
currentBoss.x = 1024;
currentBoss.y = -300; // Start above screen for dramatic entrance
levelText.setText('Secret Boss: Goosandra');
bossNameText.setText('Secret Boss: Goosandra');
bossGuideText.setText('CHAOS! Two phases, homing Viggens, ultimate mayhem!');
bossLoreText.setText(getGoosandraLore());
// Play Goosandra's theme song
LK.playMusic('goosandraTheme');
// Unlock Goosandra theme after experiencing it
if (!unlockedMusic.goosandraTheme) {
unlockedMusic.goosandraTheme = true;
storage.unlockedMusic = unlockedMusic;
}
// Dramatic entrance cutscene
LK.effects.flashScreen(0x800080, 1000);
// Easter egg: Extra special effects if both Easter eggs are unlocked
if (rapidFireUnlocked && rainbowModeUnlocked) {
// Create rainbow particle effect
for (var i = 0; i < 20; i++) {
var particle = LK.getAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + (Math.random() - 0.5) * 400,
y: 1366 + (Math.random() - 0.5) * 400,
scaleX: 2,
scaleY: 2
});
particle.tint = Math.random() * 0xFFFFFF;
game.addChild(particle);
// Animate particles
tween(particle, {
x: particle.x + (Math.random() - 0.5) * 800,
y: particle.y + (Math.random() - 0.5) * 800,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 2000,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Special message for Easter egg hunters
var easterMsg = new Text2('๐ฅ TRUE EASTER EGG HUNTER! ๐ฅ', {
size: 50,
fill: 0xFF69B4
});
easterMsg.anchor.set(0.5, 0.5);
easterMsg.x = 1024;
easterMsg.y = 1100;
game.addChild(easterMsg);
tween(easterMsg, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
easterMsg.destroy();
}
});
}
// Make UI text dramatic entrance
tween(levelText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.bounceOut
});
tween(bossNameText, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 600,
easing: tween.elasticOut
});
// Goosandra dramatic entrance from above
tween(currentBoss, {
y: 400
}, {
duration: 2000,
easing: tween.bounceOut
});
// Add spinning entrance effect
tween(currentBoss, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.easeOut
});
// Pulsing size effect
tween(currentBoss, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(currentBoss, {
scaleX: 1,
scaleY: 1
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
}
};
levelText = new Text2('Boss Level: 1', {
size: 80,
fill: 0xFFFF00
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
instructionText = new Text2('Drag to move, tap to shoot!', {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
var bossNameText = new Text2('Boss 1: Shant', {
size: 70,
fill: 0xFF6600
});
bossNameText.anchor.set(0.5, 0);
bossNameText.y = 100;
LK.gui.top.addChild(bossNameText);
// Easter egg: Rapid click on boss name for rainbow mode
bossNameText.down = function (x, y, obj) {
var currentTime = Date.now();
if (currentTime - lastClickTime < 200) {
// Clicks within 200ms
clickCounter++;
if (clickCounter >= 7) {
if (!rainbowModeUnlocked) {
rainbowModeUnlocked = true;
storage.rainbowModeUnlocked = true;
LK.effects.flashScreen(0xFFFFFF, 1000);
// Show rainbow message
var rainbowMsg = new Text2('๐ RAINBOW MODE ACTIVATED! ๐', {
size: 60,
fill: 0xFF00FF
});
rainbowMsg.anchor.set(0.5, 0.5);
rainbowMsg.x = 1024;
rainbowMsg.y = 1366;
game.addChild(rainbowMsg);
// Animate message
tween(rainbowMsg, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 3000,
onFinish: function onFinish() {
rainbowMsg.destroy();
}
});
}
clickCounter = 0;
}
} else {
clickCounter = 1;
}
lastClickTime = currentTime;
};
var bossGuideText = new Text2('', {
size: 40,
fill: 0xAAAAA
});
bossGuideText.anchor.set(0.5, 0);
bossGuideText.y = 180;
LK.gui.top.addChild(bossGuideText);
var bossLoreText = new Text2('', {
size: 35,
fill: 0xCCCCCC
});
bossLoreText.anchor.set(0.5, 0);
bossLoreText.y = 240;
LK.gui.top.addChild(bossLoreText);
// Add lore button
var loreButton = new Text2('๐ LORE', {
size: 50,
fill: 0xFFD700
});
loreButton.anchor.set(0, 1);
loreButton.x = 50;
loreButton.y = -50;
LK.gui.bottomLeft.addChild(loreButton);
// Add guide button
var guideButton = new Text2('๐ GUIDE', {
size: 45,
fill: 0x00FF88
});
guideButton.anchor.set(0, 1);
guideButton.x = 50;
guideButton.y = -190;
LK.gui.bottomLeft.addChild(guideButton);
// Add boombox button
var boomboxButton = new Text2('๐ต BOOMBOX', {
size: 45,
fill: 0x00FFFF
});
boomboxButton.anchor.set(0, 1);
boomboxButton.x = 50;
boomboxButton.y = -120;
LK.gui.bottomLeft.addChild(boomboxButton);
// Lore display overlay
var loreOverlay = null;
var loreDisplayText = null;
var loreCloseButton = null;
var showingLore = false;
// Boombox overlay variables
var boomboxOverlay = null;
var boomboxDisplayText = null;
var boomboxCloseButton = null;
var showingBoombox = false;
var musicButtons = [];
// Guide overlay variables
var guideOverlay = null;
var guideDisplayText = null;
var guideCloseButton = null;
var showingGuide = false;
// Lore button click handler
loreButton.down = function (x, y, obj) {
if (!showingLore) {
showingLore = true;
// Create dark overlay
loreOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
loreOverlay.tint = 0x000000;
game.addChild(loreOverlay);
// Create lore text
var loreContent = getGameLore();
loreDisplayText = new Text2(loreContent, {
size: 45,
fill: 0xFFFFFF
});
loreDisplayText.anchor.set(0.5, 0.5);
loreDisplayText.x = 1024;
loreDisplayText.y = 1366;
game.addChild(loreDisplayText);
// Create close button
loreCloseButton = new Text2('โ CLOSE', {
size: 60,
fill: 0xFF4444
});
loreCloseButton.anchor.set(0.5, 0.5);
loreCloseButton.x = 1024;
loreCloseButton.y = 2400;
game.addChild(loreCloseButton);
// Close button handler
loreCloseButton.down = function (x, y, obj) {
closeLoreDisplay();
};
// Animate entrance
tween(loreOverlay, {
alpha: 0.9
}, {
duration: 500
});
tween(loreDisplayText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.bounceOut
});
tween(loreCloseButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.elasticOut
});
}
};
function closeLoreDisplay() {
if (showingLore) {
showingLore = false;
if (loreOverlay) {
loreOverlay.destroy();
loreOverlay = null;
}
if (loreDisplayText) {
loreDisplayText.destroy();
loreDisplayText = null;
}
if (loreCloseButton) {
loreCloseButton.destroy();
loreCloseButton = null;
}
}
}
// Guide button click handler
guideButton.down = function (x, y, obj) {
if (!showingGuide) {
showingGuide = true;
// Create dark overlay
guideOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
guideOverlay.tint = 0x000000;
game.addChild(guideOverlay);
// Create guide text
var guideContent = getGameGuide();
guideDisplayText = new Text2(guideContent, {
size: 45,
fill: 0x00FF88
});
guideDisplayText.anchor.set(0.5, 0.5);
guideDisplayText.x = 1024;
guideDisplayText.y = 1366;
game.addChild(guideDisplayText);
// Create close button
guideCloseButton = new Text2('โ CLOSE', {
size: 60,
fill: 0xFF4444
});
guideCloseButton.anchor.set(0.5, 0.5);
guideCloseButton.x = 1024;
guideCloseButton.y = 2400;
game.addChild(guideCloseButton);
// Close button handler
guideCloseButton.down = function (x, y, obj) {
closeGuideDisplay();
};
// Animate entrance
tween(guideOverlay, {
alpha: 0.9
}, {
duration: 500
});
tween(guideDisplayText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.bounceOut
});
tween(guideCloseButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.elasticOut
});
}
};
function closeGuideDisplay() {
if (showingGuide) {
showingGuide = false;
if (guideOverlay) {
guideOverlay.destroy();
guideOverlay = null;
}
if (guideDisplayText) {
guideDisplayText.destroy();
guideDisplayText = null;
}
if (guideCloseButton) {
guideCloseButton.destroy();
guideCloseButton = null;
}
}
}
function getGameGuide() {
return "๐ฎ HOW TO PLAY\n\n" + "โข Drag to move your green ship\n" + "โข Tap anywhere to shoot\n" + "โข Defeat all 6 bosses to win!\n\n" + "โ๏ธ BOSS STRATEGIES\n\n" + "Boss 1 (Shant): Simple horizontal movement\n" + "Stay mobile, avoid single shots\n\n" + "Boss 2 (Glen): Circular pattern, spread shots\n" + "Predict movement, dodge spread fire\n\n" + "Boss 3 (Octo): Aggressive homing + lasers\n" + "Keep distance, watch for laser telegraphs\n\n" + "Boss 4 (Benjaminsen): Spiral + burst attacks\n" + "Learn patterns, time your movements\n\n" + "Boss 5 (Upit Dev): Teleports + homing missiles\n" + "Stay alert, unpredictable positioning\n\n" + "Final Boss: Two phases, everything combined\n" + "Ultimate challenge, use all your skills!\n\n" + "๐ฅ EASTER EGG HINTS\n\n" + "โข Double-tap your ship for surprises...\n" + "โข Rapidly click boss names for effects...\n" + "โข Try clicking UI during boss fights...\n" + "โข Secret bosses exist for the worthy...\n" + "โข Music unlocks through experience...\n" + "โข Some rewards are refreshingly hidden...\n\n" + "Good luck, pilot! ๐";
}
// Boombox button click handler
boomboxButton.down = function (x, y, obj) {
if (!showingBoombox) {
showingBoombox = true;
// Create dark overlay
boomboxOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
boomboxOverlay.tint = 0x000000;
game.addChild(boomboxOverlay);
// Create boombox title
boomboxDisplayText = new Text2('๐ต MUSIC BOOMBOX ๐ต\n\nEach track must be experienced in its\nnatural environment before access!', {
size: 50,
fill: 0x00FFFF
});
boomboxDisplayText.anchor.set(0.5, 0);
boomboxDisplayText.x = 1024;
boomboxDisplayText.y = 400;
game.addChild(boomboxDisplayText);
// Create music control buttons
createMusicButtons();
// Create close button
boomboxCloseButton = new Text2('โ CLOSE', {
size: 60,
fill: 0xFF4444
});
boomboxCloseButton.anchor.set(0.5, 0.5);
boomboxCloseButton.x = 1024;
boomboxCloseButton.y = 2400;
game.addChild(boomboxCloseButton);
// Close button handler
boomboxCloseButton.down = function (x, y, obj) {
closeBoomboxDisplay();
};
// Animate entrance
tween(boomboxOverlay, {
alpha: 0.9
}, {
duration: 500
});
tween(boomboxDisplayText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.bounceOut
});
}
};
function createMusicButtons() {
// Clear existing buttons
for (var i = 0; i < musicButtons.length; i++) {
musicButtons[i].destroy();
}
musicButtons = [];
var yStart = 800;
var spacing = 200;
// Battle Music button
var battleButton = new Text2('โช Battle Music', {
size: 55,
fill: unlockedMusic.battleMusic ? 0x00FF00 : 0x888888
});
battleButton.anchor.set(0.5, 0.5);
battleButton.x = 1024;
battleButton.y = yStart;
game.addChild(battleButton);
musicButtons.push(battleButton);
if (unlockedMusic.battleMusic) {
battleButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'battleMusic';
LK.playMusic('battleMusic');
updateMusicButtonColors();
};
}
// Goosandra Theme button
var goosandraButton = new Text2('โซ Goosandra Theme', {
size: 55,
fill: unlockedMusic.goosandraTheme ? 0x800080 : 0x888888
});
goosandraButton.anchor.set(0.5, 0.5);
goosandraButton.x = 1024;
goosandraButton.y = yStart + spacing;
game.addChild(goosandraButton);
musicButtons.push(goosandraButton);
if (unlockedMusic.goosandraTheme) {
goosandraButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'goosandraTheme';
LK.playMusic('goosandraTheme');
updateMusicButtonColors();
};
}
// Status text
var statusText = new Text2(getUnlockStatus(), {
size: 40,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 1024;
statusText.y = yStart + spacing * 2;
game.addChild(statusText);
musicButtons.push(statusText);
updateMusicButtonColors();
}
function updateMusicButtonColors() {
if (musicButtons.length >= 2) {
// Battle music button
musicButtons[0].tint = currentlyPlayingMusic === 'battleMusic' && unlockedMusic.battleMusic ? 0xFFFF00 : unlockedMusic.battleMusic ? 0x00FF00 : 0x888888;
// Goosandra theme button
musicButtons[1].tint = currentlyPlayingMusic === 'goosandraTheme' && unlockedMusic.goosandraTheme ? 0xFFFF00 : unlockedMusic.goosandraTheme ? 0x800080 : 0x888888;
}
}
function getUnlockStatus() {
var unlocked = 0;
var total = 2;
if (unlockedMusic.battleMusic) unlocked++;
if (unlockedMusic.goosandraTheme) unlocked++;
return 'Unlocked: ' + unlocked + '/' + total + ' tracks';
}
function closeBoomboxDisplay() {
if (showingBoombox) {
showingBoombox = false;
if (boomboxOverlay) {
boomboxOverlay.destroy();
boomboxOverlay = null;
}
if (boomboxDisplayText) {
boomboxDisplayText.destroy();
boomboxDisplayText = null;
}
if (boomboxCloseButton) {
boomboxCloseButton.destroy();
boomboxCloseButton = null;
}
// Clear music buttons
for (var i = 0; i < musicButtons.length; i++) {
musicButtons[i].destroy();
}
musicButtons = [];
}
}
function getGameLore() {
return "THE UPIT WARS: GENESIS\n\n" + "Long ago, in the digital realm of FRVR,\n" + "the UPIT Collective ruled with algorithms\n" + "and code. But power corrupted their minds,\n" + "transforming them into digital tyrants.\n\n" + "Each member became a Boss, wielding\n" + "their programming skills as weapons:\n\n" + "โข Shant - The Beat Master\n" + "โข Glen - The Haskell God\n" + "โข Octo - The Hunter-Killer\n" + "โข Benjaminsen - The Strategist\n" + "โข The Upit Developer - Reality Bender\n" + "โข The Collective - Merged Consciousness\n\n" + "In the shadows lurks Goosandra,\n" + "the Certified Viggener, responsible\n" + "for multiple digital genocides.\n\n" + "You are humanity's last hope.\n" + "Defeat the UPIT Bosses and restore\n" + "balance to the digital realm!\n\n" + "May the code be with you...";
}
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2200;
// Easter egg: Double tap player for rapid fire
var playerClickCount = 0;
var playerLastClickTime = 0;
player.down = function (x, y, obj) {
var currentTime = Date.now();
if (currentTime - playerLastClickTime < 300) {
// Double tap within 300ms
playerClickCount++;
if (playerClickCount >= 2 && !rapidFireUnlocked) {
rapidFireUnlocked = true;
storage.rapidFireUnlocked = true;
LK.effects.flashObject(player, 0xFFFF00, 1000);
// Show rapid fire message
var rapidMsg = new Text2('โก RAPID FIRE UNLOCKED! โก', {
size: 60,
fill: 0xFFFF00
});
rapidMsg.anchor.set(0.5, 0.5);
rapidMsg.x = 1024;
rapidMsg.y = 1500;
game.addChild(rapidMsg);
// Animate message
tween(rapidMsg, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
rapidMsg.destroy();
}
});
playerClickCount = 0;
}
} else {
playerClickCount = 1;
}
playerLastClickTime = currentTime;
};
// Start first boss
function getBossGuide(bossLevel) {
if (bossLevel == 1) {
return 'Simple movement, single shots. Stay mobile!';
} else if (bossLevel == 2) {
return 'Circular pattern, spread shots. Predict the path!';
} else if (bossLevel == 3) {
return 'Homing movement, radial + laser attacks. Keep distance!';
} else if (bossLevel == 4) {
return 'Spiral movement, burst attacks. Watch for patterns!';
} else if (bossLevel == 5) {
return 'Teleports randomly, homing missiles + laser waves!';
} else if (bossLevel >= 6) {
return 'Two phases, radial bursts + targeted lasers!';
}
return '';
}
function getBossLore(bossLevel) {
if (bossLevel == 1) {
var baseLore = 'A simple UPIT creator, mostly known for The Last Beat';
if (rapidFireUnlocked && rainbowModeUnlocked) {
return baseLore + ' ๐ต *hums The Last Beat* ๐ต';
}
return baseLore;
} else if (bossLevel == 2) {
// Check if secret boss has been defeated to reveal Goosandra's name
if (secretBossDefeated) {
return 'Haskell god, Goosandra\'s friend';
} else {
return 'Haskell god, #########\'s friend';
}
} else if (bossLevel == 3) {
var baseLore = 'An aggressive hunter-killer with advanced targeting.';
if (rainbowModeUnlocked) {
return baseLore + ' ๐ Surprisingly, loves rainbow colors! ๐';
}
return baseLore;
} else if (bossLevel == 4) {
var baseLore = 'A master strategist who fights with calculated precision.';
if (rapidFireUnlocked) {
return baseLore + ' โก Respects your rapid fire skills! โก';
}
return baseLore;
} else if (bossLevel == 5) {
return 'The lead developer, wielding reality-bending code.';
} else if (bossLevel >= 6) {
var baseLore = 'The merged consciousness of all UPIT minds.';
if (rapidFireUnlocked && rainbowModeUnlocked) {
return baseLore + ' ๐ง โจ They are impressed by your Easter egg hunting! โจ๐ง ';
}
return baseLore;
}
return '';
}
function getGoosandraLore() {
return 'Certified Viggener, responsible for multiple genocides. Pounds sand with geese.';
}
function spawnBoss() {
if (currentBoss) {
currentBoss.destroy();
}
bossDefeated = false;
transitionTimer = 0;
// Clear bullets
for (var i = bossBullets.length - 1; i >= 0; i--) {
bossBullets[i].destroy();
bossBullets.splice(i, 1);
}
// Clear viggens
for (var i = viggens.length - 1; i >= 0; i--) {
viggens[i].destroy();
viggens.splice(i, 1);
}
// Spawn appropriate boss
if (currentBossLevel == 1) {
currentBoss = game.addChild(new Boss1());
currentBoss.x = 1024;
currentBoss.y = 400;
levelText.setText('Boss 1: Shant');
bossNameText.setText('Boss 1: Shant');
bossGuideText.setText(getBossGuide(1));
bossLoreText.setText(getBossLore(1));
} else if (currentBossLevel == 2) {
currentBoss = game.addChild(new Boss2());
currentBoss.x = 1024;
currentBoss.y = 600;
levelText.setText('Boss 2: Glen');
bossNameText.setText('Boss 2: Glen');
bossGuideText.setText(getBossGuide(2));
bossLoreText.setText(getBossLore(2));
} else if (currentBossLevel == 3) {
currentBoss = game.addChild(new Boss3());
currentBoss.x = 1024;
currentBoss.y = 500;
levelText.setText('Boss 3: Octo');
bossNameText.setText('Boss 3: Octo');
bossGuideText.setText(getBossGuide(3));
bossLoreText.setText(getBossLore(3));
} else if (currentBossLevel == 4) {
currentBoss = game.addChild(new Boss4());
currentBoss.x = 1024;
currentBoss.y = 500;
levelText.setText('Boss 4: Benjaminsen');
bossNameText.setText('Boss 4: Benjaminsen');
bossGuideText.setText(getBossGuide(4));
bossLoreText.setText(getBossLore(4));
} else if (currentBossLevel == 5) {
currentBoss = game.addChild(new Boss5());
currentBoss.x = 1024;
currentBoss.y = 400;
levelText.setText('Boss 5: Upit Developer');
bossNameText.setText('Boss 5: Upit Developer');
bossGuideText.setText(getBossGuide(5));
bossLoreText.setText(getBossLore(5));
} else if (currentBossLevel >= 6) {
currentBoss = game.addChild(new FinalBoss());
currentBoss.x = 1024;
currentBoss.y = 400;
levelText.setText('Final Boss: The Upit Collective');
bossNameText.setText('Final Boss: The Upit Collective');
bossGuideText.setText(getBossGuide(6));
bossLoreText.setText(getBossLore(6));
}
}
spawnBoss();
// Play battle music
LK.playMusic('battleMusic');
// Unlock battle music after experiencing it
if (!unlockedMusic.battleMusic) {
unlockedMusic.battleMusic = true;
storage.unlockedMusic = unlockedMusic;
}
// Event handlers
function handleMove(x, y, obj) {
if (dragNode && !isGameOver) {
dragNode.x = Math.max(40, Math.min(2008, x));
dragNode.y = Math.max(1000, Math.min(2692, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!isGameOver) {
dragNode = player;
handleMove(x, y, obj);
player.shoot();
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
if (isGameOver) {
LK.showGameOver();
return;
}
// Handle boss transition
if (bossDefeated) {
transitionTimer++;
if (transitionTimer > 120) {
currentBossLevel++;
if (currentBossLevel > 6) {
currentBossLevel = 6; // Stay at final boss
}
spawnBoss();
// Heal player slightly between bosses
player.health = Math.min(player.maxHealth, player.health + 20);
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.y < -50) {
game.removeChild(bullet);
returnToPool(bullet, playerBulletPool);
playerBullets.splice(i, 1);
continue;
}
// Check collision with boss
if (currentBoss && bullet.intersects(currentBoss)) {
currentBoss.takeDamage(25);
game.removeChild(bullet);
returnToPool(bullet, playerBulletPool);
playerBullets.splice(i, 1);
continue;
}
}
// Update boss bullets
for (var i = bossBullets.length - 1; i >= 0; i--) {
var bullet = bossBullets[i];
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
game.removeChild(bullet);
returnToPool(bullet, bossBulletPool);
bossBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
player.takeDamage(15);
game.removeChild(bullet);
returnToPool(bullet, bossBulletPool);
bossBullets.splice(i, 1);
continue;
}
}
// Update boss lasers
for (var i = bossLasers.length - 1; i >= 0; i--) {
var laser = bossLasers[i];
if (laser.lifetime <= 0) {
game.removeChild(laser);
laser.lifetime = 120; // Reset lifetime for pooling
returnToPool(laser, bossLaserPool);
bossLasers.splice(i, 1);
continue;
}
// Check collision with player
if (laser.intersects(player)) {
player.takeDamage(2); // Continuous damage
}
}
// Update viggens
for (var i = viggens.length - 1; i >= 0; i--) {
var viggen = viggens[i];
if (viggen.lifetime <= 0 || viggen.x < -50 || viggen.x > 2098 || viggen.y < -50 || viggen.y > 2782) {
game.removeChild(viggen);
viggen.lifetime = 300; // Reset lifetime for pooling
returnToPool(viggen, viggenPool);
viggens.splice(i, 1);
continue;
}
// Check collision with player
if (viggen.intersects(player)) {
player.takeDamage(20);
game.removeChild(viggen);
viggen.lifetime = 300; // Reset lifetime for pooling
returnToPool(viggen, viggenPool);
viggens.splice(i, 1);
continue;
}
}
// Update UI (only every 10 frames to reduce text update overhead)
if (LK.ticks % 10 === 0) {
healthBar.setText('Health: ' + player.health);
if (currentBoss) {
bossHealthBar.setText('Boss Health: ' + currentBoss.health);
}
}
// Easter egg: Pulsing effect for unlocked features
if (rapidFireUnlocked) {
var pulseScale = 1 + Math.sin(easterEggTimer * 0.15) * 0.1;
player.scaleX = pulseScale;
player.scaleY = pulseScale;
}
// Auto-shoot (with rapid fire Easter egg)
var shootInterval = rapidFireUnlocked ? 5 : 15;
if (LK.ticks % shootInterval == 0 && !isGameOver) {
player.shoot();
}
// Easter egg effects
easterEggTimer++;
// Rainbow mode effect
if (rainbowModeUnlocked) {
var rainbowColor = Math.sin(easterEggTimer * 0.1) * 0.5 + 0.5;
var r = Math.sin(easterEggTimer * 0.1) * 127 + 128;
var g = Math.sin(easterEggTimer * 0.1 + 2) * 127 + 128;
var b = Math.sin(easterEggTimer * 0.1 + 4) * 127 + 128;
var color = (Math.floor(r) << 16) + (Math.floor(g) << 8) + Math.floor(b);
// Apply rainbow effect to UI elements
if (easterEggTimer % 3 == 0) {
bossNameText.tint = color;
levelText.tint = color;
}
}
// Easter egg: Hidden developer message appears randomly
if (easterEggTimer % 3600 == 0) {
// Every 60 seconds
var messages = ["The developer is watching... ๐๏ธ", "Viggens are secretly plotting...", "Glen approves of your gameplay", "Goosandra whispers your name...", "The code is strong with this one", "FRVR games are the best games! ๐ฎ"];
var randomMsg = messages[Math.floor(Math.random() * messages.length)];
var devMsg = new Text2(randomMsg, {
size: 40,
fill: 0x00FFFF
});
devMsg.anchor.set(0.5, 0.5);
devMsg.x = 1024;
devMsg.y = 2000;
devMsg.alpha = 0;
game.addChild(devMsg);
// Fade in and out
tween(devMsg, {
alpha: 1,
y: 1800
}, {
duration: 1000,
onFinish: function onFinish() {
tween(devMsg, {
alpha: 0,
y: 1600
}, {
duration: 1000,
onFinish: function onFinish() {
devMsg.destroy();
}
});
}
});
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
self.maxHealth = 100;
self.health = self.maxHealth;
self.attackCooldown = 0;
self.movePattern = 0;
self.speed = 2;
self.damage = 10;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
LK.getSound('bossHit').play();
if (self.health <= 0) {
self.health = 0;
self.onDefeat();
}
};
self.onDefeat = function () {
LK.getSound('bossDefeat').play();
bossDefeated = true;
LK.setScore(LK.getScore() + 100 * currentBossLevel);
};
return self;
});
var Goosandra = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('viggen', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x800080; // Purple tint for Goosandra
graphics.scaleX = 8; // Make Goosandra much larger
graphics.scaleY = 8; // Make Goosandra much larger
self.maxHealth = 1000;
self.health = self.maxHealth;
self.speed = 4;
self.secretPhase = 1;
self.phaseTimer = 0;
self.update = function () {
self.phaseTimer++;
if (self.secretPhase == 1) {
// Phase 1: Chaotic movement
self.x += Math.sin(self.phaseTimer * 0.03) * 4;
self.y += Math.cos(self.phaseTimer * 0.02) * 2;
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.chaosAttack();
self.attackCooldown = 25;
}
if (self.health < self.maxHealth * 0.6) {
self.secretPhase = 2;
self.phaseTimer = 0;
}
} else if (self.secretPhase == 2) {
// Phase 2: Ultimate chaos
self.x += Math.sin(self.phaseTimer * 0.05) * 6;
self.y += Math.cos(self.phaseTimer * 0.04) * 3;
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.ultimateAttack();
self.attackCooldown = 25;
}
}
};
self.chaosAttack = function () {
// Spiral chaos shot
for (var i = 0; i < 6; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 6 * Math.PI * 2 + self.phaseTimer * 0.1;
bullet.targetX = self.x + Math.cos(angle) * 800;
bullet.targetY = self.y + Math.sin(angle) * 800;
bossBullets.push(bullet);
game.addChild(bullet);
}
// Add 1 Viggen every chaos attack
for (var j = 0; j < 1; j++) {
var viggen = getPooledViggen();
viggen.x = self.x + (j - 0.5) * 100;
viggen.y = self.y + 80;
viggen.velocityX = (Math.random() - 0.5) * 2;
viggen.velocityY = Math.random() * 2 + 1;
viggen.lifetime = 300;
viggens.push(viggen);
game.addChild(viggen);
}
};
self.ultimateAttack = function () {
// Ultimate chaos burst
for (var i = 0; i < 12; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 12 * Math.PI * 2 + self.phaseTimer * 0.2;
bullet.targetX = self.x + Math.cos(angle) * 900;
bullet.targetY = self.y + Math.sin(angle) * 900;
bossBullets.push(bullet);
game.addChild(bullet);
}
// Random laser bursts
if (self.phaseTimer % 120 == 0) {
for (var j = 0; j < 2; j++) {
var laser = new BossLaser();
laser.x = 200 + Math.random() * 1648;
laser.y = 0;
bossLasers.push(laser);
game.addChild(laser);
}
}
// Add 2 Viggens during ultimate attack
for (var k = 0; k < 2; k++) {
var viggen = getPooledViggen();
viggen.x = self.x + (k - 0.5) * 80;
viggen.y = self.y + 100;
viggen.velocityX = (Math.random() - 0.5) * 3;
viggen.velocityY = Math.random() * 3 + 2;
viggen.lifetime = 300;
viggens.push(viggen);
game.addChild(viggen);
}
};
self.onDefeat = function () {
LK.getSound('bossDefeat').play();
LK.setScore(LK.getScore() + 2000);
secretBossDefeated = true;
storage.secretBossDefeated = true;
// Update Glen's lore text if currently viewing boss 2
if (currentBossLevel == 2) {
bossLoreText.setText(getBossLore(2));
}
// Dramatic defeat cutscene
LK.effects.flashScreen(0x800080, 2000);
// Spin and shrink effect
tween(self, {
rotation: Math.PI * 8,
scaleX: 0,
scaleY: 0
}, {
duration: 2000,
easing: tween.easeIn
});
// Fade out all UI elements dramatically
tween(levelText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossNameText, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossHealthBar, {
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 1500,
easing: tween.easeIn
});
tween(healthBar, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 1500,
easing: tween.easeIn
});
tween(instructionText, {
alpha: 0,
y: instructionText.y + 100
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossGuideText, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeIn
});
tween(bossLoreText, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeIn
});
// Restore UI after 2 seconds
LK.setTimeout(function () {
// Restore all UI elements with bounce-in effect
tween(levelText, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossNameText, {
alpha: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossHealthBar, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(healthBar, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(instructionText, {
alpha: 1,
y: instructionText.y - 100
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossGuideText, {
alpha: 1
}, {
duration: 800,
easing: tween.bounceOut
});
tween(bossLoreText, {
alpha: 1
}, {
duration: 800,
easing: tween.bounceOut
});
}, 2000);
// Wait for dramatic effect before showing win
LK.setTimeout(function () {
LK.showYouWin();
}, 2500);
};
return self;
});
var FinalBoss = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('finalBoss', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 800;
self.health = self.maxHealth;
self.phase = 1;
self.phaseTimer = 0;
self.speed = 2;
self.update = function () {
self.phaseTimer++;
if (self.phase == 1) {
// Phase 1: Slow movement, regular attacks
self.x += Math.sin(self.phaseTimer * 0.01) * 2;
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.phase1Attack();
self.attackCooldown = 60;
}
if (self.health < self.maxHealth * 0.5) {
self.phase = 2;
self.phaseTimer = 0;
}
} else if (self.phase == 2) {
// Phase 2: Aggressive attacks
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.phase2Attack();
self.attackCooldown = 30;
}
}
};
self.phase1Attack = function () {
// Triple spread shot
for (var i = -2; i <= 2; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 150;
bullet.targetX = player.x + i * 100;
bullet.targetY = player.y;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.phase2Attack = function () {
// Radial burst + laser
for (var i = 0; i < 12; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 12 * Math.PI * 2;
bullet.targetX = self.x + Math.cos(angle) * 600;
bullet.targetY = self.y + Math.sin(angle) * 600;
bossBullets.push(bullet);
game.addChild(bullet);
}
if (self.phaseTimer % 120 == 0) {
var laser = new BossLaser();
laser.x = player.x;
laser.y = 0;
bossLasers.push(laser);
game.addChild(laser);
}
};
self.onDefeat = function () {
LK.getSound('bossDefeat').play();
LK.setScore(LK.getScore() + 1000);
LK.showYouWin();
};
return self;
});
var Boss5 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss2', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.scaleX = 1.5;
graphics.scaleY = 1.5;
self.maxHealth = 750;
self.health = self.maxHealth;
self.speed = 3;
self.teleportTimer = 0;
self.laserWaveTimer = 0;
self.update = function () {
self.teleportTimer++;
self.laserWaveTimer++;
// Teleport movement
if (self.teleportTimer % 120 == 0) {
var newX = 300 + Math.random() * 1448;
var newY = 300 + Math.random() * 400;
tween(self, {
x: newX,
y: newY
}, {
duration: 300
});
LK.effects.flashObject(self, 0xffffff, 300);
}
// Attack patterns
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 35;
}
// Laser wave attack
if (self.laserWaveTimer % 240 == 0) {
self.laserWave();
}
};
self.attack = function () {
// Homing missiles
for (var i = 0; i < 4; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 1.5) * 80;
bullet.y = self.y + 100;
bullet.targetX = player.x + (Math.random() - 0.5) * 200;
bullet.targetY = player.y + (Math.random() - 0.5) * 200;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.laserWave = function () {
// Create multiple lasers across the screen
for (var i = 0; i < 5; i++) {
var laser = new BossLaser();
laser.x = 200 + i * 400;
laser.y = 0;
bossLasers.push(laser);
game.addChild(laser);
}
};
return self;
});
var Boss4 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss3', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 600;
self.health = self.maxHealth;
self.speed = 5;
self.spiralAngle = 0;
self.burstTimer = 0;
self.update = function () {
// Spiral movement pattern
self.spiralAngle += 0.05;
self.x = 1024 + Math.cos(self.spiralAngle) * 400;
self.y = 500 + Math.sin(self.spiralAngle * 0.7) * 150;
// Multiple attack patterns
self.attackCooldown--;
self.burstTimer++;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 40;
}
// Burst attack every 3 seconds
if (self.burstTimer % 180 == 0) {
self.burstAttack();
}
};
self.attack = function () {
// Spiral shot pattern
for (var i = 0; i < 6; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 6 * Math.PI * 2 + self.spiralAngle * 2;
bullet.targetX = self.x + Math.cos(angle) * 600;
bullet.targetY = self.y + Math.sin(angle) * 600;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.burstAttack = function () {
// Massive radial burst
for (var i = 0; i < 16; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 16 * Math.PI * 2;
bullet.targetX = self.x + Math.cos(angle) * 700;
bullet.targetY = self.y + Math.sin(angle) * 700;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var Boss3 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss3', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 400;
self.health = self.maxHealth;
self.speed = 4;
self.laserCooldown = 0;
self.update = function () {
// Aggressive movement toward player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared > 0) {
var distance = Math.sqrt(distanceSquared);
self.x += dx / distance * self.speed * 0.5;
self.y += dy / distance * self.speed * 0.3;
}
// Multiple attack patterns
self.attackCooldown--;
self.laserCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 45;
}
if (self.laserCooldown <= 0) {
self.laserAttack();
self.laserCooldown = 180;
}
};
self.attack = function () {
// Radial shot
for (var i = 0; i < 8; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = i / 8 * Math.PI * 2;
bullet.targetX = self.x + Math.cos(angle) * 500;
bullet.targetY = self.y + Math.sin(angle) * 500;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
self.laserAttack = function () {
var laser = new BossLaser();
laser.x = self.x;
laser.y = self.y + 100;
bossLasers.push(laser);
game.addChild(laser);
};
return self;
});
var Boss2 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss2', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 250;
self.health = self.maxHealth;
self.speed = 3;
self.angle = 0;
self.update = function () {
// Circular movement
self.angle += 0.02;
self.x = 1024 + Math.cos(self.angle) * 300;
self.y = 600 + Math.sin(self.angle) * 200;
// Faster shooting
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 60;
}
};
self.attack = function () {
// Spread shot
for (var i = -1; i <= 1; i++) {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 90;
bullet.targetX = player.x + i * 150;
bullet.targetY = player.y;
bossBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var Boss1 = Boss.expand(function () {
var self = Boss.call(this);
var graphics = self.attachAsset('boss1', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 150;
self.health = self.maxHealth;
self.moveDirection = 1;
self.update = function () {
// Simple horizontal movement
self.x += self.speed * self.moveDirection;
if (self.x > 1800 || self.x < 250) {
self.moveDirection *= -1;
}
// Simple shooting pattern
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attack();
self.attackCooldown = 90;
}
};
self.attack = function () {
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 75;
bullet.targetX = player.x;
bullet.targetY = player.y;
bossBullets.push(bullet);
game.addChild(bullet);
};
return self;
});
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.targetX = 0;
self.targetY = 0;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
if (self.velocityX == 0 && self.velocityY == 0) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var BossLaser = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 120;
self.update = function () {
self.lifetime--;
graphics.alpha = self.lifetime / 120;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootCooldown = 0;
self.speed = 8;
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 300);
LK.getSound('hit').play();
if (self.health <= 0) {
self.health = 0;
isGameOver = true;
}
};
self.shoot = function () {
if (self.shootCooldown <= 0) {
var bullet = getPooledPlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 50;
playerBullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 10;
LK.getSound('shoot').play();
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Viggen = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('viggen', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x00ffff; // Cyan tint for Viggens
self.speed = 4;
self.homingForce = 0.2;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 300; // 5 seconds at 60fps
self.update = function () {
self.lifetime--;
// Homing behavior toward player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX += dx / distance * self.homingForce;
self.velocityY += dy / distance * self.homingForce;
}
// Apply velocity with speed limit
var currentSpeed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (currentSpeed > self.speed) {
self.velocityX = self.velocityX / currentSpeed * self.speed;
self.velocityY = self.velocityY / currentSpeed * self.speed;
}
self.x += self.velocityX;
self.y += self.velocityY;
// Fade out as lifetime decreases
graphics.alpha = Math.min(1, self.lifetime / 60);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
var player;
var currentBoss;
var currentBossLevel = 1;
var playerBullets = [];
var bossBullets = [];
var bossLasers = [];
var viggens = [];
// Object pools for performance optimization
var playerBulletPool = [];
var bossBulletPool = [];
var bossLaserPool = [];
var viggenPool = [];
function getPooledPlayerBullet() {
if (playerBulletPool.length > 0) {
return playerBulletPool.pop();
}
return new PlayerBullet();
}
function getPooledBossBullet() {
if (bossBulletPool.length > 0) {
return bossBulletPool.pop();
}
return new BossBullet();
}
function getPooledBossLaser() {
if (bossLaserPool.length > 0) {
return bossLaserPool.pop();
}
return new BossLaser();
}
function getPooledViggen() {
if (viggenPool.length > 0) {
return viggenPool.pop();
}
return new Viggen();
}
function returnToPool(bullet, pool) {
bullet.x = 0;
bullet.y = 0;
bullet.velocityX = 0;
bullet.velocityY = 0;
bullet.targetX = 0;
bullet.targetY = 0;
pool.push(bullet);
}
var bossDefeated = false;
var isGameOver = false;
var transitionTimer = 0;
var dragNode = null;
var bossNames = ['Shant', 'Glen', 'Octo', 'Benjaminsen', 'Upit Developer', 'The Upit Collective'];
var secretBossUnlocked = false;
var secretBossDefeated = storage.secretBossDefeated || false;
var sparklingWaterUnlocked = storage.sparklingWaterUnlocked || false;
// Music unlocking system
var unlockedMusic = storage.unlockedMusic || {
battleMusic: false,
goosandraTheme: false
};
var currentlyPlayingMusic = 'battleMusic';
// Easter egg variables
var konamiCode = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]; // Up Up Down Down Left Right Left Right B A
var konamiProgress = 0;
var rapidFireUnlocked = storage.rapidFireUnlocked || false;
var rainbowModeUnlocked = storage.rainbowModeUnlocked || false;
var clickCounter = 0;
var lastClickTime = 0;
var easterEggTimer = 0;
// UI Elements
var healthBar;
var bossHealthBar;
var levelText;
var instructionText;
// Initialize UI
healthBar = new Text2('Health: 100', {
size: 60,
fill: 0x00FF00
});
healthBar.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthBar);
bossHealthBar = new Text2('Boss Health: 0', {
size: 60,
fill: 0xFF0000
});
bossHealthBar.anchor.set(0.5, 0);
LK.gui.top.addChild(bossHealthBar);
// Add click handler to boss health bar for secret boss
bossHealthBar.down = function (x, y, obj) {
if (currentBossLevel == 3 && currentBoss && !sparklingWaterUnlocked) {
// Special Easter egg: Sparkling water gift during Octo fight
sparklingWaterUnlocked = true;
storage.sparklingWaterUnlocked = true;
// Create sparkling water gift effect
LK.effects.flashScreen(0x87CEEB, 1500);
// Show sparkling water message
var sparklingMsg = new Text2('๐ง SPARKLING WATER GIFTED! ๐ง\n\nA refreshing reward for your\nexceptional Easter egg hunting!', {
size: 50,
fill: 0x87CEEB
});
sparklingMsg.anchor.set(0.5, 0.5);
sparklingMsg.x = 1024;
sparklingMsg.y = 1366;
game.addChild(sparklingMsg);
// Animate sparkling water message
tween(sparklingMsg, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
sparklingMsg.destroy();
}
});
// Create bubbling particle effect
for (var i = 0; i < 15; i++) {
var bubble = LK.getAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + (Math.random() - 0.5) * 600,
y: 1366 + (Math.random() - 0.5) * 200,
scaleX: 0.5,
scaleY: 0.5
});
bubble.tint = 0x87CEEB; // Sky blue for water bubbles
game.addChild(bubble);
// Animate bubbles floating up
tween(bubble, {
y: bubble.y - 400 - Math.random() * 200,
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 3000 + Math.random() * 1000,
onFinish: function onFinish() {
bubble.destroy();
}
});
}
}
if (currentBossLevel == 2 && currentBoss && currentBoss.health <= 0 && !secretBossUnlocked) {
secretBossUnlocked = true;
// Spawn secret boss Goosandra
currentBoss.destroy();
currentBoss = game.addChild(new Goosandra());
currentBoss.x = 1024;
currentBoss.y = -300; // Start above screen for dramatic entrance
levelText.setText('Secret Boss: Goosandra');
bossNameText.setText('Secret Boss: Goosandra');
bossGuideText.setText('CHAOS! Two phases, homing Viggens, ultimate mayhem!');
bossLoreText.setText(getGoosandraLore());
// Play Goosandra's theme song
LK.playMusic('goosandraTheme');
// Unlock Goosandra theme after experiencing it
if (!unlockedMusic.goosandraTheme) {
unlockedMusic.goosandraTheme = true;
storage.unlockedMusic = unlockedMusic;
}
// Dramatic entrance cutscene
LK.effects.flashScreen(0x800080, 1000);
// Easter egg: Extra special effects if both Easter eggs are unlocked
if (rapidFireUnlocked && rainbowModeUnlocked) {
// Create rainbow particle effect
for (var i = 0; i < 20; i++) {
var particle = LK.getAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + (Math.random() - 0.5) * 400,
y: 1366 + (Math.random() - 0.5) * 400,
scaleX: 2,
scaleY: 2
});
particle.tint = Math.random() * 0xFFFFFF;
game.addChild(particle);
// Animate particles
tween(particle, {
x: particle.x + (Math.random() - 0.5) * 800,
y: particle.y + (Math.random() - 0.5) * 800,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 2000,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Special message for Easter egg hunters
var easterMsg = new Text2('๐ฅ TRUE EASTER EGG HUNTER! ๐ฅ', {
size: 50,
fill: 0xFF69B4
});
easterMsg.anchor.set(0.5, 0.5);
easterMsg.x = 1024;
easterMsg.y = 1100;
game.addChild(easterMsg);
tween(easterMsg, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
easterMsg.destroy();
}
});
}
// Make UI text dramatic entrance
tween(levelText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.bounceOut
});
tween(bossNameText, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 600,
easing: tween.elasticOut
});
// Goosandra dramatic entrance from above
tween(currentBoss, {
y: 400
}, {
duration: 2000,
easing: tween.bounceOut
});
// Add spinning entrance effect
tween(currentBoss, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.easeOut
});
// Pulsing size effect
tween(currentBoss, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(currentBoss, {
scaleX: 1,
scaleY: 1
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
}
};
levelText = new Text2('Boss Level: 1', {
size: 80,
fill: 0xFFFF00
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
instructionText = new Text2('Drag to move, tap to shoot!', {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
var bossNameText = new Text2('Boss 1: Shant', {
size: 70,
fill: 0xFF6600
});
bossNameText.anchor.set(0.5, 0);
bossNameText.y = 100;
LK.gui.top.addChild(bossNameText);
// Easter egg: Rapid click on boss name for rainbow mode
bossNameText.down = function (x, y, obj) {
var currentTime = Date.now();
if (currentTime - lastClickTime < 200) {
// Clicks within 200ms
clickCounter++;
if (clickCounter >= 7) {
if (!rainbowModeUnlocked) {
rainbowModeUnlocked = true;
storage.rainbowModeUnlocked = true;
LK.effects.flashScreen(0xFFFFFF, 1000);
// Show rainbow message
var rainbowMsg = new Text2('๐ RAINBOW MODE ACTIVATED! ๐', {
size: 60,
fill: 0xFF00FF
});
rainbowMsg.anchor.set(0.5, 0.5);
rainbowMsg.x = 1024;
rainbowMsg.y = 1366;
game.addChild(rainbowMsg);
// Animate message
tween(rainbowMsg, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 3000,
onFinish: function onFinish() {
rainbowMsg.destroy();
}
});
}
clickCounter = 0;
}
} else {
clickCounter = 1;
}
lastClickTime = currentTime;
};
var bossGuideText = new Text2('', {
size: 40,
fill: 0xAAAAA
});
bossGuideText.anchor.set(0.5, 0);
bossGuideText.y = 180;
LK.gui.top.addChild(bossGuideText);
var bossLoreText = new Text2('', {
size: 35,
fill: 0xCCCCCC
});
bossLoreText.anchor.set(0.5, 0);
bossLoreText.y = 240;
LK.gui.top.addChild(bossLoreText);
// Add lore button
var loreButton = new Text2('๐ LORE', {
size: 50,
fill: 0xFFD700
});
loreButton.anchor.set(0, 1);
loreButton.x = 50;
loreButton.y = -50;
LK.gui.bottomLeft.addChild(loreButton);
// Add guide button
var guideButton = new Text2('๐ GUIDE', {
size: 45,
fill: 0x00FF88
});
guideButton.anchor.set(0, 1);
guideButton.x = 50;
guideButton.y = -190;
LK.gui.bottomLeft.addChild(guideButton);
// Add boombox button
var boomboxButton = new Text2('๐ต BOOMBOX', {
size: 45,
fill: 0x00FFFF
});
boomboxButton.anchor.set(0, 1);
boomboxButton.x = 50;
boomboxButton.y = -120;
LK.gui.bottomLeft.addChild(boomboxButton);
// Lore display overlay
var loreOverlay = null;
var loreDisplayText = null;
var loreCloseButton = null;
var showingLore = false;
// Boombox overlay variables
var boomboxOverlay = null;
var boomboxDisplayText = null;
var boomboxCloseButton = null;
var showingBoombox = false;
var musicButtons = [];
// Guide overlay variables
var guideOverlay = null;
var guideDisplayText = null;
var guideCloseButton = null;
var showingGuide = false;
// Lore button click handler
loreButton.down = function (x, y, obj) {
if (!showingLore) {
showingLore = true;
// Create dark overlay
loreOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
loreOverlay.tint = 0x000000;
game.addChild(loreOverlay);
// Create lore text
var loreContent = getGameLore();
loreDisplayText = new Text2(loreContent, {
size: 45,
fill: 0xFFFFFF
});
loreDisplayText.anchor.set(0.5, 0.5);
loreDisplayText.x = 1024;
loreDisplayText.y = 1366;
game.addChild(loreDisplayText);
// Create close button
loreCloseButton = new Text2('โ CLOSE', {
size: 60,
fill: 0xFF4444
});
loreCloseButton.anchor.set(0.5, 0.5);
loreCloseButton.x = 1024;
loreCloseButton.y = 2400;
game.addChild(loreCloseButton);
// Close button handler
loreCloseButton.down = function (x, y, obj) {
closeLoreDisplay();
};
// Animate entrance
tween(loreOverlay, {
alpha: 0.9
}, {
duration: 500
});
tween(loreDisplayText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.bounceOut
});
tween(loreCloseButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.elasticOut
});
}
};
function closeLoreDisplay() {
if (showingLore) {
showingLore = false;
if (loreOverlay) {
loreOverlay.destroy();
loreOverlay = null;
}
if (loreDisplayText) {
loreDisplayText.destroy();
loreDisplayText = null;
}
if (loreCloseButton) {
loreCloseButton.destroy();
loreCloseButton = null;
}
}
}
// Guide button click handler
guideButton.down = function (x, y, obj) {
if (!showingGuide) {
showingGuide = true;
// Create dark overlay
guideOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
guideOverlay.tint = 0x000000;
game.addChild(guideOverlay);
// Create guide text
var guideContent = getGameGuide();
guideDisplayText = new Text2(guideContent, {
size: 45,
fill: 0x00FF88
});
guideDisplayText.anchor.set(0.5, 0.5);
guideDisplayText.x = 1024;
guideDisplayText.y = 1366;
game.addChild(guideDisplayText);
// Create close button
guideCloseButton = new Text2('โ CLOSE', {
size: 60,
fill: 0xFF4444
});
guideCloseButton.anchor.set(0.5, 0.5);
guideCloseButton.x = 1024;
guideCloseButton.y = 2400;
game.addChild(guideCloseButton);
// Close button handler
guideCloseButton.down = function (x, y, obj) {
closeGuideDisplay();
};
// Animate entrance
tween(guideOverlay, {
alpha: 0.9
}, {
duration: 500
});
tween(guideDisplayText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.bounceOut
});
tween(guideCloseButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.elasticOut
});
}
};
function closeGuideDisplay() {
if (showingGuide) {
showingGuide = false;
if (guideOverlay) {
guideOverlay.destroy();
guideOverlay = null;
}
if (guideDisplayText) {
guideDisplayText.destroy();
guideDisplayText = null;
}
if (guideCloseButton) {
guideCloseButton.destroy();
guideCloseButton = null;
}
}
}
function getGameGuide() {
return "๐ฎ HOW TO PLAY\n\n" + "โข Drag to move your green ship\n" + "โข Tap anywhere to shoot\n" + "โข Defeat all 6 bosses to win!\n\n" + "โ๏ธ BOSS STRATEGIES\n\n" + "Boss 1 (Shant): Simple horizontal movement\n" + "Stay mobile, avoid single shots\n\n" + "Boss 2 (Glen): Circular pattern, spread shots\n" + "Predict movement, dodge spread fire\n\n" + "Boss 3 (Octo): Aggressive homing + lasers\n" + "Keep distance, watch for laser telegraphs\n\n" + "Boss 4 (Benjaminsen): Spiral + burst attacks\n" + "Learn patterns, time your movements\n\n" + "Boss 5 (Upit Dev): Teleports + homing missiles\n" + "Stay alert, unpredictable positioning\n\n" + "Final Boss: Two phases, everything combined\n" + "Ultimate challenge, use all your skills!\n\n" + "๐ฅ EASTER EGG HINTS\n\n" + "โข Double-tap your ship for surprises...\n" + "โข Rapidly click boss names for effects...\n" + "โข Try clicking UI during boss fights...\n" + "โข Secret bosses exist for the worthy...\n" + "โข Music unlocks through experience...\n" + "โข Some rewards are refreshingly hidden...\n\n" + "Good luck, pilot! ๐";
}
// Boombox button click handler
boomboxButton.down = function (x, y, obj) {
if (!showingBoombox) {
showingBoombox = true;
// Create dark overlay
boomboxOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
boomboxOverlay.tint = 0x000000;
game.addChild(boomboxOverlay);
// Create boombox title
boomboxDisplayText = new Text2('๐ต MUSIC BOOMBOX ๐ต\n\nEach track must be experienced in its\nnatural environment before access!', {
size: 50,
fill: 0x00FFFF
});
boomboxDisplayText.anchor.set(0.5, 0);
boomboxDisplayText.x = 1024;
boomboxDisplayText.y = 400;
game.addChild(boomboxDisplayText);
// Create music control buttons
createMusicButtons();
// Create close button
boomboxCloseButton = new Text2('โ CLOSE', {
size: 60,
fill: 0xFF4444
});
boomboxCloseButton.anchor.set(0.5, 0.5);
boomboxCloseButton.x = 1024;
boomboxCloseButton.y = 2400;
game.addChild(boomboxCloseButton);
// Close button handler
boomboxCloseButton.down = function (x, y, obj) {
closeBoomboxDisplay();
};
// Animate entrance
tween(boomboxOverlay, {
alpha: 0.9
}, {
duration: 500
});
tween(boomboxDisplayText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.bounceOut
});
}
};
function createMusicButtons() {
// Clear existing buttons
for (var i = 0; i < musicButtons.length; i++) {
musicButtons[i].destroy();
}
musicButtons = [];
var yStart = 800;
var spacing = 200;
// Battle Music button
var battleButton = new Text2('โช Battle Music', {
size: 55,
fill: unlockedMusic.battleMusic ? 0x00FF00 : 0x888888
});
battleButton.anchor.set(0.5, 0.5);
battleButton.x = 1024;
battleButton.y = yStart;
game.addChild(battleButton);
musicButtons.push(battleButton);
if (unlockedMusic.battleMusic) {
battleButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'battleMusic';
LK.playMusic('battleMusic');
updateMusicButtonColors();
};
}
// Goosandra Theme button
var goosandraButton = new Text2('โซ Goosandra Theme', {
size: 55,
fill: unlockedMusic.goosandraTheme ? 0x800080 : 0x888888
});
goosandraButton.anchor.set(0.5, 0.5);
goosandraButton.x = 1024;
goosandraButton.y = yStart + spacing;
game.addChild(goosandraButton);
musicButtons.push(goosandraButton);
if (unlockedMusic.goosandraTheme) {
goosandraButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'goosandraTheme';
LK.playMusic('goosandraTheme');
updateMusicButtonColors();
};
}
// Status text
var statusText = new Text2(getUnlockStatus(), {
size: 40,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 1024;
statusText.y = yStart + spacing * 2;
game.addChild(statusText);
musicButtons.push(statusText);
updateMusicButtonColors();
}
function updateMusicButtonColors() {
if (musicButtons.length >= 2) {
// Battle music button
musicButtons[0].tint = currentlyPlayingMusic === 'battleMusic' && unlockedMusic.battleMusic ? 0xFFFF00 : unlockedMusic.battleMusic ? 0x00FF00 : 0x888888;
// Goosandra theme button
musicButtons[1].tint = currentlyPlayingMusic === 'goosandraTheme' && unlockedMusic.goosandraTheme ? 0xFFFF00 : unlockedMusic.goosandraTheme ? 0x800080 : 0x888888;
}
}
function getUnlockStatus() {
var unlocked = 0;
var total = 2;
if (unlockedMusic.battleMusic) unlocked++;
if (unlockedMusic.goosandraTheme) unlocked++;
return 'Unlocked: ' + unlocked + '/' + total + ' tracks';
}
function closeBoomboxDisplay() {
if (showingBoombox) {
showingBoombox = false;
if (boomboxOverlay) {
boomboxOverlay.destroy();
boomboxOverlay = null;
}
if (boomboxDisplayText) {
boomboxDisplayText.destroy();
boomboxDisplayText = null;
}
if (boomboxCloseButton) {
boomboxCloseButton.destroy();
boomboxCloseButton = null;
}
// Clear music buttons
for (var i = 0; i < musicButtons.length; i++) {
musicButtons[i].destroy();
}
musicButtons = [];
}
}
function getGameLore() {
return "THE UPIT WARS: GENESIS\n\n" + "Long ago, in the digital realm of FRVR,\n" + "the UPIT Collective ruled with algorithms\n" + "and code. But power corrupted their minds,\n" + "transforming them into digital tyrants.\n\n" + "Each member became a Boss, wielding\n" + "their programming skills as weapons:\n\n" + "โข Shant - The Beat Master\n" + "โข Glen - The Haskell God\n" + "โข Octo - The Hunter-Killer\n" + "โข Benjaminsen - The Strategist\n" + "โข The Upit Developer - Reality Bender\n" + "โข The Collective - Merged Consciousness\n\n" + "In the shadows lurks Goosandra,\n" + "the Certified Viggener, responsible\n" + "for multiple digital genocides.\n\n" + "You are humanity's last hope.\n" + "Defeat the UPIT Bosses and restore\n" + "balance to the digital realm!\n\n" + "May the code be with you...";
}
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2200;
// Easter egg: Double tap player for rapid fire
var playerClickCount = 0;
var playerLastClickTime = 0;
player.down = function (x, y, obj) {
var currentTime = Date.now();
if (currentTime - playerLastClickTime < 300) {
// Double tap within 300ms
playerClickCount++;
if (playerClickCount >= 2 && !rapidFireUnlocked) {
rapidFireUnlocked = true;
storage.rapidFireUnlocked = true;
LK.effects.flashObject(player, 0xFFFF00, 1000);
// Show rapid fire message
var rapidMsg = new Text2('โก RAPID FIRE UNLOCKED! โก', {
size: 60,
fill: 0xFFFF00
});
rapidMsg.anchor.set(0.5, 0.5);
rapidMsg.x = 1024;
rapidMsg.y = 1500;
game.addChild(rapidMsg);
// Animate message
tween(rapidMsg, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
rapidMsg.destroy();
}
});
playerClickCount = 0;
}
} else {
playerClickCount = 1;
}
playerLastClickTime = currentTime;
};
// Start first boss
function getBossGuide(bossLevel) {
if (bossLevel == 1) {
return 'Simple movement, single shots. Stay mobile!';
} else if (bossLevel == 2) {
return 'Circular pattern, spread shots. Predict the path!';
} else if (bossLevel == 3) {
return 'Homing movement, radial + laser attacks. Keep distance!';
} else if (bossLevel == 4) {
return 'Spiral movement, burst attacks. Watch for patterns!';
} else if (bossLevel == 5) {
return 'Teleports randomly, homing missiles + laser waves!';
} else if (bossLevel >= 6) {
return 'Two phases, radial bursts + targeted lasers!';
}
return '';
}
function getBossLore(bossLevel) {
if (bossLevel == 1) {
var baseLore = 'A simple UPIT creator, mostly known for The Last Beat';
if (rapidFireUnlocked && rainbowModeUnlocked) {
return baseLore + ' ๐ต *hums The Last Beat* ๐ต';
}
return baseLore;
} else if (bossLevel == 2) {
// Check if secret boss has been defeated to reveal Goosandra's name
if (secretBossDefeated) {
return 'Haskell god, Goosandra\'s friend';
} else {
return 'Haskell god, #########\'s friend';
}
} else if (bossLevel == 3) {
var baseLore = 'An aggressive hunter-killer with advanced targeting.';
if (rainbowModeUnlocked) {
return baseLore + ' ๐ Surprisingly, loves rainbow colors! ๐';
}
return baseLore;
} else if (bossLevel == 4) {
var baseLore = 'A master strategist who fights with calculated precision.';
if (rapidFireUnlocked) {
return baseLore + ' โก Respects your rapid fire skills! โก';
}
return baseLore;
} else if (bossLevel == 5) {
return 'The lead developer, wielding reality-bending code.';
} else if (bossLevel >= 6) {
var baseLore = 'The merged consciousness of all UPIT minds.';
if (rapidFireUnlocked && rainbowModeUnlocked) {
return baseLore + ' ๐ง โจ They are impressed by your Easter egg hunting! โจ๐ง ';
}
return baseLore;
}
return '';
}
function getGoosandraLore() {
return 'Certified Viggener, responsible for multiple genocides. Pounds sand with geese.';
}
function spawnBoss() {
if (currentBoss) {
currentBoss.destroy();
}
bossDefeated = false;
transitionTimer = 0;
// Clear bullets
for (var i = bossBullets.length - 1; i >= 0; i--) {
bossBullets[i].destroy();
bossBullets.splice(i, 1);
}
// Clear viggens
for (var i = viggens.length - 1; i >= 0; i--) {
viggens[i].destroy();
viggens.splice(i, 1);
}
// Spawn appropriate boss
if (currentBossLevel == 1) {
currentBoss = game.addChild(new Boss1());
currentBoss.x = 1024;
currentBoss.y = 400;
levelText.setText('Boss 1: Shant');
bossNameText.setText('Boss 1: Shant');
bossGuideText.setText(getBossGuide(1));
bossLoreText.setText(getBossLore(1));
} else if (currentBossLevel == 2) {
currentBoss = game.addChild(new Boss2());
currentBoss.x = 1024;
currentBoss.y = 600;
levelText.setText('Boss 2: Glen');
bossNameText.setText('Boss 2: Glen');
bossGuideText.setText(getBossGuide(2));
bossLoreText.setText(getBossLore(2));
} else if (currentBossLevel == 3) {
currentBoss = game.addChild(new Boss3());
currentBoss.x = 1024;
currentBoss.y = 500;
levelText.setText('Boss 3: Octo');
bossNameText.setText('Boss 3: Octo');
bossGuideText.setText(getBossGuide(3));
bossLoreText.setText(getBossLore(3));
} else if (currentBossLevel == 4) {
currentBoss = game.addChild(new Boss4());
currentBoss.x = 1024;
currentBoss.y = 500;
levelText.setText('Boss 4: Benjaminsen');
bossNameText.setText('Boss 4: Benjaminsen');
bossGuideText.setText(getBossGuide(4));
bossLoreText.setText(getBossLore(4));
} else if (currentBossLevel == 5) {
currentBoss = game.addChild(new Boss5());
currentBoss.x = 1024;
currentBoss.y = 400;
levelText.setText('Boss 5: Upit Developer');
bossNameText.setText('Boss 5: Upit Developer');
bossGuideText.setText(getBossGuide(5));
bossLoreText.setText(getBossLore(5));
} else if (currentBossLevel >= 6) {
currentBoss = game.addChild(new FinalBoss());
currentBoss.x = 1024;
currentBoss.y = 400;
levelText.setText('Final Boss: The Upit Collective');
bossNameText.setText('Final Boss: The Upit Collective');
bossGuideText.setText(getBossGuide(6));
bossLoreText.setText(getBossLore(6));
}
}
spawnBoss();
// Play battle music
LK.playMusic('battleMusic');
// Unlock battle music after experiencing it
if (!unlockedMusic.battleMusic) {
unlockedMusic.battleMusic = true;
storage.unlockedMusic = unlockedMusic;
}
// Event handlers
function handleMove(x, y, obj) {
if (dragNode && !isGameOver) {
dragNode.x = Math.max(40, Math.min(2008, x));
dragNode.y = Math.max(1000, Math.min(2692, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!isGameOver) {
dragNode = player;
handleMove(x, y, obj);
player.shoot();
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
if (isGameOver) {
LK.showGameOver();
return;
}
// Handle boss transition
if (bossDefeated) {
transitionTimer++;
if (transitionTimer > 120) {
currentBossLevel++;
if (currentBossLevel > 6) {
currentBossLevel = 6; // Stay at final boss
}
spawnBoss();
// Heal player slightly between bosses
player.health = Math.min(player.maxHealth, player.health + 20);
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.y < -50) {
game.removeChild(bullet);
returnToPool(bullet, playerBulletPool);
playerBullets.splice(i, 1);
continue;
}
// Check collision with boss
if (currentBoss && bullet.intersects(currentBoss)) {
currentBoss.takeDamage(25);
game.removeChild(bullet);
returnToPool(bullet, playerBulletPool);
playerBullets.splice(i, 1);
continue;
}
}
// Update boss bullets
for (var i = bossBullets.length - 1; i >= 0; i--) {
var bullet = bossBullets[i];
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
game.removeChild(bullet);
returnToPool(bullet, bossBulletPool);
bossBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
player.takeDamage(15);
game.removeChild(bullet);
returnToPool(bullet, bossBulletPool);
bossBullets.splice(i, 1);
continue;
}
}
// Update boss lasers
for (var i = bossLasers.length - 1; i >= 0; i--) {
var laser = bossLasers[i];
if (laser.lifetime <= 0) {
game.removeChild(laser);
laser.lifetime = 120; // Reset lifetime for pooling
returnToPool(laser, bossLaserPool);
bossLasers.splice(i, 1);
continue;
}
// Check collision with player
if (laser.intersects(player)) {
player.takeDamage(2); // Continuous damage
}
}
// Update viggens
for (var i = viggens.length - 1; i >= 0; i--) {
var viggen = viggens[i];
if (viggen.lifetime <= 0 || viggen.x < -50 || viggen.x > 2098 || viggen.y < -50 || viggen.y > 2782) {
game.removeChild(viggen);
viggen.lifetime = 300; // Reset lifetime for pooling
returnToPool(viggen, viggenPool);
viggens.splice(i, 1);
continue;
}
// Check collision with player
if (viggen.intersects(player)) {
player.takeDamage(20);
game.removeChild(viggen);
viggen.lifetime = 300; // Reset lifetime for pooling
returnToPool(viggen, viggenPool);
viggens.splice(i, 1);
continue;
}
}
// Update UI (only every 10 frames to reduce text update overhead)
if (LK.ticks % 10 === 0) {
healthBar.setText('Health: ' + player.health);
if (currentBoss) {
bossHealthBar.setText('Boss Health: ' + currentBoss.health);
}
}
// Easter egg: Pulsing effect for unlocked features
if (rapidFireUnlocked) {
var pulseScale = 1 + Math.sin(easterEggTimer * 0.15) * 0.1;
player.scaleX = pulseScale;
player.scaleY = pulseScale;
}
// Auto-shoot (with rapid fire Easter egg)
var shootInterval = rapidFireUnlocked ? 5 : 15;
if (LK.ticks % shootInterval == 0 && !isGameOver) {
player.shoot();
}
// Easter egg effects
easterEggTimer++;
// Rainbow mode effect
if (rainbowModeUnlocked) {
var rainbowColor = Math.sin(easterEggTimer * 0.1) * 0.5 + 0.5;
var r = Math.sin(easterEggTimer * 0.1) * 127 + 128;
var g = Math.sin(easterEggTimer * 0.1 + 2) * 127 + 128;
var b = Math.sin(easterEggTimer * 0.1 + 4) * 127 + 128;
var color = (Math.floor(r) << 16) + (Math.floor(g) << 8) + Math.floor(b);
// Apply rainbow effect to UI elements
if (easterEggTimer % 3 == 0) {
bossNameText.tint = color;
levelText.tint = color;
}
}
// Easter egg: Hidden developer message appears randomly
if (easterEggTimer % 3600 == 0) {
// Every 60 seconds
var messages = ["The developer is watching... ๐๏ธ", "Viggens are secretly plotting...", "Glen approves of your gameplay", "Goosandra whispers your name...", "The code is strong with this one", "FRVR games are the best games! ๐ฎ"];
var randomMsg = messages[Math.floor(Math.random() * messages.length)];
var devMsg = new Text2(randomMsg, {
size: 40,
fill: 0x00FFFF
});
devMsg.anchor.set(0.5, 0.5);
devMsg.x = 1024;
devMsg.y = 2000;
devMsg.alpha = 0;
game.addChild(devMsg);
// Fade in and out
tween(devMsg, {
alpha: 1,
y: 1800
}, {
duration: 1000,
onFinish: function onFinish() {
tween(devMsg, {
alpha: 0,
y: 1600
}, {
duration: 1000,
onFinish: function onFinish() {
devMsg.destroy();
}
});
}
});
}
};