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", {
inventory: {},
inventoryUnlocked: false
});
/****
* 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);
// Play victory fanfare
LK.playMusic('victoryFanfare', {
loop: false
});
// Unlock victory fanfare
if (!unlockedMusic.victoryFanfare) {
unlockedMusic.victoryFanfare = true;
storage.unlockedMusic = unlockedMusic;
}
// Delay showing win screen to let fanfare play
LK.setTimeout(function () {
LK.showYouWin();
}, 3000);
};
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 Item = Container.expand(function () {
var self = Container.call(this);
self.itemId = '';
self.itemName = '';
self.itemType = 'common';
self.description = '';
self.rarity = 'common';
self.collectEffect = function () {
// Override in specific items
};
return self;
});
var ViggenCrystal = Item.expand(function () {
var self = Item.call(this);
var graphics = self.attachAsset('viggen', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x800080;
graphics.scaleX = 0.8;
graphics.scaleY = 0.8;
self.itemId = 'viggen_crystal';
self.itemName = 'Viggen Crystal';
self.itemType = 'trophy';
self.description = 'A crystallized essence of defeated Viggens';
self.rarity = 'epic';
self.collectEffect = function () {
LK.effects.flashObject(player, 0x800080, 1000);
addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
};
return self;
});
var Soda = Item.expand(function () {
var self = Item.call(this);
var graphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF4500; // Orange red for soda
graphics.scaleX = 1.3;
graphics.scaleY = 1.3;
self.itemId = 'soda';
self.itemName = 'Soda';
self.itemType = 'consumable';
self.description = 'Restores 30 health and increases fire rate for 10 seconds';
self.rarity = 'common';
self.healAmount = 30;
self.fireRateBoostDuration = 600; // 10 seconds at 60fps
self.collectEffect = function () {
LK.effects.flashObject(player, 0xFF4500, 600);
addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
};
return self;
});
var PowerCore = Item.expand(function () {
var self = Item.call(this);
var graphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFD700;
graphics.scaleX = 2;
graphics.scaleY = 2;
self.itemId = 'power_core';
self.itemName = 'Power Core';
self.itemType = 'upgrade';
self.description = 'Increases damage permanently';
self.rarity = 'rare';
self.collectEffect = function () {
LK.effects.flashObject(player, 0xFFD700, 800);
addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
};
return self;
});
var HealthPotion = Item.expand(function () {
var self = Item.call(this);
var graphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x00FF00;
graphics.scaleX = 1.5;
graphics.scaleY = 1.5;
self.itemId = 'health_potion';
self.itemName = 'Health Potion';
self.itemType = 'consumable';
self.description = 'Restores 50 health points';
self.rarity = 'common';
self.healAmount = 50;
self.collectEffect = function () {
LK.effects.flashObject(player, 0x00FF00, 500);
addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
};
return self;
});
var EnergyDrink = Item.expand(function () {
var self = Item.call(this);
var graphics = self.attachAsset('viggen', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x00BFFF; // Deep sky blue for energy
graphics.scaleX = 0.6;
graphics.scaleY = 0.6;
self.itemId = 'energy_drink';
self.itemName = 'Energy Drink';
self.itemType = 'consumable';
self.description = 'Increases movement speed for 15 seconds';
self.rarity = 'rare';
self.speedBoostDuration = 900; // 15 seconds at 60fps
self.collectEffect = function () {
LK.effects.flashObject(player, 0x00BFFF, 700);
addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
};
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,
epicFinale: false,
mysteryTheme: false,
victoryFanfare: 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;
var energyDrinkActive = false;
var energyDrinkTimer = 0;
var basePlayerSpeed = 8;
var sodaFireRateActive = false;
var sodaFireRateTimer = 0;
// UI Elements
var healthBar;
var bossHealthBar;
var levelText;
var instructionText;
// Inventory system variables
var gameInventory = storage.inventory || {};
var inventoryUnlocked = storage.inventoryUnlocked || false;
var droppedItems = [];
var showingInventory = false;
var inventoryOverlay = null;
var inventoryDisplayText = null;
var inventoryCloseButton = null;
var inventoryItems = [];
// Inventory system functions
function addToInventory(itemId, itemName, itemType, description, rarity) {
if (!gameInventory[itemId]) {
gameInventory[itemId + '_name'] = itemName;
gameInventory[itemId + '_type'] = itemType;
gameInventory[itemId + '_description'] = description;
gameInventory[itemId + '_rarity'] = rarity;
gameInventory[itemId + '_quantity'] = 0;
}
gameInventory[itemId + '_quantity']++;
storage.inventory = gameInventory;
// Show collection message
var collectMsg = new Text2('+ ' + itemName, {
size: 45,
fill: getRarityColor(rarity)
});
collectMsg.anchor.set(0.5, 0.5);
collectMsg.x = 1024;
collectMsg.y = 1800;
collectMsg.alpha = 0;
game.addChild(collectMsg);
tween(collectMsg, {
alpha: 1,
y: 1600,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
onFinish: function onFinish() {
tween(collectMsg, {
alpha: 0,
y: 1400
}, {
duration: 600,
onFinish: function onFinish() {
collectMsg.destroy();
}
});
}
});
// Unlock inventory after first item
if (!inventoryUnlocked) {
inventoryUnlocked = true;
storage.inventoryUnlocked = true;
var unlockMsg = new Text2('📦 INVENTORY UNLOCKED! 📦\nCheck the INVENTORY button!', {
size: 50,
fill: 0xFFD700
});
unlockMsg.anchor.set(0.5, 0.5);
unlockMsg.x = 1024;
unlockMsg.y = 1366;
game.addChild(unlockMsg);
tween(unlockMsg, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0
}, {
duration: 3000,
onFinish: function onFinish() {
unlockMsg.destroy();
}
});
}
}
function getRarityColor(rarity) {
if (rarity === 'common') return 0xFFFFFF;
if (rarity === 'rare') return 0x0099FF;
if (rarity === 'epic') return 0x9933FF;
if (rarity === 'legendary') return 0xFF6600;
return 0xFFFFFF;
}
function useItem(itemId) {
var quantity = gameInventory[itemId + '_quantity'] || 0;
if (quantity <= 0) return false;
if (itemId === 'health_potion') {
player.health = Math.min(player.maxHealth, player.health + 50);
LK.effects.flashObject(player, 0x00FF00, 500);
gameInventory[itemId + '_quantity']--;
if (gameInventory[itemId + '_quantity'] <= 0) {
delete gameInventory[itemId + '_name'];
delete gameInventory[itemId + '_type'];
delete gameInventory[itemId + '_description'];
delete gameInventory[itemId + '_rarity'];
delete gameInventory[itemId + '_quantity'];
}
storage.inventory = gameInventory;
return true;
} else if (itemId === 'energy_drink') {
if (!energyDrinkActive) {
energyDrinkActive = true;
energyDrinkTimer = 900; // 15 seconds
player.speed = basePlayerSpeed * 1.8; // 80% speed increase
LK.effects.flashObject(player, 0x00BFFF, 700);
// Show speed boost message
var speedMsg = new Text2('⚡ SPEED BOOST ACTIVE! ⚡', {
size: 50,
fill: 0x00BFFF
});
speedMsg.anchor.set(0.5, 0.5);
speedMsg.x = 1024;
speedMsg.y = 1800;
game.addChild(speedMsg);
tween(speedMsg, {
alpha: 0,
y: 1600,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 2000,
onFinish: function onFinish() {
speedMsg.destroy();
}
});
gameInventory[itemId + '_quantity']--;
if (gameInventory[itemId + '_quantity'] <= 0) {
delete gameInventory[itemId + '_name'];
delete gameInventory[itemId + '_type'];
delete gameInventory[itemId + '_description'];
delete gameInventory[itemId + '_rarity'];
delete gameInventory[itemId + '_quantity'];
}
storage.inventory = gameInventory;
return true;
}
} else if (itemId === 'soda') {
// Heal first
player.health = Math.min(player.maxHealth, player.health + 30);
LK.effects.flashObject(player, 0xFF4500, 600);
// Activate fire rate boost
if (!sodaFireRateActive) {
sodaFireRateActive = true;
sodaFireRateTimer = 600; // 10 seconds
// Show fire rate boost message
var fireRateMsg = new Text2('🥤 FIRE RATE BOOST! 🥤', {
size: 50,
fill: 0xFF4500
});
fireRateMsg.anchor.set(0.5, 0.5);
fireRateMsg.x = 1024;
fireRateMsg.y = 1800;
game.addChild(fireRateMsg);
tween(fireRateMsg, {
alpha: 0,
y: 1600,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 2000,
onFinish: function onFinish() {
fireRateMsg.destroy();
}
});
}
gameInventory[itemId + '_quantity']--;
if (gameInventory[itemId + '_quantity'] <= 0) {
delete gameInventory[itemId + '_name'];
delete gameInventory[itemId + '_type'];
delete gameInventory[itemId + '_description'];
delete gameInventory[itemId + '_rarity'];
delete gameInventory[itemId + '_quantity'];
}
storage.inventory = gameInventory;
return true;
}
return false;
}
function spawnRandomItem(x, y) {
if (Math.random() < 0.3) {
// 30% chance to spawn item
var itemType = Math.random();
var newItem;
if (itemType < 0.3) {
newItem = new HealthPotion();
} else if (itemType < 0.5) {
newItem = new PowerCore();
} else if (itemType < 0.65) {
newItem = new EnergyDrink();
} else if (itemType < 0.85) {
newItem = new Soda();
} else {
newItem = new ViggenCrystal();
}
newItem.x = Math.max(100, Math.min(1948, x + (Math.random() - 0.5) * 200));
newItem.y = Math.max(1200, Math.min(2600, y + (Math.random() - 0.5) * 200));
newItem.collectTimer = 600; // 10 seconds to collect
droppedItems.push(newItem);
game.addChild(newItem);
// Animate spawn
newItem.alpha = 0;
newItem.scaleX = 0;
newItem.scaleY = 0;
tween(newItem, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.bounceOut
});
}
}
// 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;
// Cancel the normal boss defeat process
bossDefeated = false;
transitionTimer = 0;
// Destroy Glen and spawn 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);
// Add inventory button
var inventoryButton = new Text2('📦 INVENTORY', {
size: 45,
fill: inventoryUnlocked ? 0xFFD700 : 0x666666
});
inventoryButton.anchor.set(0, 1);
inventoryButton.x = 50;
inventoryButton.y = -260;
LK.gui.bottomLeft.addChild(inventoryButton);
// 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;
}
}
}
// Inventory button click handler
inventoryButton.down = function (x, y, obj) {
if (inventoryUnlocked && !showingInventory) {
showingInventory = true;
// Create dark overlay
inventoryOverlay = LK.getAsset('boss1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 13.65,
scaleY: 18.21,
alpha: 0.8
});
inventoryOverlay.tint = 0x000000;
game.addChild(inventoryOverlay);
// Create inventory display
createInventoryDisplay();
// Create close button
inventoryCloseButton = new Text2('❌ CLOSE', {
size: 60,
fill: 0xFF4444
});
inventoryCloseButton.anchor.set(0.5, 0.5);
inventoryCloseButton.x = 1024;
inventoryCloseButton.y = 2400;
game.addChild(inventoryCloseButton);
inventoryCloseButton.down = function (x, y, obj) {
closeInventoryDisplay();
};
// Animate entrance
tween(inventoryOverlay, {
alpha: 0.9
}, {
duration: 500
});
}
};
function createInventoryDisplay() {
// Clear existing inventory items
for (var i = 0; i < inventoryItems.length; i++) {
inventoryItems[i].destroy();
}
inventoryItems = [];
// Create title
inventoryDisplayText = new Text2('📦 INVENTORY 📦\n\nCollected Items:', {
size: 50,
fill: 0xFFD700
});
inventoryDisplayText.anchor.set(0.5, 0);
inventoryDisplayText.x = 1024;
inventoryDisplayText.y = 400;
game.addChild(inventoryDisplayText);
inventoryItems.push(inventoryDisplayText);
var yPos = 700;
var itemCount = 0;
// Display each inventory item
var processedItems = {};
for (var key in gameInventory) {
if (key.endsWith('_quantity')) {
var itemId = key.replace('_quantity', '');
var quantity = gameInventory[key];
if (quantity > 0) {
var itemName = gameInventory[itemId + '_name'] || 'Unknown';
var itemDescription = gameInventory[itemId + '_description'] || '';
var itemType = gameInventory[itemId + '_type'] || 'common';
var itemRarity = gameInventory[itemId + '_rarity'] || 'common';
var itemText = new Text2(itemName + ' x' + quantity + '\n' + itemDescription, {
size: 40,
fill: getRarityColor(itemRarity)
});
itemText.anchor.set(0.5, 0.5);
itemText.x = 1024;
itemText.y = yPos;
game.addChild(itemText);
inventoryItems.push(itemText);
// Add use button for consumables
if (itemType === 'consumable') {
var useButton = new Text2('USE', {
size: 35,
fill: 0x00FF00
});
useButton.anchor.set(0.5, 0.5);
useButton.x = 1400;
useButton.y = yPos;
game.addChild(useButton);
inventoryItems.push(useButton);
// Create closure to capture itemId
(function (capturedItemId) {
useButton.down = function (x, y, obj) {
if (useItem(capturedItemId)) {
closeInventoryDisplay();
// Reopen to refresh display
LK.setTimeout(function () {
inventoryButton.down(0, 0, {});
}, 100);
}
};
})(itemId);
}
yPos += 120;
itemCount++;
}
}
}
if (itemCount === 0) {
var emptyText = new Text2('No items collected yet!\nDefeat bosses and collect drops!', {
size: 45,
fill: 0x888888
});
emptyText.anchor.set(0.5, 0.5);
emptyText.x = 1024;
emptyText.y = 1000;
game.addChild(emptyText);
inventoryItems.push(emptyText);
}
}
function closeInventoryDisplay() {
if (showingInventory) {
showingInventory = false;
if (inventoryOverlay) {
inventoryOverlay.destroy();
inventoryOverlay = null;
}
// Clear all inventory display items
for (var i = 0; i < inventoryItems.length; i++) {
inventoryItems[i].destroy();
}
inventoryItems = [];
if (inventoryCloseButton) {
inventoryCloseButton.destroy();
inventoryCloseButton = 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 = 700;
var spacing = 120;
// Battle Music button
var battleButton = new Text2('♪ Battle Music', {
size: 50,
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();
};
}
// Mystery Theme button
var mysteryButton = new Text2('♪ Mystery Theme', {
size: 50,
fill: unlockedMusic.mysteryTheme ? 0x4B0082 : 0x888888
});
mysteryButton.anchor.set(0.5, 0.5);
mysteryButton.x = 1024;
mysteryButton.y = yStart + spacing;
game.addChild(mysteryButton);
musicButtons.push(mysteryButton);
if (unlockedMusic.mysteryTheme) {
mysteryButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'mysteryTheme';
LK.playMusic('mysteryTheme');
updateMusicButtonColors();
};
}
// Epic Finale button
var epicButton = new Text2('♫ Epic Finale', {
size: 50,
fill: unlockedMusic.epicFinale ? 0xFF4500 : 0x888888
});
epicButton.anchor.set(0.5, 0.5);
epicButton.x = 1024;
epicButton.y = yStart + spacing * 2;
game.addChild(epicButton);
musicButtons.push(epicButton);
if (unlockedMusic.epicFinale) {
epicButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'epicFinale';
LK.playMusic('epicFinale');
updateMusicButtonColors();
};
}
// Goosandra Theme button
var goosandraButton = new Text2('♫ Goosandra Theme', {
size: 50,
fill: unlockedMusic.goosandraTheme ? 0x800080 : 0x888888
});
goosandraButton.anchor.set(0.5, 0.5);
goosandraButton.x = 1024;
goosandraButton.y = yStart + spacing * 3;
game.addChild(goosandraButton);
musicButtons.push(goosandraButton);
if (unlockedMusic.goosandraTheme) {
goosandraButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'goosandraTheme';
LK.playMusic('goosandraTheme');
updateMusicButtonColors();
};
}
// Victory Fanfare button
var victoryButton = new Text2('♫ Victory Fanfare', {
size: 50,
fill: unlockedMusic.victoryFanfare ? 0xFFD700 : 0x888888
});
victoryButton.anchor.set(0.5, 0.5);
victoryButton.x = 1024;
victoryButton.y = yStart + spacing * 4;
game.addChild(victoryButton);
musicButtons.push(victoryButton);
if (unlockedMusic.victoryFanfare) {
victoryButton.down = function (x, y, obj) {
currentlyPlayingMusic = 'victoryFanfare';
LK.playMusic('victoryFanfare', {
loop: false
});
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 * 5;
game.addChild(statusText);
musicButtons.push(statusText);
updateMusicButtonColors();
}
function updateMusicButtonColors() {
if (musicButtons.length >= 5) {
// Battle music button
musicButtons[0].tint = currentlyPlayingMusic === 'battleMusic' && unlockedMusic.battleMusic ? 0xFFFF00 : unlockedMusic.battleMusic ? 0x00FF00 : 0x888888;
// Mystery theme button
musicButtons[1].tint = currentlyPlayingMusic === 'mysteryTheme' && unlockedMusic.mysteryTheme ? 0xFFFF00 : unlockedMusic.mysteryTheme ? 0x4B0082 : 0x888888;
// Epic finale button
musicButtons[2].tint = currentlyPlayingMusic === 'epicFinale' && unlockedMusic.epicFinale ? 0xFFFF00 : unlockedMusic.epicFinale ? 0xFF4500 : 0x888888;
// Goosandra theme button
musicButtons[3].tint = currentlyPlayingMusic === 'goosandraTheme' && unlockedMusic.goosandraTheme ? 0xFFFF00 : unlockedMusic.goosandraTheme ? 0x800080 : 0x888888;
// Victory fanfare button
musicButtons[4].tint = currentlyPlayingMusic === 'victoryFanfare' && unlockedMusic.victoryFanfare ? 0xFFFF00 : unlockedMusic.victoryFanfare ? 0xFFD700 : 0x888888;
}
}
function getUnlockStatus() {
var unlocked = 0;
var total = 5;
if (unlockedMusic.battleMusic) unlocked++;
if (unlockedMusic.goosandraTheme) unlocked++;
if (unlockedMusic.epicFinale) unlocked++;
if (unlockedMusic.mysteryTheme) unlocked++;
if (unlockedMusic.victoryFanfare) 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;
};
// Starting cutscene variables
var cutsceneActive = true;
var cutsceneTimer = 0;
var cutsceneText1 = null;
var cutsceneText2 = null;
var cutsceneText3 = null;
// Create starting cutscene
function startCutscene() {
// Hide player during cutscene
player.alpha = 0;
// First text: Title
cutsceneText1 = new Text2('THE UPIT WARS', {
size: 120,
fill: 0xFFFF00
});
cutsceneText1.anchor.set(0.5, 0.5);
cutsceneText1.x = 1024;
cutsceneText1.y = 800;
cutsceneText1.alpha = 0;
game.addChild(cutsceneText1);
// Second text: Subtitle
cutsceneText2 = new Text2('GENESIS', {
size: 80,
fill: 0xFF6600
});
cutsceneText2.anchor.set(0.5, 0.5);
cutsceneText2.x = 1024;
cutsceneText2.y = 950;
cutsceneText2.alpha = 0;
game.addChild(cutsceneText2);
// Third text: Mission briefing
cutsceneText3 = new Text2('Defeat the UPIT Collective\nSave the digital realm', {
size: 60,
fill: 0x00FFFF
});
cutsceneText3.anchor.set(0.5, 0.5);
cutsceneText3.x = 1024;
cutsceneText3.y = 1200;
cutsceneText3.alpha = 0;
game.addChild(cutsceneText3);
// Animate title entrance
tween(cutsceneText1, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut
});
// Animate subtitle entrance (delayed)
LK.setTimeout(function () {
tween(cutsceneText2, {
alpha: 1,
y: 950
}, {
duration: 800,
easing: tween.bounceOut
});
}, 500);
// Animate mission briefing (delayed)
LK.setTimeout(function () {
tween(cutsceneText3, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
easing: tween.elasticOut
});
}, 1200);
// Flash screen effect
LK.setTimeout(function () {
LK.effects.flashScreen(0x000088, 800);
}, 2000);
// Start fade out sequence
LK.setTimeout(function () {
// Fade out all cutscene text
tween(cutsceneText1, {
alpha: 0,
y: 600
}, {
duration: 1000,
easing: tween.easeIn
});
tween(cutsceneText2, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1000,
easing: tween.easeIn
});
tween(cutsceneText3, {
alpha: 0,
y: 1400
}, {
duration: 1000,
easing: tween.easeIn
});
// Reveal player ship with dramatic entrance
tween(player, {
alpha: 1,
y: 2200,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Return player to normal size
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
}
});
// Clean up cutscene after animations complete
LK.setTimeout(function () {
if (cutsceneText1) {
cutsceneText1.destroy();
cutsceneText1 = null;
}
if (cutsceneText2) {
cutsceneText2.destroy();
cutsceneText2 = null;
}
if (cutsceneText3) {
cutsceneText3.destroy();
cutsceneText3 = null;
}
cutsceneActive = false;
}, 1500);
}, 3500);
}
// Start the cutscene
startCutscene();
// Start with soft ambient music during cutscene
LK.playMusic('mysteryTheme', {
volume: 0.3,
fade: {
start: 0,
end: 0.3,
duration: 2000
}
});
// Transition to battle music after cutscene ends
LK.setTimeout(function () {
if (!secretBossUnlocked) {
// Only if not fighting secret boss
LK.playMusic('battleMusic', {
fade: {
start: 0,
end: 1,
duration: 2000
}
});
currentlyPlayingMusic = 'battleMusic';
// Unlock battle music
if (!unlockedMusic.battleMusic) {
unlockedMusic.battleMusic = true;
storage.unlockedMusic = unlockedMusic;
}
}
}, 5000); // 5 seconds - after cutscene completes
// 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));
}
// Choose appropriate music for boss level
// Only change music if user hasn't manually selected music from boombox
var shouldChangeMusicForBoss = true;
// Check if user has manually selected music from boombox by comparing with expected boss music
var expectedBossMusic = '';
if (currentBossLevel >= 6) {
expectedBossMusic = 'epicFinale';
} else if (currentBossLevel == 4 || currentBossLevel == 5) {
expectedBossMusic = 'mysteryTheme';
} else {
expectedBossMusic = 'battleMusic';
}
// If currently playing music doesn't match what boss would normally play, preserve user choice
if (currentlyPlayingMusic !== expectedBossMusic && (currentlyPlayingMusic === 'battleMusic' || currentlyPlayingMusic === 'goosandraTheme' || currentlyPlayingMusic === 'epicFinale' || currentlyPlayingMusic === 'mysteryTheme' || currentlyPlayingMusic === 'victoryFanfare')) {
shouldChangeMusicForBoss = false;
}
if (shouldChangeMusicForBoss) {
// LK.playMusic automatically stops any currently playing music
if (currentBossLevel >= 6) {
// Play epic finale music for final boss
LK.playMusic('epicFinale', {
fade: {
start: 0,
end: 1,
duration: 1500
}
});
currentlyPlayingMusic = 'epicFinale';
// Unlock epic finale music
if (!unlockedMusic.epicFinale) {
unlockedMusic.epicFinale = true;
storage.unlockedMusic = unlockedMusic;
}
} else if (currentBossLevel == 4 || currentBossLevel == 5) {
// Play mystery theme for mid-tier bosses
LK.playMusic('mysteryTheme', {
fade: {
start: 0,
end: 0.8,
duration: 1000
}
});
currentlyPlayingMusic = 'mysteryTheme';
// Unlock mystery theme
if (!unlockedMusic.mysteryTheme) {
unlockedMusic.mysteryTheme = true;
storage.unlockedMusic = unlockedMusic;
}
} else {
// Play regular battle music for early bosses (levels 1-3)
// Only play if not already playing battle music to avoid restart
if (currentlyPlayingMusic !== 'battleMusic') {
LK.playMusic('battleMusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
currentlyPlayingMusic = 'battleMusic';
}
// Unlock battle music after experiencing it
if (!unlockedMusic.battleMusic) {
unlockedMusic.battleMusic = true;
storage.unlockedMusic = unlockedMusic;
}
}
} else {
// Still unlock music tracks even if not playing them
if (currentBossLevel >= 6 && !unlockedMusic.epicFinale) {
unlockedMusic.epicFinale = true;
storage.unlockedMusic = unlockedMusic;
} else if ((currentBossLevel == 4 || currentBossLevel == 5) && !unlockedMusic.mysteryTheme) {
unlockedMusic.mysteryTheme = true;
storage.unlockedMusic = unlockedMusic;
} else if (currentBossLevel <= 3 && !unlockedMusic.battleMusic) {
unlockedMusic.battleMusic = true;
storage.unlockedMusic = unlockedMusic;
}
}
}
spawnBoss();
// Event handlers
function handleMove(x, y, obj) {
if (dragNode && !isGameOver && !cutsceneActive) {
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 && !cutsceneActive) {
dragNode = player;
handleMove(x, y, obj);
player.shoot();
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
// Handle cutscene
if (cutsceneActive) {
cutsceneTimer++;
return; // Skip all game logic during cutscene
}
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();
// Spawn items for the new boss to ensure availability
if (currentBoss) {
spawnRandomItem(currentBoss.x, currentBoss.y);
spawnRandomItem(currentBoss.x + 100, currentBoss.y + 100);
}
// Heal player slightly between bosses
player.health = Math.min(player.maxHealth, player.health + 20);
}
}
// Update dropped items
for (var i = droppedItems.length - 1; i >= 0; i--) {
var item = droppedItems[i];
item.collectTimer--;
// Pulsing effect
var pulse = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
item.scaleX = pulse;
item.scaleY = pulse;
// Fade out as time runs out
if (item.collectTimer < 120) {
item.alpha = item.collectTimer / 120;
}
// Remove expired items
if (item.collectTimer <= 0) {
item.destroy();
droppedItems.splice(i, 1);
continue;
}
// Check collection by player
if (item.intersects(player)) {
item.collectEffect();
item.destroy();
droppedItems.splice(i, 1);
continue;
}
}
// 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);
}
// Update inventory button color
inventoryButton.tint = inventoryUnlocked ? 0xFFD700 : 0x666666;
}
// 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 and soda boost)
var shootInterval = rapidFireUnlocked ? 5 : 15;
if (sodaFireRateActive) {
shootInterval = Math.max(3, Math.floor(shootInterval * 0.6)); // 40% faster fire rate
}
if (LK.ticks % shootInterval == 0 && !isGameOver) {
player.shoot();
}
// Handle energy drink effect
if (energyDrinkActive) {
energyDrinkTimer--;
// Add sparkling particle effect while active
if (LK.ticks % 10 === 0) {
var sparkle = LK.getAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x + (Math.random() - 0.5) * 80,
y: player.y + (Math.random() - 0.5) * 80,
scaleX: 0.3,
scaleY: 0.3
});
sparkle.tint = 0x00BFFF;
game.addChild(sparkle);
tween(sparkle, {
alpha: 0,
y: sparkle.y - 100,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 800,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
if (energyDrinkTimer <= 0) {
energyDrinkActive = false;
player.speed = basePlayerSpeed; // Reset to normal speed
// Show effect ended message
var endMsg = new Text2('Speed boost ended', {
size: 40,
fill: 0x888888
});
endMsg.anchor.set(0.5, 0.5);
endMsg.x = 1024;
endMsg.y = 1900;
game.addChild(endMsg);
tween(endMsg, {
alpha: 0,
y: 1700
}, {
duration: 1500,
onFinish: function onFinish() {
endMsg.destroy();
}
});
}
}
// Handle soda fire rate boost effect
if (sodaFireRateActive) {
sodaFireRateTimer--;
// Add fizzy particle effect while active
if (LK.ticks % 15 === 0) {
var fizz = LK.getAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x + (Math.random() - 0.5) * 60,
y: player.y + (Math.random() - 0.5) * 60,
scaleX: 0.2,
scaleY: 0.2
});
fizz.tint = 0xFF4500;
game.addChild(fizz);
tween(fizz, {
alpha: 0,
y: fizz.y - 80,
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 600,
onFinish: function onFinish() {
fizz.destroy();
}
});
}
if (sodaFireRateTimer <= 0) {
sodaFireRateActive = false;
// Show effect ended message
var endMsg = new Text2('Fire rate boost ended', {
size: 40,
fill: 0x888888
});
endMsg.anchor.set(0.5, 0.5);
endMsg.x = 1024;
endMsg.y = 1900;
game.addChild(endMsg);
tween(endMsg, {
alpha: 0,
y: 1700
}, {
duration: 1500,
onFinish: function onFinish() {
endMsg.destroy();
}
});
}
}
// 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();
}
});
}
});
}
}; ===================================================================
--- original.js
+++ change.js
@@ -659,8 +659,30 @@
addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
};
return self;
});
+var Soda = Item.expand(function () {
+ var self = Item.call(this);
+ var graphics = self.attachAsset('playerBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ graphics.tint = 0xFF4500; // Orange red for soda
+ graphics.scaleX = 1.3;
+ graphics.scaleY = 1.3;
+ self.itemId = 'soda';
+ self.itemName = 'Soda';
+ self.itemType = 'consumable';
+ self.description = 'Restores 30 health and increases fire rate for 10 seconds';
+ self.rarity = 'common';
+ self.healAmount = 30;
+ self.fireRateBoostDuration = 600; // 10 seconds at 60fps
+ self.collectEffect = function () {
+ LK.effects.flashObject(player, 0xFF4500, 600);
+ addToInventory(self.itemId, self.itemName, self.itemType, self.description, self.rarity);
+ };
+ return self;
+});
var PowerCore = Item.expand(function () {
var self = Item.call(this);
var graphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
@@ -889,8 +911,10 @@
var easterEggTimer = 0;
var energyDrinkActive = false;
var energyDrinkTimer = 0;
var basePlayerSpeed = 8;
+var sodaFireRateActive = false;
+var sodaFireRateTimer = 0;
// UI Elements
var healthBar;
var bossHealthBar;
var levelText;
@@ -1027,22 +1051,63 @@
}
storage.inventory = gameInventory;
return true;
}
+ } else if (itemId === 'soda') {
+ // Heal first
+ player.health = Math.min(player.maxHealth, player.health + 30);
+ LK.effects.flashObject(player, 0xFF4500, 600);
+ // Activate fire rate boost
+ if (!sodaFireRateActive) {
+ sodaFireRateActive = true;
+ sodaFireRateTimer = 600; // 10 seconds
+ // Show fire rate boost message
+ var fireRateMsg = new Text2('🥤 FIRE RATE BOOST! 🥤', {
+ size: 50,
+ fill: 0xFF4500
+ });
+ fireRateMsg.anchor.set(0.5, 0.5);
+ fireRateMsg.x = 1024;
+ fireRateMsg.y = 1800;
+ game.addChild(fireRateMsg);
+ tween(fireRateMsg, {
+ alpha: 0,
+ y: 1600,
+ scaleX: 1.3,
+ scaleY: 1.3
+ }, {
+ duration: 2000,
+ onFinish: function onFinish() {
+ fireRateMsg.destroy();
+ }
+ });
+ }
+ gameInventory[itemId + '_quantity']--;
+ if (gameInventory[itemId + '_quantity'] <= 0) {
+ delete gameInventory[itemId + '_name'];
+ delete gameInventory[itemId + '_type'];
+ delete gameInventory[itemId + '_description'];
+ delete gameInventory[itemId + '_rarity'];
+ delete gameInventory[itemId + '_quantity'];
+ }
+ storage.inventory = gameInventory;
+ return true;
}
return false;
}
function spawnRandomItem(x, y) {
if (Math.random() < 0.3) {
// 30% chance to spawn item
var itemType = Math.random();
var newItem;
- if (itemType < 0.4) {
+ if (itemType < 0.3) {
newItem = new HealthPotion();
- } else if (itemType < 0.65) {
+ } else if (itemType < 0.5) {
newItem = new PowerCore();
- } else if (itemType < 0.85) {
+ } else if (itemType < 0.65) {
newItem = new EnergyDrink();
+ } else if (itemType < 0.85) {
+ newItem = new Soda();
} else {
newItem = new ViggenCrystal();
}
newItem.x = Math.max(100, Math.min(1948, x + (Math.random() - 0.5) * 200));
@@ -2451,10 +2516,13 @@
var pulseScale = 1 + Math.sin(easterEggTimer * 0.15) * 0.1;
player.scaleX = pulseScale;
player.scaleY = pulseScale;
}
- // Auto-shoot (with rapid fire Easter egg)
+ // Auto-shoot (with rapid fire Easter egg and soda boost)
var shootInterval = rapidFireUnlocked ? 5 : 15;
+ if (sodaFireRateActive) {
+ shootInterval = Math.max(3, Math.floor(shootInterval * 0.6)); // 40% faster fire rate
+ }
if (LK.ticks % shootInterval == 0 && !isGameOver) {
player.shoot();
}
// Handle energy drink effect
@@ -2506,8 +2574,57 @@
}
});
}
}
+ // Handle soda fire rate boost effect
+ if (sodaFireRateActive) {
+ sodaFireRateTimer--;
+ // Add fizzy particle effect while active
+ if (LK.ticks % 15 === 0) {
+ var fizz = LK.getAsset('playerBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: player.x + (Math.random() - 0.5) * 60,
+ y: player.y + (Math.random() - 0.5) * 60,
+ scaleX: 0.2,
+ scaleY: 0.2
+ });
+ fizz.tint = 0xFF4500;
+ game.addChild(fizz);
+ tween(fizz, {
+ alpha: 0,
+ y: fizz.y - 80,
+ scaleX: 0.6,
+ scaleY: 0.6
+ }, {
+ duration: 600,
+ onFinish: function onFinish() {
+ fizz.destroy();
+ }
+ });
+ }
+ if (sodaFireRateTimer <= 0) {
+ sodaFireRateActive = false;
+ // Show effect ended message
+ var endMsg = new Text2('Fire rate boost ended', {
+ size: 40,
+ fill: 0x888888
+ });
+ endMsg.anchor.set(0.5, 0.5);
+ endMsg.x = 1024;
+ endMsg.y = 1900;
+ game.addChild(endMsg);
+ tween(endMsg, {
+ alpha: 0,
+ y: 1700
+ }, {
+ duration: 1500,
+ onFinish: function onFinish() {
+ endMsg.destroy();
+ }
+ });
+ }
+ }
// Easter egg effects
easterEggTimer++;
// Rainbow mode effect
if (rainbowModeUnlocked) {