/**** * 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(); } }); } }); } };
/****
* 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();
}
});
}
});
}
};