User prompt
Bütün balon boyutlarını aynı boyutta yap
User prompt
20 farklı çeşit balon resimi oluştur.
User prompt
Her stage yükselişinde MaxHP +10 değil, +20 artsın.
User prompt
combo ve altında çıkan lucy tarzı yazının konumlarını 2 satır sola kaydır.
User prompt
Giant Ball türünü oyundan kaldır.
User prompt
arkaplan müziğini resmine basınca durdur veya oynat.
User prompt
Arkaplan müziğinin resim dosyasını Archievements butonunun altına yerleştir.
User prompt
Oyuna arkaplan müziği ekle ve dosyasını oluştur.
User prompt
Lucy Shot ve Amazing yazılarını çeşitlendir. Farklı farklı yazılar çıksın.
User prompt
Bunu görünmez yap
User prompt
combo ve amazing yazılarını 2 satır sola kaydır.
User prompt
Combo yazısını Score yazısının 1 satır soluna taşı. Amazing yazısını bunun 1 satır altına taşı ve boyutları Balls Left yazı boyutu ile aynı olsun.
User prompt
HP yazısının boyutunu Next Stage ile aynı fontta yap.
User prompt
Ekranın sağ alt köşesine ''Reset'' butonu ekle. Basınca, bütün ilerlemeler ve herşey sıfırlansın. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Archievements panel içerisini, başarımları yana doğru 3 sıra ve alta doğru 5 sıra olacak şekilde yeniden düzenle, panele 1-2-3 şeklinde butonlar ekle ve paneli bu şekilde sayfalara ayır.
User prompt
Archievements panel içerisinde ki bütün yazıları ''Balls Left'' yazı boyutu olacak kadar büyüt ve paneli de aynı şekilde hizalı olacak şekilde büyüt.
User prompt
Shockwave efekti bunu oyundan kaldır.
User prompt
Her stage sonrası MaxHP +10 artsın.
User prompt
Stage yükseltmesi için kalan süre, Hp'nin altında yazsın.
User prompt
Her 2 dakikada 1, Stage yükseltmesi sağlansın.
User prompt
Explosive topa değince, oyunda bazı toplar kalıyor. Ne vurabiliyorum, ne yok edebiliyorum. Bug gibi ekranda kalıyor öylece. Bunu tamamen çözmeni istiyorum.
User prompt
Explosive topa değince, oyunda bazı toplar kalıyor. Ne vurabiliyorum, ne yok edebiliyorum. Bug gibi ekranda kalıyor öylece. Bunu tamamen çözmeni istiyorum.
User prompt
Hala oyunda kalan toplar var. Sorunu çözmemişsin.
User prompt
Mermi gönderdikten sonra ve mermiler tamamen yok olduktan sonra yeni bir mermi gönderemiyoruz. Sorun var. Çöz.
User prompt
Şimdi mermi döngüsünde, mermi gönderilmiyor.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AimLine = Container.expand(function () { var self = Container.call(this); for (var i = 0; i < 10; i++) { var dot = self.attachAsset('aimline', { anchorX: 0.5, anchorY: 0.5, y: -i * 30, alpha: 0.5 - i * 0.05 }); } return self; }); var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.numberText = new Text2('1', { size: 40, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 1; self.radius = 40; self.velocityX = 0; self.velocityY = 0; self.setNumber = function (num) { self.hits = num; self.numberText.setText(num.toString()); var scale = 1 + num / 50 * 0.5; ballGraphics.scale.set(scale); self.radius = 40 * scale; }; self.takeDamage = function () { self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); tween(ballGraphics, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); return false; }; return self; }); var BombBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, tint: 0x333333, scaleX: 1.3, scaleY: 1.3 }); self.numberText = new Text2('💣', { size: 40, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 5; self.radius = 50; self.velocityX = 0; self.velocityY = 0; self.pulseTimer = 0; self.isBomb = true; self.takeDamage = function () { self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); ballGraphics.tint = self.hits <= 2 ? 0xff0000 : 0x333333; return false; }; self.update = function () { self.pulseTimer += 0.15; if (self.hits <= 2) { var pulse = 1 + Math.sin(self.pulseTimer) * 0.2; ballGraphics.scale.set(1.3 * pulse); } }; return self; }); var BossBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, tint: 0xff1744, scaleX: 2, scaleY: 2 }); self.numberText = new Text2('BOSS', { size: 50, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 50; self.radius = 80; self.velocityX = 2; self.moveTimer = 0; self.isBoss = true; self.takeDamage = function () { self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); ballGraphics.tint = Math.random() > 0.5 ? 0xff1744 : 0xff6600; tween(ballGraphics, { scaleX: 1.8, scaleY: 1.8 }, { duration: 100, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 2, scaleY: 2 }, { duration: 100 }); } }); return false; }; self.update = function () { self.moveTimer += 0.05; self.x += self.velocityX; if (self.x <= self.radius || self.x >= 2048 - self.radius) { self.velocityX *= -1; } ballGraphics.rotation += 0.02; }; return self; }); var Cannon = Container.expand(function () { var self = Container.call(this); var cannonGraphics = self.attachAsset('cannon', { anchorX: 0.5, anchorY: 0.8 }); self.rotation = 0; return self; }); var ChainReactionPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0xff8800, scaleX: 1.4, scaleY: 1.4 }); self.radius = 35; self.chainTimer = 0; self.update = function () { self.chainTimer += 0.2; var scale = 1.4 + Math.sin(self.chainTimer) * 0.2; powerupGraphics.scale.set(scale); // Chain effect if (Math.random() < 0.2) { var chain = self.attachAsset('aimline', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, tint: 0xff8800, alpha: 0.6, rotation: Math.random() * Math.PI * 2 }); tween(chain, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 400, onFinish: function onFinish() { chain.destroy(); } }); } }; return self; }); var DoubleShotPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0xffff00, scaleX: 1.2, scaleY: 1.2 }); self.radius = 30; self.bounceTimer = 0; self.update = function () { self.bounceTimer += 0.08; var scale = 1.2 + Math.sin(self.bounceTimer * 2) * 0.1; powerupGraphics.scale.set(scale); powerupGraphics.rotation -= 0.03; }; return self; }); var FireBallPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0xff6600 }); self.radius = 25; self.flameTimer = 0; self.update = function () { self.flameTimer += 0.15; var scale = 1 + Math.sin(self.flameTimer) * 0.4; powerupGraphics.scale.set(scale); powerupGraphics.alpha = 0.7 + Math.sin(self.flameTimer * 2) * 0.3; }; return self; }); var FreezeBombPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ccff, scaleX: 1.3, scaleY: 1.3 }); self.radius = 30; self.iceTimer = 0; self.update = function () { self.iceTimer += 0.15; powerupGraphics.alpha = 0.6 + Math.sin(self.iceTimer) * 0.4; powerupGraphics.rotation += 0.02; // Ice particle effect if (Math.random() < 0.1) { var iceParticle = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, tint: 0x00ffff, alpha: 0.8 }); iceParticle.x = (Math.random() - 0.5) * 40; iceParticle.y = (Math.random() - 0.5) * 40; tween(iceParticle, { y: iceParticle.y - 20, alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { iceParticle.destroy(); } }); } }; return self; }); var GhostBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, tint: 0x8888ff, alpha: 0.5 }); self.numberText = new Text2('G', { size: 40, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 7; self.radius = 40; self.phaseTimer = 0; self.isPhased = false; self.isGhost = true; self.takeDamage = function () { if (self.isPhased) return false; self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); return false; }; self.update = function () { self.phaseTimer += 0.1; self.isPhased = Math.sin(self.phaseTimer) > 0; ballGraphics.alpha = self.isPhased ? 0.2 : 0.8; self.numberText.alpha = self.isPhased ? 0.2 : 1; }; return self; }); var GiantBallPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ff00, scaleX: 1.5, scaleY: 1.5 }); self.radius = 35; self.bounceTimer = 0; self.update = function () { self.bounceTimer += 0.1; var scale = 1.5 + Math.sin(self.bounceTimer) * 0.3; powerupGraphics.scale.set(scale); }; return self; }); // HeartBall: Ball with heart icon, gives +10 HP when collected var HeartBall = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, tint: 0xff3366, scaleX: 1.1, scaleY: 1.1 }); self.radius = 28; self.heartText = new Text2('♥', { size: 38, fill: 0xffffff }); self.heartText.anchor.set(0.5, 0.5); self.addChild(self.heartText); self.update = function () { heartGraphics.rotation += 0.04; self.heartText.scale.set(1 + Math.sin(LK.ticks * 0.15) * 0.1); }; return self; }); var LaserPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff }); self.radius = 25; self.glowTimer = 0; self.update = function () { self.glowTimer += 0.2; powerupGraphics.alpha = 0.5 + Math.sin(self.glowTimer) * 0.5; }; return self; }); var LightningPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x9966ff }); self.radius = 25; self.sparkTimer = 0; self.update = function () { self.sparkTimer += 0.3; powerupGraphics.alpha = 0.4 + Math.random() * 0.6; powerupGraphics.scale.set(1 + Math.sin(self.sparkTimer) * 0.3); }; return self; }); var MagnetBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, tint: 0x0066cc, scaleX: 1.3, scaleY: 1.3 }); self.numberText = new Text2('MAG', { size: 35, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 20; self.radius = 50; self.magnetRadius = 200; self.isMagnet = true; self.magnetTimer = 0; self.takeDamage = function () { self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); // Pulse effect on hit tween(ballGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1.3, scaleY: 1.3 }, { duration: 100 }); } }); return false; }; self.update = function () { self.magnetTimer += 0.1; // Magnetic field visual effect if (Math.random() < 0.2) { var field = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, tint: 0x0099ff, alpha: 0.3 }); var angle = Math.random() * Math.PI * 2; var radius = Math.random() * self.magnetRadius; field.x = Math.cos(angle) * radius; field.y = Math.sin(angle) * radius; tween(field, { scaleX: 0.5, scaleY: 0.5, alpha: 0, x: field.x * 0.5, y: field.y * 0.5 }, { duration: 1000, onFinish: function onFinish() { field.destroy(); } }); } ballGraphics.rotation = self.magnetTimer * 0.5; }; return self; }); var MirrorBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, tint: 0xc0c0c0, scaleX: 1.2, scaleY: 1.2 }); self.numberText = new Text2('M', { size: 40, fill: 0x000000 }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 15; self.radius = 45; self.velocityX = 0; self.velocityY = 0; self.isMirror = true; self.reflectTimer = 0; self.takeDamage = function () { self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); // Flash effect on hit tween(ballGraphics, { tint: 0xffffff }, { duration: 100, onFinish: function onFinish() { tween(ballGraphics, { tint: 0xc0c0c0 }, { duration: 100 }); } }); return false; }; self.update = function () { self.reflectTimer += 0.1; ballGraphics.alpha = 0.7 + Math.sin(self.reflectTimer * 2) * 0.3; // Shine effect if (Math.random() < 0.05) { var shine = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, tint: 0xffffff, alpha: 0.8 }); shine.x = (Math.random() - 0.5) * 40; shine.y = (Math.random() - 0.5) * 40; tween(shine, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, onFinish: function onFinish() { shine.destroy(); } }); } }; return self; }); var MultiballPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0xe74c3c }); self.radius = 25; self.rotationSpeed = 0.05; self.update = function () { powerupGraphics.rotation += self.rotationSpeed; var scale = 1 + Math.sin(LK.ticks * 0.1) * 0.3; powerupGraphics.scale.set(scale); }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.lifetime = 30; self.fadeSpeed = 0.03; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.velocityY += 0.075; // gravity self.lifetime--; self.alpha -= self.fadeSpeed; if (self.lifetime <= 0 || self.alpha <= 0) { return true; // destroy } return false; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 20; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.speed = 15; self.radius = 10; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Apply gravity (0.75% per frame) self.velocityY += 0.075; if (self.x <= self.radius || self.x >= 2048 - self.radius) { self.velocityX *= -1; self.x = Math.max(self.radius, Math.min(2048 - self.radius, self.x)); } if (self.y <= self.radius) { self.velocityY *= -1; self.y = self.radius; } }; return self; }); var RainbowBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.numberText = new Text2('★', { size: 50, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.hits = 10; self.radius = 60; self.velocityX = 0; self.velocityY = 0; self.colorTimer = 0; self.isRainbow = true; self.takeDamage = function () { self.hits--; if (self.hits <= 0) { return true; } self.numberText.setText(self.hits.toString()); return false; }; self.update = function () { self.colorTimer += 0.1; var hue = (Math.sin(self.colorTimer) + 1) * 0.5; var r = Math.floor(Math.sin(hue * Math.PI * 2) * 127 + 128); var g = Math.floor(Math.sin((hue + 0.33) * Math.PI * 2) * 127 + 128); var b = Math.floor(Math.sin((hue + 0.67) * Math.PI * 2) * 127 + 128); ballGraphics.tint = r << 16 | g << 8 | b; ballGraphics.rotation += 0.05; }; return self; }); var ShieldPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x3498db }); self.radius = 25; self.shieldTimer = 0; self.update = function () { self.shieldTimer += 0.1; var scale = 1 + Math.sin(self.shieldTimer * 2) * 0.2; powerupGraphics.scale.set(scale); powerupGraphics.rotation += 0.05; }; return self; }); var SlowMotionPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x9b59b6 }); self.radius = 30; self.pulseTimer = 0; self.update = function () { self.pulseTimer += 0.1; var scale = 1 + Math.sin(self.pulseTimer) * 0.2; powerupGraphics.scale.set(scale); }; return self; }); var SpecialProjectile = Container.expand(function () { var self = Container.call(this); self.type = 'normal'; self.velocityX = 0; self.velocityY = 0; self.speed = 15; self.radius = 10; self.piercing = 0; self.bounces = 999; var projectileGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.setType = function (type) { self.type = type; switch (type) { case 'piercing': projectileGraphics.tint = 0xff00ff; self.piercing = 3; projectileGraphics.scale.set(1.5); self.radius = 15; break; case 'explosive': projectileGraphics.tint = 0xff4444; projectileGraphics.scale.set(2); self.radius = 20; self.speed = 10; break; case 'rapid': projectileGraphics.tint = 0x44ff44; projectileGraphics.scale.set(0.7); self.radius = 7; self.speed = 25; break; case 'fireball': projectileGraphics.tint = 0xff6600; projectileGraphics.scale.set(1.8); self.radius = 18; self.speed = 12; self.piercing = 999; break; case 'giant': projectileGraphics.tint = 0x00ff00; projectileGraphics.scale.set(3); self.radius = 30; self.speed = 8; break; case 'split': projectileGraphics.tint = 0xff00ff; projectileGraphics.scale.set(1.2); self.radius = 12; self.speed = 15; break; case 'laser': projectileGraphics.tint = 0x00ffff; projectileGraphics.scale.set(0.5); self.radius = 5; self.speed = 30; self.piercing = 999; break; case 'lightning': projectileGraphics.tint = 0x9966ff; projectileGraphics.scale.set(1.5); self.radius = 15; self.speed = 20; self.piercing = 1; break; } }; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Apply gravity (0.75% per frame) if (self.gravity === undefined) self.gravity = 0.075; self.velocityY += self.gravity; if (self.x <= self.radius || self.x >= 2048 - self.radius) { self.velocityX *= -1; self.x = Math.max(self.radius, Math.min(2048 - self.radius, self.x)); self.bounces--; } if (self.y <= self.radius) { self.velocityY *= -1; self.y = self.radius; self.bounces--; } if (self.type === 'rapid') { // Add trail effect if (Math.random() < 0.3) { var trail = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, alpha: 0.5, tint: 0x44ff44 }); tween(trail, { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 300, onFinish: function onFinish() { trail.destroy(); } }); } } else if (self.type === 'fireball') { // Add flame trail if (Math.random() < 0.5) { var flame = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, alpha: 0.8, tint: Math.random() > 0.5 ? 0xff6600 : 0xffaa00 }); tween(flame, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 200, onFinish: function onFinish() { flame.destroy(); } }); } } else if (self.type === 'laser') { // Add laser glow projectileGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.3) * 0.2; } return self.bounces <= 0; }; return self; }); var SplitBallPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0xff00ff }); self.radius = 25; self.rotationSpeed = 0.1; self.update = function () { powerupGraphics.rotation += self.rotationSpeed; }; return self; }); var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 25; starGraphics.rotation = Math.PI / 4; self.update = function () { starGraphics.rotation += 0.02; }; return self; }); var TeleportPowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5, tint: 0x8000ff, scaleX: 1.2, scaleY: 1.2 }); self.radius = 30; self.teleportTimer = 0; self.update = function () { self.teleportTimer += 0.3; powerupGraphics.alpha = 0.3 + Math.abs(Math.sin(self.teleportTimer)) * 0.7; // Portal effect if (powerupGraphics.alpha < 0.4) { powerupGraphics.x = (Math.random() - 0.5) * 10; powerupGraphics.y = (Math.random() - 0.5) * 10; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var cannon; var aimLine; var balls = []; var projectiles = []; var powerups = []; var stars = []; var isAiming = false; var canShoot = true; var projectileCount = 1; var stage = 1; var ballsPerRow = 6; var ballSpeed = 0.5; var gameActive = true; // HP system var maxHP = 20; var hp = maxHP; var hpText = new Text2('HP: ' + hp, { size: 50, fill: 0xff4444 }); hpText.anchor.set(0, 0); hpText.x = 20 + 2 * 80; hpText.y = 20; LK.gui.topLeft.addChild(hpText); // Remaining balls count text (above stage text) var ballsLeftText = new Text2('Balls Left: 0', { size: 28, fill: 0xCCCCCC }); ballsLeftText.anchor.set(0.5, 0); ballsLeftText.y = 0; LK.gui.top.addChild(ballsLeftText); var stageText = new Text2('Stage 1', { size: 60, fill: 0xFFFFFF }); stageText.anchor.set(0.5, 0); stageText.y = 20; LK.gui.top.addChild(stageText); var projectileCountText = new Text2('x1', { size: 50, fill: 0x4ECDC4 }); projectileCountText.anchor.set(0.5, 0); projectileCountText.y = 100; LK.gui.top.addChild(projectileCountText); var scoreText = new Text2('Score: 0', { size: 40, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); scoreText.x = -20; scoreText.y = 20; LK.gui.topRight.addChild(scoreText); var combo = 0; var comboTimer = 0; var scoreMultiplier = 1; var comboText = new Text2('', { size: 30, fill: 0xFFD700 }); comboText.anchor.set(0.5, 0.5); LK.gui.center.addChild(comboText); var particles = []; var currentWeapon = 'normal'; var weaponUnlocks = { piercing: false, explosive: false, rapid: false }; var slowMotionActive = false; var slowMotionTimer = 0; var gameSpeed = 1; var magnetActive = false; var magnetTimer = 0; var specialEffects = []; var chainReactionActive = false; var lastBallDestroyed = null; var consecutiveHits = 0; var slowMotionPowerups = []; var multiballPowerups = []; var multiballActive = false; var fireballPowerups = []; var giantBallPowerups = []; var splitBallPowerups = []; var laserPowerups = []; var fireballActive = false; var giantBallActive = false; var splitBallActive = false; var laserActive = false; var shieldPowerups = []; var shieldActive = false; var shieldTimer = 0; var bossBalls = []; var bossSpawnCounter = 0; var freezeActive = false; var freezeTimer = 0; var criticalHitChance = 0.1; var magnetBalls = []; var perfectStageBonus = false; var rainbowBalls = []; var bombBalls = []; var doubleShotPowerups = []; var doubleShotActive = false; var doubleShotTimer = 0; var lightningPowerups = []; var lightningActive = false; var ghostBalls = []; var reverseGravityActive = false; var reverseGravityTimer = 0; var scoreBoostActive = false; var scoreBoostTimer = 0; var scoreBoostMultiplier = 1; var autoAimActive = false; var autoAimTimer = 0; var freezeBombPowerups = []; var freezeBombActive = false; var mirrorBalls = []; var chainReactionPowerups = []; var chainReactionBombActive = false; var teleportPowerups = []; var teleportActive = false; var ballsDestroyed = 0; var perfectHits = 0; var missedShots = 0; var powerupsCollected = 0; var maxCombo = 0; var timePlayed = 0; var achievements = { // Basic achievements firstWin: false, combo10: false, score1000: false, allWeapons: false, bossKiller: false, perfectStage: false, shieldMaster: false, lightningMaster: false, ghostHunter: false, reverseGravity: false, // New achievements stage10: false, stage25: false, stage50: false, score5000: false, score10000: false, score50000: false, combo20: false, combo50: false, multiKill5: false, multiKill10: false, projectiles50: false, projectiles100: false, fireballKills: false, laserKills: false, explosiveKills: false, piercingKills: false, rapidKills: false, splitKills: false, giantKills: false, lightningChain: false, bombExpert: false, rainbowHunter: false, starCollector: false, powerupMaster: false, dodgeMaster: false, speedDemon: false, slowMotionPro: false, magnetMaster: false, freezeMaster: false, doubleTrouble: false, tripleCombo: false, chainReactionPro: false, perfectAccuracy: false, luckyShot: false, survivor: false, pacifist: false, aggressive: false, versatile: false, persistent: false, flawless: false, comeback: false, closeCall: false, longShot: false, richPlayer: false, masterOfAll: false }; var achievementDescriptions = { firstWin: "Clear your first stage", combo10: "Achieve a 10x combo", score1000: "Score 1,000 points", allWeapons: "Unlock all basic weapons", bossKiller: "Defeat a boss", perfectStage: "Clear a stage with only 1 projectile", shieldMaster: "Use a shield power-up", lightningMaster: "Use lightning power-up", ghostHunter: "Defeat a ghost ball", reverseGravity: "Use reverse gravity", stage10: "Reach stage 10", stage25: "Reach stage 25", stage50: "Reach stage 50", score5000: "Score 5,000 points", score10000: "Score 10,000 points", score50000: "Score 50,000 points", combo20: "Achieve a 20x combo", combo50: "Achieve a 50x combo", multiKill5: "Destroy 5 balls with one shot", multiKill10: "Destroy 10 balls with one shot", projectiles50: "Collect 50 projectiles total", projectiles100: "Collect 100 projectiles total", fireballKills: "Destroy 100 balls with fireball", laserKills: "Destroy 100 balls with laser", explosiveKills: "Destroy 100 balls with explosive", piercingKills: "Destroy 100 balls with piercing", rapidKills: "Destroy 100 balls with rapid fire", splitKills: "Destroy 100 balls with split shot", giantKills: "Destroy 100 balls with giant ball", lightningChain: "Chain lightning to 5 balls", bombExpert: "Trigger 10 bomb explosions", rainbowHunter: "Destroy 20 rainbow balls", starCollector: "Collect 50 stars", powerupMaster: "Use 100 power-ups", dodgeMaster: "Survive with balls at bottom 10 times", speedDemon: "Clear a stage in under 30 seconds", slowMotionPro: "Use slow motion 20 times", magnetMaster: "Use magnet 20 times", freezeMaster: "Use freeze 20 times", doubleTrouble: "Use double shot 20 times", tripleCombo: "Get 3 different power-ups active", chainReactionPro: "Trigger 50 chain reactions", perfectAccuracy: "Hit 100 balls without missing", luckyShot: "Hit a ball from max distance", survivor: "Survive for 10 minutes", pacifist: "Clear a stage without power-ups", aggressive: "Clear a stage in under 10 shots", versatile: "Use all weapon types in one game", persistent: "Play 100 games", flawless: "Clear 5 stages without taking damage", comeback: "Win with 1 projectile left", closeCall: "Survive with shield save 5 times", longShot: "Hit a ball from bottom to top", richPlayer: "Have 10+ projectiles at once", masterOfAll: "Unlock all 50 achievements" }; var achievementProgress = { fireballKills: 0, laserKills: 0, explosiveKills: 0, piercingKills: 0, rapidKills: 0, splitKills: 0, giantKills: 0, bombExpert: 0, rainbowHunter: 0, starCollector: 0, powerupMaster: 0, dodgeMaster: 0, slowMotionPro: 0, magnetMaster: 0, freezeMaster: 0, doubleTrouble: 0, chainReactionPro: 0, perfectAccuracy: 0, persistent: 0, flawless: 0, closeCall: 0 }; // Load saved data var savedData = storage['99balls_save'] || {}; if (savedData.highScore) { var highScoreText = new Text2('Best: ' + savedData.highScore, { size: 30, fill: 0xFFD700 }); highScoreText.anchor.set(1, 0); highScoreText.x = -20; highScoreText.y = 70; LK.gui.topRight.addChild(highScoreText); } // Load achievements from flattened structure for (var key in achievements) { if (savedData[key] !== undefined) { achievements[key] = savedData[key]; } } // Load achievement progress for (var key in achievementProgress) { if (savedData[key + 'Progress'] !== undefined) { achievementProgress[key] = savedData[key + 'Progress']; } } var weaponText = new Text2('Normal', { size: 40, fill: 0xFFFFFF }); weaponText.anchor.set(0.5, 1); weaponText.y = -20; LK.gui.bottom.addChild(weaponText); var slowMotionOverlay = new Container(); var slowMotionBg = slowMotionOverlay.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 50, scaleY: 50, alpha: 0, tint: 0x9b59b6 }); LK.gui.center.addChild(slowMotionOverlay); var powerUpIndicator = new Text2('', { size: 50, fill: 0xFFFFFF }); powerUpIndicator.anchor.set(0, 0); powerUpIndicator.x = 20; powerUpIndicator.y = 200; LK.gui.topLeft.addChild(powerUpIndicator); var doubleShotIndicator = new Text2('', { size: 40, fill: 0xffff00 }); doubleShotIndicator.anchor.set(0, 0); doubleShotIndicator.x = 20; doubleShotIndicator.y = 260; LK.gui.topLeft.addChild(doubleShotIndicator); var shieldIndicator = new Container(); var shieldBg = shieldIndicator.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, alpha: 0, tint: 0x3498db }); game.addChild(shieldIndicator); function initializeLevel() { // Reset game state gameActive = true; canShoot = true; isAiming = false; cannon = game.addChild(new Cannon()); cannon.x = 1024; cannon.y = 2600; aimLine = game.addChild(new AimLine()); aimLine.x = cannon.x; aimLine.y = cannon.y; aimLine.visible = false; spawnBallRow(); } function spawnBallRow() { var spacing = 2048 / (ballsPerRow + 1); for (var i = 0; i < ballsPerRow; i++) { if (Math.random() < 0.8) { var ball = new Ball(); ball.x = spacing * (i + 1); ball.y = -50; ball.setNumber(Math.floor(Math.random() * stage * 5) + stage); balls.push(ball); game.addChild(ball); if (Math.random() < 0.15) { var powerup = new PowerUp(); powerup.x = ball.x; powerup.y = ball.y; powerups.push(powerup); game.addChild(powerup); } else if (Math.random() < 0.07) { // 7% chance for heart ball var heartBall = new HeartBall(); heartBall.x = ball.x; heartBall.y = ball.y; stars.push(heartBall); // Use stars array for easy y-movement and removal game.addChild(heartBall); } else if (Math.random() < 0.1) { var star = new Star(); star.x = ball.x; star.y = ball.y; stars.push(star); game.addChild(star); } else if (Math.random() < 0.05 && stage > 2) { var slowPowerup = new SlowMotionPowerUp(); slowPowerup.x = ball.x; slowPowerup.y = ball.y; slowMotionPowerups.push(slowPowerup); game.addChild(slowPowerup); } else if (Math.random() < 0.04 && stage > 3) { var multiballPowerup = new MultiballPowerUp(); multiballPowerup.x = ball.x; multiballPowerup.y = ball.y; multiballPowerups.push(multiballPowerup); game.addChild(multiballPowerup); } else if (Math.random() < 0.04 && stage > 1) { var fireballPowerup = new FireBallPowerUp(); fireballPowerup.x = ball.x; fireballPowerup.y = ball.y; fireballPowerups.push(fireballPowerup); game.addChild(fireballPowerup); } else if (Math.random() < 0.03 && stage > 2) { var giantBallPowerup = new GiantBallPowerUp(); giantBallPowerup.x = ball.x; giantBallPowerup.y = ball.y; giantBallPowerups.push(giantBallPowerup); game.addChild(giantBallPowerup); } else if (Math.random() < 0.03 && stage > 4) { var splitBallPowerup = new SplitBallPowerUp(); splitBallPowerup.x = ball.x; splitBallPowerup.y = ball.y; splitBallPowerups.push(splitBallPowerup); game.addChild(splitBallPowerup); } else if (Math.random() < 0.02 && stage > 5) { var laserPowerup = new LaserPowerUp(); laserPowerup.x = ball.x; laserPowerup.y = ball.y; laserPowerups.push(laserPowerup); game.addChild(laserPowerup); } else if (Math.random() < 0.03 && stage > 3) { var shieldPowerup = new ShieldPowerUp(); shieldPowerup.x = ball.x; shieldPowerup.y = ball.y; shieldPowerups.push(shieldPowerup); game.addChild(shieldPowerup); } else if (Math.random() < 0.04 && stage > 2) { var doubleShotPowerup = new DoubleShotPowerUp(); doubleShotPowerup.x = ball.x; doubleShotPowerup.y = ball.y; doubleShotPowerups.push(doubleShotPowerup); game.addChild(doubleShotPowerup); } else if (Math.random() < 0.03 && stage > 4) { var lightningPowerup = new LightningPowerUp(); lightningPowerup.x = ball.x; lightningPowerup.y = ball.y; lightningPowerups.push(lightningPowerup); game.addChild(lightningPowerup); } } else if (Math.random() < 0.05 && stage > 3) { // Spawn rainbow ball var rainbowBall = new RainbowBall(); rainbowBall.x = ball.x; rainbowBall.y = ball.y; rainbowBalls.push(rainbowBall); game.addChild(rainbowBall); } else if (Math.random() < 0.04 && stage > 4) { // Spawn bomb ball var bombBall = new BombBall(); bombBall.x = ball.x; bombBall.y = ball.y; bombBalls.push(bombBall); game.addChild(bombBall); } else if (Math.random() < 0.03 && stage > 5) { // Spawn ghost ball var ghostBall = new GhostBall(); ghostBall.x = ball.x; ghostBall.y = ball.y; ghostBalls.push(ghostBall); game.addChild(ghostBall); } else if (Math.random() < 0.02 && stage > 6) { // Spawn mirror ball var mirrorBall = new MirrorBall(); mirrorBall.x = ball.x; mirrorBall.y = ball.y; mirrorBalls.push(mirrorBall); game.addChild(mirrorBall); } else if (Math.random() < 0.03 && stage > 4) { // Spawn freeze bomb power-up var freezeBombPowerup = new FreezeBombPowerUp(); freezeBombPowerup.x = ball.x; freezeBombPowerup.y = ball.y; freezeBombPowerups.push(freezeBombPowerup); game.addChild(freezeBombPowerup); } else if (Math.random() < 0.02 && stage > 5) { // Spawn chain reaction power-up var chainReactionPowerup = new ChainReactionPowerUp(); chainReactionPowerup.x = ball.x; chainReactionPowerup.y = ball.y; chainReactionPowerups.push(chainReactionPowerup); game.addChild(chainReactionPowerup); } else if (Math.random() < 0.02 && stage > 7) { // Spawn teleport power-up var teleportPowerup = new TeleportPowerUp(); teleportPowerup.x = ball.x; teleportPowerup.y = ball.y; teleportPowerups.push(teleportPowerup); game.addChild(teleportPowerup); } else if (Math.random() < 0.03 && stage > 6) { // Spawn magnet ball var magnetBall = new MagnetBall(); magnetBall.x = ball.x; magnetBall.y = ball.y; magnetBalls.push(magnetBall); game.addChild(magnetBall); } } // Spawn boss every 5 stages bossSpawnCounter++; if (stage > 0 && stage % 5 === 0 && bossSpawnCounter === 1) { var boss = new BossBall(); boss.x = 1024; boss.y = 200; bossBalls.push(boss); game.addChild(boss); var bossWarning = new Text2('BOSS INCOMING!', { size: 100, fill: 0xff1744 }); bossWarning.anchor.set(0.5, 0.5); bossWarning.alpha = 0; LK.gui.center.addChild(bossWarning); tween(bossWarning, { alpha: 1, scaleX: 1.5, scaleY: 1.5 }, { duration: 500, onFinish: function onFinish() { tween(bossWarning, { alpha: 0 }, { duration: 500, delay: 1000, onFinish: function onFinish() { bossWarning.destroy(); } }); } }); } else if (stage % 5 !== 0) { bossSpawnCounter = 0; } } function fireProjectiles(angle) { var shotCount = projectileCount; var delay = 100; var weaponType = currentWeapon; if (currentWeapon === 'rapid') { shotCount = Math.min(projectileCount * 3, 15); delay = 30; } // Double shot modifier if (doubleShotActive) { shotCount *= 2; } // Check for active power-ups if (fireballActive) { weaponType = 'fireball'; fireballActive = false; } else if (giantBallActive) { weaponType = 'giant'; giantBallActive = false; } else if (splitBallActive) { weaponType = 'split'; splitBallActive = false; } else if (laserActive) { weaponType = 'laser'; laserActive = false; shotCount = 1; } else if (lightningActive) { weaponType = 'lightning'; lightningActive = false; } // Add cannon fire effect var muzzleFlash = cannon.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, y: -40, scaleX: 0.5, scaleY: 0.5, alpha: 0.8, tint: weaponType === 'fireball' ? 0xff6600 : weaponType === 'laser' ? 0x00ffff : 0xffffff }); // Special combo effects for weapon combinations var activeEffects = 0; if (fireballActive) activeEffects++; if (giantBallActive) activeEffects++; if (splitBallActive) activeEffects++; if (laserActive) activeEffects++; if (lightningActive) activeEffects++; if (multiballActive) activeEffects++; if (doubleShotActive) activeEffects++; if (activeEffects >= 3) { // Triple combo effect var comboFlash = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: cannon.x, y: cannon.y, scaleX: 0.1, scaleY: 0.1, alpha: 0.8, tint: 0xff00ff }); tween(comboFlash, { scaleX: 10, scaleY: 10, alpha: 0, rotation: Math.PI * 4 }, { duration: 1000, onFinish: function onFinish() { comboFlash.destroy(); } }); checkAchievement('tripleCombo'); } tween(muzzleFlash, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 200, onFinish: function onFinish() { muzzleFlash.destroy(); } }); if (multiballActive) { // Fire in multiple directions var angles = [-0.3, -0.15, 0, 0.15, 0.3]; for (var a = 0; a < angles.length; a++) { (function (angleOffset) { LK.setTimeout(function () { var projectile = new SpecialProjectile(); projectile.x = cannon.x; projectile.y = cannon.y - 40; projectile.setType(weaponType); projectile.velocityX = Math.cos(angle + angleOffset) * projectile.speed; projectile.velocityY = Math.sin(angle + angleOffset) * projectile.speed; projectiles.push(projectile); game.addChild(projectile); }, a * 50); })(angles[a]); } multiballActive = false; return; } for (var i = 0; i < shotCount; i++) { LK.setTimeout(function () { var projectile = new SpecialProjectile(); projectile.x = cannon.x; projectile.y = cannon.y - 40; projectile.setType(weaponType); if (weaponType === 'rapid') { var spread = (Math.random() - 0.5) * 0.2; projectile.velocityX = Math.cos(angle + spread) * projectile.speed; projectile.velocityY = Math.sin(angle + spread) * projectile.speed; } else if (weaponType === 'laser') { // Laser goes straight up projectile.velocityX = 0; projectile.velocityY = -projectile.speed; } else { projectile.velocityX = Math.cos(angle) * projectile.speed; projectile.velocityY = Math.sin(angle) * projectile.speed; } projectiles.push(projectile); game.addChild(projectile); LK.getSound('shoot').play(); }, i * delay); } } function checkCollision(obj1, obj2, radius1, radius2) { var dx = obj1.x - obj2.x; var dy = obj1.y - obj2.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < radius1 + radius2; } function createExplosion(x, y, color, count) { for (var i = 0; i < count; i++) { var particle = new Particle(); particle.x = x; particle.y = y; var angle = Math.random() * Math.PI * 2; var speed = Math.random() * 10 + 5; particle.velocityX = Math.cos(angle) * speed; particle.velocityY = Math.sin(angle) * speed; particle.tint = color; particles.push(particle); game.addChild(particle); } // Create shockwave effect for chain reactions if (chainReactionActive && count > 15) { var shockwave = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: x, y: y, scaleX: 0.02, scaleY: 0.02, alpha: 0.8, tint: color }); tween(shockwave, { scaleX: 1, scaleY: 1, alpha: 0 }, { duration: 500, onFinish: function onFinish() { shockwave.destroy(); } }); } } function updateAchievementDisplay() { // Clear existing achievement displays for (var i = achievementPanel.children.length - 1; i >= 0; i--) { var child = achievementPanel.children[i]; if (child !== panelBg && child !== achievementTitle && child !== closeButton) { child.destroy(); } } var unlocked = 0; var total = 0; var yOffset = -500; var xOffset = -400; var row = 0; var col = 0; for (var key in achievements) { total++; if (achievements[key]) unlocked++; var achContainer = new Container(); var achBg = achContainer.attachAsset('achievementItemBg', { anchorX: 0.5, anchorY: 0.5, tint: achievements[key] ? 0x27ae60 : 0x7f8c8d, alpha: 0.9 }); var achText = new Text2(key.replace(/([A-Z])/g, ' $1').trim(), { size: 20, fill: achievements[key] ? 0xFFFFFF : 0x95a5a6 }); achText.anchor.set(0.5, 0.5); achText.y = -10; achContainer.addChild(achText); var achDesc = new Text2(achievementDescriptions[key] || '', { size: 15, fill: achievements[key] ? 0xecf0f1 : 0x7f8c8d }); achDesc.anchor.set(0.5, 0.5); achDesc.y = 10; achContainer.addChild(achDesc); achContainer.x = xOffset + col * 250; achContainer.y = yOffset + row * 60; achievementPanel.addChild(achContainer); col++; if (col > 3) { col = 0; row++; } } var progressText = new Text2('Progress: ' + unlocked + '/' + total, { size: 40, fill: 0xFFD700 }); progressText.anchor.set(0.5, 0.5); progressText.y = 600; achievementPanel.addChild(progressText); } function checkAchievement(key) { if (!achievements[key]) { achievements[key] = true; showAchievement(achievementDescriptions[key] || key, 0xFFD700); saveAchievements(); // Check master achievement var allUnlocked = true; for (var k in achievements) { if (k !== 'masterOfAll' && !achievements[k]) { allUnlocked = false; break; } } if (allUnlocked && !achievements.masterOfAll) { achievements.masterOfAll = true; showAchievement("MASTER OF ALL ACHIEVEMENTS!", 0xFF00FF); } } } function saveAchievements() { savedData.highScore = savedData.highScore || 0; for (var key in achievements) { savedData[key] = achievements[key]; } for (var key in achievementProgress) { savedData[key + 'Progress'] = achievementProgress[key]; } storage['99balls_save'] = savedData; } function showAchievement(text, color) { var achievementText = new Text2('Achievement: ' + text, { size: 60, fill: color }); achievementText.anchor.set(0.5, 0.5); achievementText.y = 200; achievementText.alpha = 0; LK.gui.center.addChild(achievementText); tween(achievementText, { alpha: 1, y: 100 }, { duration: 500, onFinish: function onFinish() { tween(achievementText, { alpha: 0 }, { duration: 1000, delay: 2000, onFinish: function onFinish() { achievementText.destroy(); } }); } }); } function updateCombo() { combo++; comboTimer = 120; // 2 seconds at 60 FPS if (combo >= 5) { scoreMultiplier = Math.min(combo / 5, 5); comboText.setText('COMBO x' + Math.floor(scoreMultiplier)); comboText.alpha = 1; // Enhanced visual feedback var colors = [0xFFD700, 0xFF6347, 0x00CED1, 0xFF1493, 0x32CD32]; comboText.tint = colors[Math.min(Math.floor(scoreMultiplier) - 1, 4)]; tween(comboText, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, onFinish: function onFinish() { tween(comboText, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); // Combo milestone effects if (combo === 10 || combo === 20 || combo === 30 || combo === 50 || combo === 100) { var message = combo === 100 ? 'LEGENDARY!' : combo === 50 ? 'UNSTOPPABLE!' : 'AMAZING!'; var comboFlash = new Text2(message, { size: (80 + combo / 10) * 0.5, fill: combo === 100 ? 0xff00ff : 0xFFD700 }); comboFlash.anchor.set(0.5, 0.5); comboFlash.y = -100; comboFlash.alpha = 0; LK.gui.center.addChild(comboFlash); tween(comboFlash, { alpha: 1, y: -150 }, { duration: 300, onFinish: function onFinish() { tween(comboFlash, { alpha: 0 }, { duration: 500, delay: 200, onFinish: function onFinish() { comboFlash.destroy(); } }); } }); } } } function moveRow() { chainReactionActive = false; consecutiveHits = 0; spawnBallRow(); } game.down = function (x, y, obj) { if (!canShoot || !gameActive) return; isAiming = true; aimLine.visible = true; }; game.move = function (x, y, obj) { if (!isAiming || !gameActive) return; var dx = x - cannon.x; var dy = y - cannon.y; var angle = Math.atan2(dy, dx); // Auto aim to nearest ball if (autoAimActive && balls.length > 0) { var closestBall = null; var closestDist = 999999; for (var i = 0; i < balls.length; i++) { var ball = balls[i]; var ballDx = ball.x - cannon.x; var ballDy = ball.y - cannon.y; var dist = Math.sqrt(ballDx * ballDx + ballDy * ballDy); if (dist < closestDist && ball.y < cannon.y) { closestDist = dist; closestBall = ball; } } if (closestBall) { dx = closestBall.x - cannon.x; dy = closestBall.y - cannon.y; angle = Math.atan2(dy, dx); } } if (angle > -Math.PI && angle < 0) { cannon.rotation = angle + Math.PI / 2; aimLine.rotation = angle + Math.PI / 2; } }; game.up = function (x, y, obj) { if (!isAiming || !gameActive) return; isAiming = false; aimLine.visible = false; canShoot = false; var dx = x - cannon.x; var dy = y - cannon.y; var angle = Math.atan2(dy, dx); if (angle > -Math.PI && angle < 0) { fireProjectiles(angle); } }; game.update = function () { if (!gameActive) return; // Update slow motion if (slowMotionActive) { slowMotionTimer--; gameSpeed = 0.3; if (slowMotionTimer <= 0) { slowMotionActive = false; gameSpeed = 1; tween(slowMotionBg, { alpha: 0 }, { duration: 300 }); powerUpIndicator.setText(''); } } else { gameSpeed = 1; } // Update magnet effect if (magnetActive) { magnetTimer--; if (magnetTimer <= 0) { magnetActive = false; } } // Update combo timer if (comboTimer > 0) { comboTimer--; if (comboTimer === 0) { combo = 0; scoreMultiplier = 1; consecutiveHits = 0; tween(comboText, { alpha: 0 }, { duration: 300 }); } } else if (combo > 0) { // Add dynamic combo multiplier visual var comboScale = 1 + Math.sin(LK.ticks * 0.2) * 0.1 * Math.min(combo / 10, 1); comboText.scale.set(comboScale); } // Update particles for (var i = particles.length - 1; i >= 0; i--) { if (particles[i].update()) { particles[i].destroy(); particles.splice(i, 1); } } // Update slow motion powerups for (var i = 0; i < slowMotionPowerups.length; i++) { slowMotionPowerups[i].update(); } // Update multiball powerups for (var i = 0; i < multiballPowerups.length; i++) { multiballPowerups[i].update(); } // Update shield if (shieldActive) { shieldTimer--; shieldIndicator.x = cannon.x; shieldIndicator.y = cannon.y; shieldBg.alpha = 0.3 + Math.sin(LK.ticks * 0.2) * 0.2; shieldBg.rotation += 0.05; if (shieldTimer <= 0) { shieldActive = false; tween(shieldBg, { alpha: 0 }, { duration: 300 }); powerUpIndicator.setText(''); } } // Update freeze if (freezeActive) { freezeTimer--; if (freezeTimer <= 0) { freezeActive = false; gameSpeed = 1; for (var i = 0; i < balls.length; i++) { balls[i].tint = 0xffffff; } } } // Update new power-ups for (var i = 0; i < shieldPowerups.length; i++) { shieldPowerups[i].update(); } for (var i = 0; i < fireballPowerups.length; i++) { fireballPowerups[i].update(); } for (var i = 0; i < giantBallPowerups.length; i++) { giantBallPowerups[i].update(); } for (var i = 0; i < splitBallPowerups.length; i++) { splitBallPowerups[i].update(); } for (var i = 0; i < laserPowerups.length; i++) { laserPowerups[i].update(); } for (var i = 0; i < doubleShotPowerups.length; i++) { doubleShotPowerups[i].update(); } // Update double shot timer if (doubleShotActive) { doubleShotTimer--; if (doubleShotTimer <= 0) { doubleShotActive = false; doubleShotIndicator.setText(''); } } // Update lightning powerups for (var i = 0; i < lightningPowerups.length; i++) { lightningPowerups[i].update(); } // Update ghost balls for (var i = 0; i < ghostBalls.length; i++) { ghostBalls[i].update(); } // Update reverse gravity if (reverseGravityActive) { reverseGravityTimer--; if (reverseGravityTimer <= 0) { reverseGravityActive = false; ballSpeed = Math.abs(ballSpeed); powerUpIndicator.setText(''); } } // Update score boost if (scoreBoostActive) { scoreBoostTimer--; scoreBoostMultiplier = 3; if (scoreBoostTimer <= 0) { scoreBoostActive = false; scoreBoostMultiplier = 1; powerUpIndicator.setText(''); } } else { scoreBoostMultiplier = 1; } // Update auto aim if (autoAimActive) { autoAimTimer--; if (autoAimTimer <= 0) { autoAimActive = false; powerUpIndicator.setText(''); } } // Update freeze bomb powerups for (var i = 0; i < freezeBombPowerups.length; i++) { freezeBombPowerups[i].update(); } // Update mirror balls for (var i = 0; i < mirrorBalls.length; i++) { if (mirrorBalls[i].update) { mirrorBalls[i].update(); } } // Update magnet balls for (var i = 0; i < magnetBalls.length; i++) { if (magnetBalls[i].update) { magnetBalls[i].update(); } } // Update chain reaction powerups for (var i = 0; i < chainReactionPowerups.length; i++) { chainReactionPowerups[i].update(); } // Update teleport powerups for (var i = 0; i < teleportPowerups.length; i++) { teleportPowerups[i].update(); } // Track time played timePlayed++; if (timePlayed % 3600 === 0) { // Every minute var minutes = timePlayed / 3600; if (minutes === 5) checkAchievement('persistent'); } // Track max combo if (combo > maxCombo) { maxCombo = combo; } // Update balls left text ballsLeftText.setText('Balls Left: ' + balls.length); // Update boss balls for (var i = 0; i < bossBalls.length; i++) { if (bossBalls[i].update) { bossBalls[i].update(); } bossBalls[i].y += ballSpeed * gameSpeed * 0.5; // Boss moves slower } // Update ball falling speed and call update, and destroy if off screen for (var i = balls.length - 1; i >= 0; i--) { balls[i].y += ballSpeed * gameSpeed; if (balls[i].update) { balls[i].update(); } if (balls[i].y > 2732 + 100) { balls[i].destroy(); balls.splice(i, 1); } } for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].y += ballSpeed * gameSpeed; if (powerups[i].y > 2732 + 100) { powerups[i].destroy(); powerups.splice(i, 1); } } for (var i = stars.length - 1; i >= 0; i--) { stars[i].y += ballSpeed * gameSpeed; if (stars[i].update) { stars[i].update(); } if (stars[i].y > 2732 + 100) { stars[i].destroy(); stars.splice(i, 1); } } for (var i = slowMotionPowerups.length - 1; i >= 0; i--) { slowMotionPowerups[i].y += ballSpeed * gameSpeed; if (slowMotionPowerups[i].y > 2732 + 100) { slowMotionPowerups[i].destroy(); slowMotionPowerups.splice(i, 1); } } for (var i = multiballPowerups.length - 1; i >= 0; i--) { multiballPowerups[i].y += ballSpeed * gameSpeed; if (multiballPowerups[i].y > 2732 + 100) { multiballPowerups[i].destroy(); multiballPowerups.splice(i, 1); } } for (var i = fireballPowerups.length - 1; i >= 0; i--) { fireballPowerups[i].y += ballSpeed * gameSpeed; if (fireballPowerups[i].y > 2732 + 100) { fireballPowerups[i].destroy(); fireballPowerups.splice(i, 1); } } for (var i = giantBallPowerups.length - 1; i >= 0; i--) { giantBallPowerups[i].y += ballSpeed * gameSpeed; if (giantBallPowerups[i].y > 2732 + 100) { giantBallPowerups[i].destroy(); giantBallPowerups.splice(i, 1); } } for (var i = splitBallPowerups.length - 1; i >= 0; i--) { splitBallPowerups[i].y += ballSpeed * gameSpeed; if (splitBallPowerups[i].y > 2732 + 100) { splitBallPowerups[i].destroy(); splitBallPowerups.splice(i, 1); } } for (var i = laserPowerups.length - 1; i >= 0; i--) { laserPowerups[i].y += ballSpeed * gameSpeed; if (laserPowerups[i].y > 2732 + 100) { laserPowerups[i].destroy(); laserPowerups.splice(i, 1); } } for (var i = shieldPowerups.length - 1; i >= 0; i--) { shieldPowerups[i].y += ballSpeed * gameSpeed; if (shieldPowerups[i].y > 2732 + 100) { shieldPowerups[i].destroy(); shieldPowerups.splice(i, 1); } } for (var i = doubleShotPowerups.length - 1; i >= 0; i--) { doubleShotPowerups[i].y += ballSpeed * gameSpeed; if (doubleShotPowerups[i].y > 2732 + 100) { doubleShotPowerups[i].destroy(); doubleShotPowerups.splice(i, 1); } } for (var i = lightningPowerups.length - 1; i >= 0; i--) { lightningPowerups[i].y += ballSpeed * gameSpeed; if (lightningPowerups[i].y > 2732 + 100) { lightningPowerups[i].destroy(); lightningPowerups.splice(i, 1); } } for (var i = ghostBalls.length - 1; i >= 0; i--) { ghostBalls[i].y += ballSpeed * gameSpeed; if (ghostBalls[i].y > 2732 + 100) { ghostBalls[i].destroy(); ghostBalls.splice(i, 1); } } for (var i = mirrorBalls.length - 1; i >= 0; i--) { mirrorBalls[i].y += ballSpeed * gameSpeed; if (mirrorBalls[i].y > 2732 + 100) { mirrorBalls[i].destroy(); mirrorBalls.splice(i, 1); } } for (var i = magnetBalls.length - 1; i >= 0; i--) { magnetBalls[i].y += ballSpeed * gameSpeed; if (magnetBalls[i].y > 2732 + 100) { magnetBalls[i].destroy(); magnetBalls.splice(i, 1); } } for (var i = freezeBombPowerups.length - 1; i >= 0; i--) { freezeBombPowerups[i].y += ballSpeed * gameSpeed; if (freezeBombPowerups[i].y > 2732 + 100) { freezeBombPowerups[i].destroy(); freezeBombPowerups.splice(i, 1); } } for (var i = chainReactionPowerups.length - 1; i >= 0; i--) { chainReactionPowerups[i].y += ballSpeed * gameSpeed; if (chainReactionPowerups[i].y > 2732 + 100) { chainReactionPowerups[i].destroy(); chainReactionPowerups.splice(i, 1); } } for (var i = teleportPowerups.length - 1; i >= 0; i--) { teleportPowerups[i].y += ballSpeed * gameSpeed; if (teleportPowerups[i].y > 2732 + 100) { teleportPowerups[i].destroy(); teleportPowerups.splice(i, 1); } } // Update rainbow balls for (var i = 0; i < rainbowBalls.length; i++) { rainbowBalls[i].y += ballSpeed * gameSpeed; if (rainbowBalls[i].update) { rainbowBalls[i].update(); } } // Update bomb balls for (var i = 0; i < bombBalls.length; i++) { bombBalls[i].y += ballSpeed * gameSpeed; if (bombBalls[i].update) { bombBalls[i].update(); } } // Update projectiles for (var i = projectiles.length - 1; i >= 0; i--) { var projectile = projectiles[i]; // Defensive: skip if projectile is undefined/null if (!projectile) { projectiles.splice(i, 1); continue; } // Apply game speed to projectile movement (but only for update, do not overwrite velocity permanently) var oldVelX = projectile.velocityX !== undefined ? projectile.velocityX : 0; var oldVelY = projectile.velocityY !== undefined ? projectile.velocityY : 0; projectile.x += oldVelX * (gameSpeed - 1); projectile.y += oldVelY * (gameSpeed - 1); if (typeof projectile.update === "function" ? projectile.update() : true || projectile.y > 2732 + 50) { if (typeof projectile.destroy === "function") projectile.destroy(); projectiles.splice(i, 1); continue; } // Apply magnet effect if (magnetActive) { var closestBall = null; var closestDist = 200; for (var j = 0; j < balls.length; j++) { var ball = balls[j]; var dx = ball.x - projectile.x; var dy = ball.y - projectile.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < closestDist) { closestDist = dist; closestBall = ball; } } if (closestBall) { var dx = closestBall.x - projectile.x; var dy = closestBall.y - projectile.y; var dist = Math.sqrt(dx * dx + dy * dy); projectile.velocityX += dx / dist * 2; projectile.velocityY += dy / dist * 2; var speed = Math.sqrt(projectile.velocityX * projectile.velocityX + projectile.velocityY * projectile.velocityY); if (speed > projectile.speed * 1.5) { projectile.velocityX = projectile.velocityX / speed * projectile.speed * 1.5; projectile.velocityY = projectile.velocityY / speed * projectile.speed * 1.5; } } } // Apply magnet ball attraction for (var m = 0; m < magnetBalls.length; m++) { var magnetBall = magnetBalls[m]; var dx = magnetBall.x - projectile.x; var dy = magnetBall.y - projectile.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < magnetBall.magnetRadius && dist > magnetBall.radius) { // Attract projectile var force = (1 - dist / magnetBall.magnetRadius) * 3; projectile.velocityX += dx / dist * force; projectile.velocityY += dy / dist * force; // Normalize speed var speed = Math.sqrt(projectile.velocityX * projectile.velocityX + projectile.velocityY * projectile.velocityY); if (speed > projectile.speed * 2) { projectile.velocityX = projectile.velocityX / speed * projectile.speed * 2; projectile.velocityY = projectile.velocityY / speed * projectile.speed * 2; } } } var hitBall = false; // Check boss collisions first for (var j = bossBalls.length - 1; j >= 0; j--) { var boss = bossBalls[j]; if (checkCollision(projectile, boss, projectile.radius, boss.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; // Critical hit chance var isCritical = Math.random() < criticalHitChance; var damage = isCritical ? 5 : 1; if (isCritical) { var critText = new Text2('CRITICAL!', { size: 60, fill: 0xffff00 }); critText.anchor.set(0.5, 0.5); critText.x = boss.x; critText.y = boss.y - 100; game.addChild(critText); tween(critText, { y: boss.y - 150, alpha: 0 }, { duration: 1000, onFinish: function onFinish() { critText.destroy(); } }); // Add critical hit effect var critEffect = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: boss.x, y: boss.y, scaleX: 0.1, scaleY: 0.1, alpha: 0.8, tint: 0xffff00 }); tween(critEffect, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 500, onFinish: function onFinish() { critEffect.destroy(); } }); } for (var d = 0; d < damage; d++) { if (boss.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + 500); createExplosion(boss.x, boss.y, 0xff1744, 50); boss.destroy(); bossBalls.splice(j, 1); // Boss killed achievement if (!achievements.bossKiller) { achievements.bossKiller = true; showAchievement('Boss Slayer!', 0xff1744); } break; } } // Handle projectile after boss hit if (projectile.type !== 'piercing' && projectile.type !== 'fireball' && projectile.type !== 'laser') { projectile.destroy(); projectiles.splice(i, 1); i--; break; } } } // Check rainbow ball collisions for (var j = rainbowBalls.length - 1; j >= 0; j--) { var rainbowBall = rainbowBalls[j]; if (checkCollision(projectile, rainbowBall, projectile.radius, rainbowBall.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; // Rainbow balls give bonus points var bonus = 50 * scoreMultiplier; if (rainbowBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + bonus * 5); createExplosion(rainbowBall.x, rainbowBall.y, 0xffffff, 40); achievementProgress.rainbowHunter++; if (achievementProgress.rainbowHunter >= 20) checkAchievement('rainbowHunter'); // Create rainbow particle effect for (var p = 0; p < 20; p++) { var particle = new Particle(); particle.x = rainbowBall.x; particle.y = rainbowBall.y; var angle = p / 20 * Math.PI * 2; particle.velocityX = Math.cos(angle) * 8; particle.velocityY = Math.sin(angle) * 8; particle.tint = Math.random() * 0xffffff | 0; particles.push(particle); game.addChild(particle); } rainbowBall.destroy(); rainbowBalls.splice(j, 1); } // Projectile continues through rainbow balls } } // Check ghost ball collisions for (var j = ghostBalls.length - 1; j >= 0; j--) { var ghostBall = ghostBalls[j]; if (!ghostBall.isPhased && checkCollision(projectile, ghostBall, projectile.radius, ghostBall.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; if (ghostBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + 100 * scoreMultiplier * scoreBoostMultiplier); createExplosion(ghostBall.x, ghostBall.y, 0x8888ff, 30); ghostBall.destroy(); ghostBalls.splice(j, 1); ballsDestroyed++; if (!achievements.ghostHunter) { achievements.ghostHunter = true; showAchievement('Ghost Hunter!', 0x8888ff); } } } } // Check magnet ball collisions for (var j = magnetBalls.length - 1; j >= 0; j--) { var magnetBall = magnetBalls[j]; if (checkCollision(projectile, magnetBall, projectile.radius, magnetBall.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; if (magnetBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + 200 * scoreMultiplier * scoreBoostMultiplier); createExplosion(magnetBall.x, magnetBall.y, 0x0066cc, 45); // Create magnetic shockwave var shockwave = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: magnetBall.x, y: magnetBall.y, scaleX: 0.1, scaleY: 0.1, alpha: 0.6, tint: 0x0099ff }); tween(shockwave, { scaleX: 8, scaleY: 8, alpha: 0 }, { duration: 800, onFinish: function onFinish() { shockwave.destroy(); } }); magnetBall.destroy(); magnetBalls.splice(j, 1); ballsDestroyed++; checkAchievement('magnetMaster'); } // Projectile behavior after magnet hit if (projectile.type !== 'laser' && projectile.type !== 'piercing') { projectile.destroy(); projectiles.splice(i, 1); i--; break; } } } // Check mirror ball collisions for (var j = mirrorBalls.length - 1; j >= 0; j--) { var mirrorBall = mirrorBalls[j]; if (checkCollision(projectile, mirrorBall, projectile.radius, mirrorBall.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; // Reflect projectile var dx = projectile.x - mirrorBall.x; var dy = projectile.y - mirrorBall.y; var dist = Math.sqrt(dx * dx + dy * dy); dx /= dist; dy /= dist; projectile.velocityX = dx * projectile.speed * 1.5; projectile.velocityY = dy * projectile.speed * 1.5; // Mirror flash effect var flash = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: mirrorBall.x, y: mirrorBall.y, scaleX: 1, scaleY: 1, alpha: 0.8, tint: 0xffffff }); tween(flash, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, onFinish: function onFinish() { flash.destroy(); } }); if (mirrorBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + 150 * scoreMultiplier * scoreBoostMultiplier); createExplosion(mirrorBall.x, mirrorBall.y, 0xc0c0c0, 40); mirrorBall.destroy(); mirrorBalls.splice(j, 1); ballsDestroyed++; } // Projectile bounces off mirror balls if (projectile.type !== 'laser') { break; } } } // Check bomb ball collisions for (var j = bombBalls.length - 1; j >= 0; j--) { var bombBall = bombBalls[j]; if (checkCollision(projectile, bombBall, projectile.radius, bombBall.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; if (bombBall.takeDamage()) { LK.getSound('destroy').play(); // Bomb explosion damages all nearby balls createExplosion(bombBall.x, bombBall.y, 0xff0000, 50); LK.effects.flashScreen(0xff0000, 300); achievementProgress.bombExpert++; if (achievementProgress.bombExpert >= 10) checkAchievement('bombExpert'); // Damage all balls in explosion radius (collect first, then destroy to avoid index skipping) var toDestroy = []; for (var k = 0; k < balls.length; k++) { var nearbyBall = balls[k]; if (checkCollision(bombBall, nearbyBall, 200, nearbyBall.radius)) { for (var d = 0; d < 3; d++) { if (nearbyBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 2)); createExplosion(nearbyBall.x, nearbyBall.y, 0xffff00, 20); toDestroy.push(nearbyBall); break; } } } } // Now destroy all marked balls (destroy objects, then remove from array) for (var td = 0; td < toDestroy.length; td++) { var obj = toDestroy[td]; var idx = balls.indexOf(obj); if (idx !== -1) { balls[idx].destroy(); balls.splice(idx, 1); } } bombBall.destroy(); bombBalls.splice(j, 1); } projectile.destroy(); projectiles.splice(i, 1); i--; break; } } // Check ball collisions for (var j = balls.length - 1; j >= 0; j--) { var ball = balls[j]; if (checkCollision(projectile, ball, projectile.radius, ball.radius)) { LK.getSound('hit').play(); updateCombo(); hitBall = true; // Set gravity to 1% per frame after hit if (typeof projectile.gravity === "undefined" || projectile.gravity < 0.1) { projectile.gravity = 0.1; } // Handle explosive projectiles if (projectile.type === 'explosive') { // No explosion effect, just damage nearby balls (loop backwards to avoid skipping) // Also remove any projectiles that are inside the explosion radius to prevent stuck balls for (var k = balls.length - 1; k >= 0; k--) { var otherBall = balls[k]; if (checkCollision(ball, otherBall, 150, otherBall.radius)) { if (otherBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier)); // No explosion effect here otherBall.destroy(); balls.splice(k, 1); } } } // Remove any projectiles that are inside the explosion radius (except the current one) for (var pk = projectiles.length - 1; pk >= 0; pk--) { var otherProj = projectiles[pk]; if (otherProj !== projectile && checkCollision(ball, otherProj, 150, otherProj.radius)) { otherProj.destroy(); projectiles.splice(pk, 1); } } } if (ball.takeDamage()) { LK.getSound('destroy').play(); consecutiveHits++; if (consecutiveHits >= 3) { chainReactionActive = true; achievementProgress.chainReactionPro++; if (achievementProgress.chainReactionPro >= 50) checkAchievement('chainReactionPro'); } // Track weapon kills switch (projectile.type) { case 'fireball': achievementProgress.fireballKills++; if (achievementProgress.fireballKills >= 100) checkAchievement('fireballKills'); break; case 'laser': achievementProgress.laserKills++; if (achievementProgress.laserKills >= 100) checkAchievement('laserKills'); break; case 'explosive': achievementProgress.explosiveKills++; if (achievementProgress.explosiveKills >= 100) checkAchievement('explosiveKills'); break; case 'piercing': achievementProgress.piercingKills++; if (achievementProgress.piercingKills >= 100) checkAchievement('piercingKills'); break; case 'rapid': achievementProgress.rapidKills++; if (achievementProgress.rapidKills >= 100) checkAchievement('rapidKills'); break; case 'split': achievementProgress.splitKills++; if (achievementProgress.splitKills >= 100) checkAchievement('splitKills'); break; case 'giant': achievementProgress.giantKills++; if (achievementProgress.giantKills >= 100) checkAchievement('giantKills'); break; } // Track perfect accuracy achievementProgress.perfectAccuracy++; if (achievementProgress.perfectAccuracy >= 100) checkAchievement('perfectAccuracy'); // Check for lucky long distance shot var shotDistance = Math.sqrt(Math.pow(ball.x - cannon.x, 2) + Math.pow(ball.y - cannon.y, 2)); if (shotDistance > 2000) { checkAchievement('luckyShot'); // Lucky shot visual effect var luckyText = new Text2('LUCKY SHOT!', { size: 20, fill: 0xffd700 }); luckyText.anchor.set(0.5, 0.5); luckyText.x = ball.x; luckyText.y = ball.y - 100; game.addChild(luckyText); tween(luckyText, { y: ball.y - 200, alpha: 0 }, { duration: 1500, onFinish: function onFinish() { luckyText.destroy(); } }); } var points = Math.floor(stage * scoreMultiplier * scoreBoostMultiplier * (chainReactionActive ? 2 : 1)); LK.setScore(LK.getScore() + points); scoreText.setText('Score: ' + LK.getScore()); createExplosion(ball.x, ball.y, 0xffff00, chainReactionActive ? 25 : 15); // Chain reaction damage (loop backwards to avoid skipping) if (chainReactionActive) { for (var k = balls.length - 1; k >= 0; k--) { var nearbyBall = balls[k]; if (nearbyBall !== ball && checkCollision(ball, nearbyBall, 100, nearbyBall.radius)) { if (nearbyBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 2)); createExplosion(nearbyBall.x, nearbyBall.y, 0xffff00, 20); nearbyBall.destroy(); balls.splice(k, 1); } } } } ball.destroy(); balls.splice(j, 1); ballsDestroyed++; perfectHits++; } // Handle projectile behavior after hit if (projectile.type === 'lightning') { // Chain to nearby balls var chainTargets = []; for (var k = 0; k < balls.length; k++) { var nearbyBall = balls[k]; if (nearbyBall !== ball && checkCollision(ball, nearbyBall, 150, nearbyBall.radius)) { chainTargets.push(nearbyBall); } } // Create lightning visual effect for (var c = 0; c < Math.min(chainTargets.length, 3); c++) { var target = chainTargets[c]; var lightning = game.attachAsset('aimline', { anchorX: 0.5, anchorY: 0, x: ball.x, y: ball.y, tint: 0x9966ff, alpha: 0.8 }); var dx = target.x - ball.x; var dy = target.y - ball.y; var dist = Math.sqrt(dx * dx + dy * dy); lightning.height = dist; lightning.rotation = Math.atan2(dy, dx) + Math.PI / 2; tween(lightning, { alpha: 0, scaleX: 0.1 }, { duration: 300, onFinish: function onFinish() { lightning.destroy(); } }); // Damage chained balls if (target.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * scoreBoostMultiplier)); createExplosion(target.x, target.y, 0x9966ff, 20); target.destroy(); var idx = balls.indexOf(target); if (idx > -1) balls.splice(idx, 1); } } projectile.destroy(); projectiles.splice(i, 1); i--; break; } else if (projectile.type === 'piercing' && projectile.piercing > 0) { projectile.piercing--; // Continue in same direction } else if (projectile.type === 'explosive') { projectile.destroy(); projectiles.splice(i, 1); i--; break; } else if (projectile.type === 'fireball') { // Fireball burns through everything createExplosion(ball.x, ball.y, 0xff6600, 15); } else if (projectile.type === 'split') { // Split into 3 projectiles for (var s = 0; s < 3; s++) { var splitProjectile = new SpecialProjectile(); splitProjectile.x = projectile.x; splitProjectile.y = projectile.y; splitProjectile.setType('normal'); var splitAngle = Math.atan2(projectile.velocityY, projectile.velocityX) + (s - 1) * 0.5; splitProjectile.velocityX = Math.cos(splitAngle) * splitProjectile.speed; splitProjectile.velocityY = Math.sin(splitAngle) * splitProjectile.speed; projectiles.push(splitProjectile); game.addChild(splitProjectile); } projectile.destroy(); projectiles.splice(i, 1); i--; break; } else if (projectile.type === 'laser') { // Laser continues straight } else { // Normal bounce var dx = projectile.x - ball.x; var dy = projectile.y - ball.y; var dist = Math.sqrt(dx * dx + dy * dy); dx /= dist; dy /= dist; projectile.velocityX = dx * projectile.speed; projectile.velocityY = dy * projectile.speed; } if (!projectile.type || projectile.type === 'normal' || projectile.type === 'rapid' || projectile.type === 'giant') { break; } } } if (hitBall) { // Perfect shot bonus if (consecutiveHits >= 10 && consecutiveHits % 5 === 0) { var perfectBonus = 100 * scoreMultiplier; LK.setScore(LK.getScore() + perfectBonus); var perfectText = new Text2('PERFECT SHOT! +' + perfectBonus, { size: 60, fill: 0x00ff00 }); perfectText.anchor.set(0.5, 0.5); perfectText.alpha = 0; LK.gui.center.addChild(perfectText); tween(perfectText, { alpha: 1, y: -50 }, { duration: 300, onFinish: function onFinish() { tween(perfectText, { alpha: 0 }, { duration: 500, delay: 500, onFinish: function onFinish() { perfectText.destroy(); } }); } }); } continue; } else { chainReactionActive = false; consecutiveHits = 0; } // Check powerup collisions for (var j = powerups.length - 1; j >= 0; j--) { var powerup = powerups[j]; if (checkCollision(projectile, powerup, projectile.radius, powerup.radius)) { LK.getSound('collect').play(); projectileCount++; projectileCountText.setText('x' + projectileCount); createExplosion(powerup.x, powerup.y, 0x4ecdc4, 10); powerup.destroy(); powerups.splice(j, 1); } } // Check slow motion power-up collisions for (var j = slowMotionPowerups.length - 1; j >= 0; j--) { var slowPowerup = slowMotionPowerups[j]; if (checkCollision(projectile, slowPowerup, projectile.radius, slowPowerup.radius)) { LK.getSound('collect').play(); slowMotionActive = true; slowMotionTimer = 300; // 5 seconds at 60 FPS powerUpIndicator.setText('SLOW MOTION'); achievementProgress.slowMotionPro++; achievementProgress.powerupMaster++; if (achievementProgress.slowMotionPro >= 20) checkAchievement('slowMotionPro'); if (achievementProgress.powerupMaster >= 100) checkAchievement('powerupMaster'); tween(slowMotionBg, { alpha: 0.1 }, { duration: 300 }); createExplosion(slowPowerup.x, slowPowerup.y, 0x9b59b6, 20); slowPowerup.destroy(); slowMotionPowerups.splice(j, 1); } } // Check multiball power-up collisions for (var j = multiballPowerups.length - 1; j >= 0; j--) { var multiballPowerup = multiballPowerups[j]; if (checkCollision(projectile, multiballPowerup, projectile.radius, multiballPowerup.radius)) { LK.getSound('collect').play(); multiballActive = true; powerUpIndicator.setText('MULTIBALL!'); createExplosion(multiballPowerup.x, multiballPowerup.y, 0xe74c3c, 25); multiballPowerup.destroy(); multiballPowerups.splice(j, 1); } } // Check fireball power-up collisions for (var j = fireballPowerups.length - 1; j >= 0; j--) { var fireballPowerup = fireballPowerups[j]; if (checkCollision(projectile, fireballPowerup, projectile.radius, fireballPowerup.radius)) { LK.getSound('collect').play(); fireballActive = true; powerUpIndicator.setText('FIREBALL!'); createExplosion(fireballPowerup.x, fireballPowerup.y, 0xff6600, 30); fireballPowerup.destroy(); fireballPowerups.splice(j, 1); } } // Check giant ball power-up collisions for (var j = giantBallPowerups.length - 1; j >= 0; j--) { var giantBallPowerup = giantBallPowerups[j]; if (checkCollision(projectile, giantBallPowerup, projectile.radius, giantBallPowerup.radius)) { LK.getSound('collect').play(); giantBallActive = true; powerUpIndicator.setText('GIANT BALL!'); createExplosion(giantBallPowerup.x, giantBallPowerup.y, 0x00ff00, 35); giantBallPowerup.destroy(); giantBallPowerups.splice(j, 1); } } // Check split ball power-up collisions for (var j = splitBallPowerups.length - 1; j >= 0; j--) { var splitBallPowerup = splitBallPowerups[j]; if (checkCollision(projectile, splitBallPowerup, projectile.radius, splitBallPowerup.radius)) { LK.getSound('collect').play(); splitBallActive = true; powerUpIndicator.setText('SPLIT BALL!'); createExplosion(splitBallPowerup.x, splitBallPowerup.y, 0xff00ff, 30); splitBallPowerup.destroy(); splitBallPowerups.splice(j, 1); } } // Check laser power-up collisions for (var j = laserPowerups.length - 1; j >= 0; j--) { var laserPowerup = laserPowerups[j]; if (checkCollision(projectile, laserPowerup, projectile.radius, laserPowerup.radius)) { LK.getSound('collect').play(); laserActive = true; powerUpIndicator.setText('LASER BEAM!'); createExplosion(laserPowerup.x, laserPowerup.y, 0x00ffff, 40); laserPowerup.destroy(); laserPowerups.splice(j, 1); } } // Check shield power-up collisions for (var j = shieldPowerups.length - 1; j >= 0; j--) { var shieldPowerup = shieldPowerups[j]; if (checkCollision(projectile, shieldPowerup, projectile.radius, shieldPowerup.radius)) { LK.getSound('collect').play(); shieldActive = true; shieldTimer = 600; // 10 seconds powerUpIndicator.setText('SHIELD ACTIVE!'); tween(shieldBg, { alpha: 0.3 }, { duration: 300 }); createExplosion(shieldPowerup.x, shieldPowerup.y, 0x3498db, 30); shieldPowerup.destroy(); shieldPowerups.splice(j, 1); // Shield achievement if (!achievements.shieldMaster) { achievements.shieldMaster = true; showAchievement('Shield Master!', 0x3498db); } } } // Check double shot power-up collisions for (var j = doubleShotPowerups.length - 1; j >= 0; j--) { var doubleShotPowerup = doubleShotPowerups[j]; if (checkCollision(projectile, doubleShotPowerup, projectile.radius, doubleShotPowerup.radius)) { LK.getSound('collect').play(); doubleShotActive = true; doubleShotTimer = 600; // 10 seconds doubleShotIndicator.setText('DOUBLE SHOT!'); createExplosion(doubleShotPowerup.x, doubleShotPowerup.y, 0xffff00, 35); doubleShotPowerup.destroy(); doubleShotPowerups.splice(j, 1); } } // Check lightning power-up collisions for (var j = lightningPowerups.length - 1; j >= 0; j--) { var lightningPowerup = lightningPowerups[j]; if (checkCollision(projectile, lightningPowerup, projectile.radius, lightningPowerup.radius)) { LK.getSound('collect').play(); lightningActive = true; powerUpIndicator.setText('LIGHTNING CHAIN!'); createExplosion(lightningPowerup.x, lightningPowerup.y, 0x9966ff, 40); lightningPowerup.destroy(); lightningPowerups.splice(j, 1); powerupsCollected++; if (!achievements.lightningMaster) { achievements.lightningMaster = true; showAchievement('Lightning Master!', 0x9966ff); } } } // Check freeze bomb power-up collisions for (var j = freezeBombPowerups.length - 1; j >= 0; j--) { var freezeBombPowerup = freezeBombPowerups[j]; if (checkCollision(projectile, freezeBombPowerup, projectile.radius, freezeBombPowerup.radius)) { LK.getSound('collect').play(); // Freeze explosion effect createExplosion(freezeBombPowerup.x, freezeBombPowerup.y, 0x00ccff, 50); LK.effects.flashScreen(0x00ccff, 500); // Freeze all balls in radius (loop backwards to avoid skipping) for (var k = balls.length - 1; k >= 0; k--) { var ball = balls[k]; if (checkCollision(freezeBombPowerup, ball, 300, ball.radius)) { ball.tint = 0x00ccff; // Create ice effect on ball var ice = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: ball.x, y: ball.y, scaleX: 1.2, scaleY: 1.2, alpha: 0.3, tint: 0x00ffff }); tween(ice, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 2000, onFinish: function onFinish() { ice.destroy(); } }); // Damage frozen ball for (var d = 0; d < 5; d++) { if (ball.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 3)); createExplosion(ball.x, ball.y, 0x00ccff, 25); ball.destroy(); balls.splice(k, 1); ballsDestroyed++; break; } } } } freezeBombPowerup.destroy(); freezeBombPowerups.splice(j, 1); powerupsCollected++; } } // Check chain reaction power-up collisions for (var j = chainReactionPowerups.length - 1; j >= 0; j--) { var chainReactionPowerup = chainReactionPowerups[j]; if (checkCollision(projectile, chainReactionPowerup, projectile.radius, chainReactionPowerup.radius)) { LK.getSound('collect').play(); chainReactionBombActive = true; powerUpIndicator.setText('CHAIN BOMB!'); createExplosion(chainReactionPowerup.x, chainReactionPowerup.y, 0xff8800, 40); // Make next hit cause massive chain reaction consecutiveHits = 10; chainReactionActive = true; chainReactionPowerup.destroy(); chainReactionPowerups.splice(j, 1); powerupsCollected++; } } // Check teleport power-up collisions for (var j = teleportPowerups.length - 1; j >= 0; j--) { var teleportPowerup = teleportPowerups[j]; if (checkCollision(projectile, teleportPowerup, projectile.radius, teleportPowerup.radius)) { LK.getSound('collect').play(); // Teleport effect var portal1 = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: projectile.x, y: projectile.y, scaleX: 0.1, scaleY: 0.1, alpha: 0.8, tint: 0x8000ff }); tween(portal1, { scaleX: 2, scaleY: 2, alpha: 0, rotation: Math.PI * 2 }, { duration: 500, onFinish: function onFinish() { portal1.destroy(); } }); // Teleport projectile to random position projectile.x = Math.random() * 1648 + 200; projectile.y = Math.random() * 1000 + 500; // Exit portal effect var portal2 = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: projectile.x, y: projectile.y, scaleX: 2, scaleY: 2, alpha: 0, tint: 0x8000ff }); tween(portal2, { scaleX: 0.1, scaleY: 0.1, alpha: 0.8, rotation: -Math.PI * 2 }, { duration: 500, onFinish: function onFinish() { portal2.destroy(); } }); teleportPowerup.destroy(); teleportPowerups.splice(j, 1); powerupsCollected++; } } // Check star collisions for (var j = stars.length - 1; j >= 0; j--) { var star = stars[j]; // HeartBall: +10 HP, effect, destroy if (star instanceof HeartBall && checkCollision(projectile, star, projectile.radius, star.radius)) { LK.getSound('collect').play(); var oldHP = hp; hp = Math.min(hp + 10, maxHP); // Show +10 HP effect var hpGainText = new Text2('+10 HP', { size: 60, fill: 0xff3366 }); hpGainText.anchor.set(0.5, 0.5); hpGainText.x = star.x; hpGainText.y = star.y; game.addChild(hpGainText); tween(hpGainText, { y: star.y - 100, alpha: 0 }, { duration: 800, onFinish: function onFinish() { hpGainText.destroy(); } }); hpText.setText('HP: ' + hp); createExplosion(star.x, star.y, 0xff3366, 15); star.destroy(); stars.splice(j, 1); continue; } // Normal star if (checkCollision(projectile, star, projectile.radius, star.radius)) { LK.getSound('collect').play(); // Random bonus effect var randomEffect = Math.random(); if (randomEffect < 0.15) { magnetActive = true; magnetTimer = 180; // 3 seconds powerUpIndicator.setText('MAGNET ACTIVE'); } else if (randomEffect < 0.3) { projectileCount += 2; projectileCountText.setText('x' + projectileCount); } else if (randomEffect < 0.45) { // Freeze all balls temporarily freezeActive = true; freezeTimer = 180; // 3 seconds powerUpIndicator.setText('FREEZE!'); for (var k = 0; k < balls.length; k++) { balls[k].tint = 0x00ffff; } } else if (randomEffect < 0.6) { // Reverse gravity reverseGravityActive = true; reverseGravityTimer = 300; // 5 seconds ballSpeed = -Math.abs(ballSpeed); powerUpIndicator.setText('REVERSE GRAVITY!'); LK.effects.flashScreen(0xff00ff, 500); if (!achievements.reverseGravity) { achievements.reverseGravity = true; showAchievement('Gravity Master!', 0xff00ff); } } else if (randomEffect < 0.75) { // Score boost scoreBoostActive = true; scoreBoostTimer = 600; // 10 seconds powerUpIndicator.setText('3X SCORE!'); } else if (randomEffect < 0.9) { // Auto aim autoAimActive = true; autoAimTimer = 300; // 5 seconds powerUpIndicator.setText('AUTO AIM!'); } else { // Random weapon power-up var weapons = ['fireball', 'giant', 'split', 'laser', 'lightning']; var randomWeapon = weapons[Math.floor(Math.random() * weapons.length)]; switch (randomWeapon) { case 'fireball': fireballActive = true; break; case 'giant': giantBallActive = true; break; case 'split': splitBallActive = true; break; case 'laser': laserActive = true; break; case 'lightning': lightningActive = true; break; } powerUpIndicator.setText(randomWeapon.toUpperCase() + '!'); } // Unlock weapons based on score // Check achievements if (combo >= 10 && !achievements.combo10) { achievements.combo10 = true; showAchievement('Combo Master!', 0xFF00FF); } if (LK.getScore() >= 1000 && !achievements.score1000) { achievements.score1000 = true; showAchievement('Score Champion!', 0xFFD700); } if (weaponUnlocks.piercing && weaponUnlocks.explosive && weaponUnlocks.rapid && !achievements.allWeapons) { achievements.allWeapons = true; showAchievement('Weapon Master!', 0x00FF00); } // Save high score if (!savedData.highScore || LK.getScore() > savedData.highScore) { savedData.highScore = LK.getScore(); // Flatten achievements into savedData directly savedData.firstWin = achievements.firstWin; savedData.combo10 = achievements.combo10; savedData.score1000 = achievements.score1000; savedData.allWeapons = achievements.allWeapons; storage['99balls_save'] = savedData; } if (LK.getScore() >= 100 && !weaponUnlocks.piercing) { weaponUnlocks.piercing = true; var unlockText = new Text2('Piercing Weapon Unlocked!', { size: 80, fill: 0xFF00FF }); unlockText.anchor.set(0.5, 0.5); unlockText.alpha = 0; LK.gui.center.addChild(unlockText); tween(unlockText, { alpha: 1, y: -100 }, { duration: 500, onFinish: function onFinish() { tween(unlockText, { alpha: 0 }, { duration: 1000, delay: 1000, onFinish: function onFinish() { unlockText.destroy(); } }); } }); } if (LK.getScore() >= 300 && !weaponUnlocks.explosive) { weaponUnlocks.explosive = true; var unlockText = new Text2('Explosive Weapon Unlocked!', { size: 80, fill: 0xFF4444 }); unlockText.anchor.set(0.5, 0.5); unlockText.alpha = 0; LK.gui.center.addChild(unlockText); tween(unlockText, { alpha: 1, y: -100 }, { duration: 500, onFinish: function onFinish() { tween(unlockText, { alpha: 0 }, { duration: 1000, delay: 1000, onFinish: function onFinish() { unlockText.destroy(); } }); } }); } if (LK.getScore() >= 500 && !weaponUnlocks.rapid) { weaponUnlocks.rapid = true; var unlockText = new Text2('Rapid Fire Unlocked!', { size: 80, fill: 0x44FF44 }); unlockText.anchor.set(0.5, 0.5); unlockText.alpha = 0; LK.gui.center.addChild(unlockText); tween(unlockText, { alpha: 1, y: -100 }, { duration: 500, onFinish: function onFinish() { tween(unlockText, { alpha: 0 }, { duration: 1000, delay: 1000, onFinish: function onFinish() { unlockText.destroy(); } }); } }); } LK.setScore(LK.getScore() + Math.floor(10 * scoreMultiplier)); scoreText.setText('Score: ' + LK.getScore()); createExplosion(star.x, star.y, 0xffd93d, 15); star.destroy(); stars.splice(j, 1); achievementProgress.starCollector++; if (achievementProgress.starCollector >= 50) checkAchievement('starCollector'); } } } // Check if all projectiles are gone if (projectiles.length === 0 && !canShoot) { canShoot = true; moveRow(); if (balls.length === 0) { stage++; stageText.setText('Stage ' + stage); ballSpeed += 0.1; // Bonus for clearing stage var bonus = stage * 50; LK.setScore(LK.getScore() + bonus); scoreText.setText('Score: ' + LK.getScore()); var bonusText = new Text2('Stage Clear! +' + bonus, { size: 100, fill: 0x00FF00 }); bonusText.anchor.set(0.5, 0.5); bonusText.alpha = 0; LK.gui.center.addChild(bonusText); // Check if this is first stage clear if (stage === 2 && !achievements.firstWin) { achievements.firstWin = true; showAchievement('First Victory!', 0x00FF00); } // Perfect stage bonus if (projectileCount === 1) { perfectStageBonus = true; var perfectBonus = stage * 100; LK.setScore(LK.getScore() + perfectBonus); showAchievement('Perfect Stage! +' + perfectBonus, 0xFFD700); if (!achievements.perfectStage) { achievements.perfectStage = true; showAchievement('Perfectionist!', 0xFFD700); } } tween(bonusText, { alpha: 1, y: -200 }, { duration: 500, onFinish: function onFinish() { tween(bonusText, { alpha: 0 }, { duration: 500, delay: 500, onFinish: function onFinish() { bonusText.destroy(); } }); } }); } } // Check time-based achievements if (LK.ticks % 60 === 0) { var seconds = Math.floor(LK.ticks / 60); if (seconds >= 600 && !achievements.survivor) { checkAchievement('survivor'); } } // Check stage achievements if (stage >= 10) checkAchievement('stage10'); if (stage >= 25) checkAchievement('stage25'); if (stage >= 50) checkAchievement('stage50'); // Check score achievements if (LK.getScore() >= 5000) checkAchievement('score5000'); if (LK.getScore() >= 10000) checkAchievement('score10000'); if (LK.getScore() >= 50000) checkAchievement('score50000'); // Check combo achievements if (combo >= 20) checkAchievement('combo20'); if (combo >= 50) checkAchievement('combo50'); // Check projectile achievements if (projectileCount >= 10) checkAchievement('richPlayer'); if (achievementProgress.projectiles50 >= 50) checkAchievement('projectiles50'); if (achievementProgress.projectiles100 >= 100) checkAchievement('projectiles100'); // Special win condition - collect all power-up types in one game var allPowerUpsCollected = fireballActive || giantBallActive || splitBallActive || laserActive || lightningActive || multiballActive || doubleShotActive || slowMotionActive || magnetActive || shieldActive || freezeActive; if (allPowerUpsCollected && powerupsCollected >= 20 && !achievements.versatile) { checkAchievement('versatile'); // Epic win effect var epicWin = new Text2('POWER MASTER!', { size: 120, fill: 0xff00ff }); epicWin.anchor.set(0.5, 0.5); epicWin.alpha = 0; LK.gui.center.addChild(epicWin); tween(epicWin, { alpha: 1, rotation: Math.PI * 2 }, { duration: 1000, onFinish: function onFinish() { tween(epicWin, { alpha: 0, scaleX: 3, scaleY: 3 }, { duration: 1000, onFinish: function onFinish() { epicWin.destroy(); } }); } }); } // Check power-up master achievement if (powerupsCollected >= 100) checkAchievement('powerupMaster'); // Special effects for high combos if (combo > 30 && combo % 10 === 0) { var rainbowFlash = game.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.1, scaleY: 0.1, alpha: 0.5, tint: Math.random() * 0xffffff | 0 }); tween(rainbowFlash, { scaleX: 30, scaleY: 30, alpha: 0, rotation: Math.PI * 4 }, { duration: 1000, onFinish: function onFinish() { rainbowFlash.destroy(); } }); } // Check game over if (gameActive) { for (var i = 0; i < balls.length; i++) { if (balls[i].y > 2400) { if (shieldActive) { // Shield protects from game over once shieldActive = false; shieldTimer = 0; tween(shieldBg, { alpha: 0 }, { duration: 300 }); balls[i].destroy(); balls.splice(i, 1); var shieldSaveText = new Text2('SHIELD SAVED YOU!', { size: 80, fill: 0x3498db }); shieldSaveText.anchor.set(0.5, 0.5); shieldSaveText.alpha = 0; LK.gui.center.addChild(shieldSaveText); tween(shieldSaveText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { tween(shieldSaveText, { alpha: 0 }, { duration: 500, delay: 1000, onFinish: function onFinish() { shieldSaveText.destroy(); } }); } }); LK.effects.flashScreen(0x3498db, 500); continue; } // HP system: decrease HP by the number on the ball var lostHP = 1; if (typeof balls[i].hits === "number") { lostHP = balls[i].hits; } else if (_typeof(balls[i].numberText) === "object" && balls[i].numberText.text) { var parsed = parseInt(balls[i].numberText.text, 10); if (!isNaN(parsed)) lostHP = parsed; } hp -= lostHP; if (hp < 0) hp = 0; hpText.setText('HP: ' + hp); // Visual feedback for HP loss var hpLossText = new Text2('-' + lostHP + ' HP', { size: 60, fill: 0xff4444 }); hpLossText.anchor.set(0.5, 0.5); hpLossText.x = balls[i].x; hpLossText.y = balls[i].y; game.addChild(hpLossText); tween(hpLossText, { y: balls[i].y - 100, alpha: 0 }, { duration: 800, onFinish: function onFinish() { hpLossText.destroy(); } }); balls[i].destroy(); balls.splice(i, 1); // Game over if HP is 0 or less if (hp <= 0) { gameActive = false; // Save progress before game over if (!savedData.highScore || LK.getScore() > savedData.highScore) { savedData.highScore = LK.getScore(); // Flatten achievements into savedData directly savedData.firstWin = achievements.firstWin; savedData.combo10 = achievements.combo10; savedData.score1000 = achievements.score1000; savedData.allWeapons = achievements.allWeapons; storage['99balls_save'] = savedData; } LK.showGameOver(); break; } } } } }; // Add achievements button var achievementsButton = game.addChild(new Container()); var achievementsBg = achievementsButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFD700, scaleX: 1.2, scaleY: 1.2 }); var achievementsButtonText = new Text2('Achievements', { size: 25, fill: 0x000000 }); achievementsButtonText.anchor.set(0.5, 0.5); achievementsButton.addChild(achievementsButtonText); achievementsButton.x = 1924; achievementsButton.y = 200; // Add glow effect to achievements button achievementsButton.update = function () { achievementsBg.alpha = 0.8 + Math.sin(LK.ticks * 0.05) * 0.2; }; // Achievement panel var achievementPanel = new Container(); var panelBg = achievementPanel.attachAsset('achievementPanelBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.95 }); achievementPanel.visible = false; LK.gui.center.addChild(achievementPanel); var achievementTitle = new Text2('ACHIEVEMENTS', { size: 60, fill: 0xFFD700 }); achievementTitle.anchor.set(0.5, 0.5); achievementTitle.y = -600; achievementPanel.addChild(achievementTitle); var closeButton = new Container(); var closeBg = closeButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5, tint: 0xff4444 }); var closeText = new Text2('X', { size: 40, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeButton.addChild(closeText); closeButton.x = 450; closeButton.y = -600; achievementPanel.addChild(closeButton); closeButton.down = function () { achievementPanel.visible = false; gameActive = true; }; achievementsButton.down = function () { achievementPanel.visible = true; gameActive = false; updateAchievementDisplay(); }; // Add weapon switch button var weaponButton = game.addChild(new Container()); var buttonBg = weaponButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2('Switch', { size: 30, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); weaponButton.addChild(buttonText); weaponButton.x = 1024; weaponButton.y = 2400; weaponButton.down = function () { var weapons = ['normal']; if (weaponUnlocks.piercing) weapons.push('piercing'); if (weaponUnlocks.explosive) weapons.push('explosive'); if (weaponUnlocks.rapid) weapons.push('rapid'); var currentIndex = weapons.indexOf(currentWeapon); currentWeapon = weapons[(currentIndex + 1) % weapons.length]; switch (currentWeapon) { case 'normal': weaponText.setText('Normal'); weaponText.tint = 0xFFFFFF; break; case 'piercing': weaponText.setText('Piercing'); weaponText.tint = 0xFF00FF; break; case 'explosive': weaponText.setText('Explosive'); weaponText.tint = 0xFF4444; break; case 'rapid': weaponText.setText('Rapid Fire'); weaponText.tint = 0x44FF44; break; } tween(weaponButton, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, onFinish: function onFinish() { tween(weaponButton, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); }; initializeLevel();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AimLine = Container.expand(function () {
var self = Container.call(this);
for (var i = 0; i < 10; i++) {
var dot = self.attachAsset('aimline', {
anchorX: 0.5,
anchorY: 0.5,
y: -i * 30,
alpha: 0.5 - i * 0.05
});
}
return self;
});
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.numberText = new Text2('1', {
size: 40,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 1;
self.radius = 40;
self.velocityX = 0;
self.velocityY = 0;
self.setNumber = function (num) {
self.hits = num;
self.numberText.setText(num.toString());
var scale = 1 + num / 50 * 0.5;
ballGraphics.scale.set(scale);
self.radius = 40 * scale;
};
self.takeDamage = function () {
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
tween(ballGraphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
return false;
};
return self;
});
var BombBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333,
scaleX: 1.3,
scaleY: 1.3
});
self.numberText = new Text2('💣', {
size: 40,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 5;
self.radius = 50;
self.velocityX = 0;
self.velocityY = 0;
self.pulseTimer = 0;
self.isBomb = true;
self.takeDamage = function () {
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
ballGraphics.tint = self.hits <= 2 ? 0xff0000 : 0x333333;
return false;
};
self.update = function () {
self.pulseTimer += 0.15;
if (self.hits <= 2) {
var pulse = 1 + Math.sin(self.pulseTimer) * 0.2;
ballGraphics.scale.set(1.3 * pulse);
}
};
return self;
});
var BossBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff1744,
scaleX: 2,
scaleY: 2
});
self.numberText = new Text2('BOSS', {
size: 50,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 50;
self.radius = 80;
self.velocityX = 2;
self.moveTimer = 0;
self.isBoss = true;
self.takeDamage = function () {
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
ballGraphics.tint = Math.random() > 0.5 ? 0xff1744 : 0xff6600;
tween(ballGraphics, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 2,
scaleY: 2
}, {
duration: 100
});
}
});
return false;
};
self.update = function () {
self.moveTimer += 0.05;
self.x += self.velocityX;
if (self.x <= self.radius || self.x >= 2048 - self.radius) {
self.velocityX *= -1;
}
ballGraphics.rotation += 0.02;
};
return self;
});
var Cannon = Container.expand(function () {
var self = Container.call(this);
var cannonGraphics = self.attachAsset('cannon', {
anchorX: 0.5,
anchorY: 0.8
});
self.rotation = 0;
return self;
});
var ChainReactionPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff8800,
scaleX: 1.4,
scaleY: 1.4
});
self.radius = 35;
self.chainTimer = 0;
self.update = function () {
self.chainTimer += 0.2;
var scale = 1.4 + Math.sin(self.chainTimer) * 0.2;
powerupGraphics.scale.set(scale);
// Chain effect
if (Math.random() < 0.2) {
var chain = self.attachAsset('aimline', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xff8800,
alpha: 0.6,
rotation: Math.random() * Math.PI * 2
});
tween(chain, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
chain.destroy();
}
});
}
};
return self;
});
var DoubleShotPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xffff00,
scaleX: 1.2,
scaleY: 1.2
});
self.radius = 30;
self.bounceTimer = 0;
self.update = function () {
self.bounceTimer += 0.08;
var scale = 1.2 + Math.sin(self.bounceTimer * 2) * 0.1;
powerupGraphics.scale.set(scale);
powerupGraphics.rotation -= 0.03;
};
return self;
});
var FireBallPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff6600
});
self.radius = 25;
self.flameTimer = 0;
self.update = function () {
self.flameTimer += 0.15;
var scale = 1 + Math.sin(self.flameTimer) * 0.4;
powerupGraphics.scale.set(scale);
powerupGraphics.alpha = 0.7 + Math.sin(self.flameTimer * 2) * 0.3;
};
return self;
});
var FreezeBombPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ccff,
scaleX: 1.3,
scaleY: 1.3
});
self.radius = 30;
self.iceTimer = 0;
self.update = function () {
self.iceTimer += 0.15;
powerupGraphics.alpha = 0.6 + Math.sin(self.iceTimer) * 0.4;
powerupGraphics.rotation += 0.02;
// Ice particle effect
if (Math.random() < 0.1) {
var iceParticle = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
tint: 0x00ffff,
alpha: 0.8
});
iceParticle.x = (Math.random() - 0.5) * 40;
iceParticle.y = (Math.random() - 0.5) * 40;
tween(iceParticle, {
y: iceParticle.y - 20,
alpha: 0,
scaleX: 0,
scaleY: 0
}, {
duration: 500,
onFinish: function onFinish() {
iceParticle.destroy();
}
});
}
};
return self;
});
var GhostBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x8888ff,
alpha: 0.5
});
self.numberText = new Text2('G', {
size: 40,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 7;
self.radius = 40;
self.phaseTimer = 0;
self.isPhased = false;
self.isGhost = true;
self.takeDamage = function () {
if (self.isPhased) return false;
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
return false;
};
self.update = function () {
self.phaseTimer += 0.1;
self.isPhased = Math.sin(self.phaseTimer) > 0;
ballGraphics.alpha = self.isPhased ? 0.2 : 0.8;
self.numberText.alpha = self.isPhased ? 0.2 : 1;
};
return self;
});
var GiantBallPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ff00,
scaleX: 1.5,
scaleY: 1.5
});
self.radius = 35;
self.bounceTimer = 0;
self.update = function () {
self.bounceTimer += 0.1;
var scale = 1.5 + Math.sin(self.bounceTimer) * 0.3;
powerupGraphics.scale.set(scale);
};
return self;
});
// HeartBall: Ball with heart icon, gives +10 HP when collected
var HeartBall = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff3366,
scaleX: 1.1,
scaleY: 1.1
});
self.radius = 28;
self.heartText = new Text2('♥', {
size: 38,
fill: 0xffffff
});
self.heartText.anchor.set(0.5, 0.5);
self.addChild(self.heartText);
self.update = function () {
heartGraphics.rotation += 0.04;
self.heartText.scale.set(1 + Math.sin(LK.ticks * 0.15) * 0.1);
};
return self;
});
var LaserPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ffff
});
self.radius = 25;
self.glowTimer = 0;
self.update = function () {
self.glowTimer += 0.2;
powerupGraphics.alpha = 0.5 + Math.sin(self.glowTimer) * 0.5;
};
return self;
});
var LightningPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x9966ff
});
self.radius = 25;
self.sparkTimer = 0;
self.update = function () {
self.sparkTimer += 0.3;
powerupGraphics.alpha = 0.4 + Math.random() * 0.6;
powerupGraphics.scale.set(1 + Math.sin(self.sparkTimer) * 0.3);
};
return self;
});
var MagnetBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x0066cc,
scaleX: 1.3,
scaleY: 1.3
});
self.numberText = new Text2('MAG', {
size: 35,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 20;
self.radius = 50;
self.magnetRadius = 200;
self.isMagnet = true;
self.magnetTimer = 0;
self.takeDamage = function () {
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
// Pulse effect on hit
tween(ballGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100
});
}
});
return false;
};
self.update = function () {
self.magnetTimer += 0.1;
// Magnetic field visual effect
if (Math.random() < 0.2) {
var field = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
tint: 0x0099ff,
alpha: 0.3
});
var angle = Math.random() * Math.PI * 2;
var radius = Math.random() * self.magnetRadius;
field.x = Math.cos(angle) * radius;
field.y = Math.sin(angle) * radius;
tween(field, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0,
x: field.x * 0.5,
y: field.y * 0.5
}, {
duration: 1000,
onFinish: function onFinish() {
field.destroy();
}
});
}
ballGraphics.rotation = self.magnetTimer * 0.5;
};
return self;
});
var MirrorBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xc0c0c0,
scaleX: 1.2,
scaleY: 1.2
});
self.numberText = new Text2('M', {
size: 40,
fill: 0x000000
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 15;
self.radius = 45;
self.velocityX = 0;
self.velocityY = 0;
self.isMirror = true;
self.reflectTimer = 0;
self.takeDamage = function () {
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
// Flash effect on hit
tween(ballGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
tint: 0xc0c0c0
}, {
duration: 100
});
}
});
return false;
};
self.update = function () {
self.reflectTimer += 0.1;
ballGraphics.alpha = 0.7 + Math.sin(self.reflectTimer * 2) * 0.3;
// Shine effect
if (Math.random() < 0.05) {
var shine = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xffffff,
alpha: 0.8
});
shine.x = (Math.random() - 0.5) * 40;
shine.y = (Math.random() - 0.5) * 40;
tween(shine, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
onFinish: function onFinish() {
shine.destroy();
}
});
}
};
return self;
});
var MultiballPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xe74c3c
});
self.radius = 25;
self.rotationSpeed = 0.05;
self.update = function () {
powerupGraphics.rotation += self.rotationSpeed;
var scale = 1 + Math.sin(LK.ticks * 0.1) * 0.3;
powerupGraphics.scale.set(scale);
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 30;
self.fadeSpeed = 0.03;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += 0.075; // gravity
self.lifetime--;
self.alpha -= self.fadeSpeed;
if (self.lifetime <= 0 || self.alpha <= 0) {
return true; // destroy
}
return false;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 20;
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 15;
self.radius = 10;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Apply gravity (0.75% per frame)
self.velocityY += 0.075;
if (self.x <= self.radius || self.x >= 2048 - self.radius) {
self.velocityX *= -1;
self.x = Math.max(self.radius, Math.min(2048 - self.radius, self.x));
}
if (self.y <= self.radius) {
self.velocityY *= -1;
self.y = self.radius;
}
};
return self;
});
var RainbowBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.numberText = new Text2('★', {
size: 50,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.hits = 10;
self.radius = 60;
self.velocityX = 0;
self.velocityY = 0;
self.colorTimer = 0;
self.isRainbow = true;
self.takeDamage = function () {
self.hits--;
if (self.hits <= 0) {
return true;
}
self.numberText.setText(self.hits.toString());
return false;
};
self.update = function () {
self.colorTimer += 0.1;
var hue = (Math.sin(self.colorTimer) + 1) * 0.5;
var r = Math.floor(Math.sin(hue * Math.PI * 2) * 127 + 128);
var g = Math.floor(Math.sin((hue + 0.33) * Math.PI * 2) * 127 + 128);
var b = Math.floor(Math.sin((hue + 0.67) * Math.PI * 2) * 127 + 128);
ballGraphics.tint = r << 16 | g << 8 | b;
ballGraphics.rotation += 0.05;
};
return self;
});
var ShieldPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x3498db
});
self.radius = 25;
self.shieldTimer = 0;
self.update = function () {
self.shieldTimer += 0.1;
var scale = 1 + Math.sin(self.shieldTimer * 2) * 0.2;
powerupGraphics.scale.set(scale);
powerupGraphics.rotation += 0.05;
};
return self;
});
var SlowMotionPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x9b59b6
});
self.radius = 30;
self.pulseTimer = 0;
self.update = function () {
self.pulseTimer += 0.1;
var scale = 1 + Math.sin(self.pulseTimer) * 0.2;
powerupGraphics.scale.set(scale);
};
return self;
});
var SpecialProjectile = Container.expand(function () {
var self = Container.call(this);
self.type = 'normal';
self.velocityX = 0;
self.velocityY = 0;
self.speed = 15;
self.radius = 10;
self.piercing = 0;
self.bounces = 999;
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.setType = function (type) {
self.type = type;
switch (type) {
case 'piercing':
projectileGraphics.tint = 0xff00ff;
self.piercing = 3;
projectileGraphics.scale.set(1.5);
self.radius = 15;
break;
case 'explosive':
projectileGraphics.tint = 0xff4444;
projectileGraphics.scale.set(2);
self.radius = 20;
self.speed = 10;
break;
case 'rapid':
projectileGraphics.tint = 0x44ff44;
projectileGraphics.scale.set(0.7);
self.radius = 7;
self.speed = 25;
break;
case 'fireball':
projectileGraphics.tint = 0xff6600;
projectileGraphics.scale.set(1.8);
self.radius = 18;
self.speed = 12;
self.piercing = 999;
break;
case 'giant':
projectileGraphics.tint = 0x00ff00;
projectileGraphics.scale.set(3);
self.radius = 30;
self.speed = 8;
break;
case 'split':
projectileGraphics.tint = 0xff00ff;
projectileGraphics.scale.set(1.2);
self.radius = 12;
self.speed = 15;
break;
case 'laser':
projectileGraphics.tint = 0x00ffff;
projectileGraphics.scale.set(0.5);
self.radius = 5;
self.speed = 30;
self.piercing = 999;
break;
case 'lightning':
projectileGraphics.tint = 0x9966ff;
projectileGraphics.scale.set(1.5);
self.radius = 15;
self.speed = 20;
self.piercing = 1;
break;
}
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Apply gravity (0.75% per frame)
if (self.gravity === undefined) self.gravity = 0.075;
self.velocityY += self.gravity;
if (self.x <= self.radius || self.x >= 2048 - self.radius) {
self.velocityX *= -1;
self.x = Math.max(self.radius, Math.min(2048 - self.radius, self.x));
self.bounces--;
}
if (self.y <= self.radius) {
self.velocityY *= -1;
self.y = self.radius;
self.bounces--;
}
if (self.type === 'rapid') {
// Add trail effect
if (Math.random() < 0.3) {
var trail = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.5,
tint: 0x44ff44
});
tween(trail, {
alpha: 0,
scaleX: 0,
scaleY: 0
}, {
duration: 300,
onFinish: function onFinish() {
trail.destroy();
}
});
}
} else if (self.type === 'fireball') {
// Add flame trail
if (Math.random() < 0.5) {
var flame = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
alpha: 0.8,
tint: Math.random() > 0.5 ? 0xff6600 : 0xffaa00
});
tween(flame, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 200,
onFinish: function onFinish() {
flame.destroy();
}
});
}
} else if (self.type === 'laser') {
// Add laser glow
projectileGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.3) * 0.2;
}
return self.bounces <= 0;
};
return self;
});
var SplitBallPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff00ff
});
self.radius = 25;
self.rotationSpeed = 0.1;
self.update = function () {
powerupGraphics.rotation += self.rotationSpeed;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 25;
starGraphics.rotation = Math.PI / 4;
self.update = function () {
starGraphics.rotation += 0.02;
};
return self;
});
var TeleportPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x8000ff,
scaleX: 1.2,
scaleY: 1.2
});
self.radius = 30;
self.teleportTimer = 0;
self.update = function () {
self.teleportTimer += 0.3;
powerupGraphics.alpha = 0.3 + Math.abs(Math.sin(self.teleportTimer)) * 0.7;
// Portal effect
if (powerupGraphics.alpha < 0.4) {
powerupGraphics.x = (Math.random() - 0.5) * 10;
powerupGraphics.y = (Math.random() - 0.5) * 10;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
var cannon;
var aimLine;
var balls = [];
var projectiles = [];
var powerups = [];
var stars = [];
var isAiming = false;
var canShoot = true;
var projectileCount = 1;
var stage = 1;
var ballsPerRow = 6;
var ballSpeed = 0.5;
var gameActive = true;
// HP system
var maxHP = 20;
var hp = maxHP;
var hpText = new Text2('HP: ' + hp, {
size: 50,
fill: 0xff4444
});
hpText.anchor.set(0, 0);
hpText.x = 20 + 2 * 80;
hpText.y = 20;
LK.gui.topLeft.addChild(hpText);
// Remaining balls count text (above stage text)
var ballsLeftText = new Text2('Balls Left: 0', {
size: 28,
fill: 0xCCCCCC
});
ballsLeftText.anchor.set(0.5, 0);
ballsLeftText.y = 0;
LK.gui.top.addChild(ballsLeftText);
var stageText = new Text2('Stage 1', {
size: 60,
fill: 0xFFFFFF
});
stageText.anchor.set(0.5, 0);
stageText.y = 20;
LK.gui.top.addChild(stageText);
var projectileCountText = new Text2('x1', {
size: 50,
fill: 0x4ECDC4
});
projectileCountText.anchor.set(0.5, 0);
projectileCountText.y = 100;
LK.gui.top.addChild(projectileCountText);
var scoreText = new Text2('Score: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -20;
scoreText.y = 20;
LK.gui.topRight.addChild(scoreText);
var combo = 0;
var comboTimer = 0;
var scoreMultiplier = 1;
var comboText = new Text2('', {
size: 30,
fill: 0xFFD700
});
comboText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(comboText);
var particles = [];
var currentWeapon = 'normal';
var weaponUnlocks = {
piercing: false,
explosive: false,
rapid: false
};
var slowMotionActive = false;
var slowMotionTimer = 0;
var gameSpeed = 1;
var magnetActive = false;
var magnetTimer = 0;
var specialEffects = [];
var chainReactionActive = false;
var lastBallDestroyed = null;
var consecutiveHits = 0;
var slowMotionPowerups = [];
var multiballPowerups = [];
var multiballActive = false;
var fireballPowerups = [];
var giantBallPowerups = [];
var splitBallPowerups = [];
var laserPowerups = [];
var fireballActive = false;
var giantBallActive = false;
var splitBallActive = false;
var laserActive = false;
var shieldPowerups = [];
var shieldActive = false;
var shieldTimer = 0;
var bossBalls = [];
var bossSpawnCounter = 0;
var freezeActive = false;
var freezeTimer = 0;
var criticalHitChance = 0.1;
var magnetBalls = [];
var perfectStageBonus = false;
var rainbowBalls = [];
var bombBalls = [];
var doubleShotPowerups = [];
var doubleShotActive = false;
var doubleShotTimer = 0;
var lightningPowerups = [];
var lightningActive = false;
var ghostBalls = [];
var reverseGravityActive = false;
var reverseGravityTimer = 0;
var scoreBoostActive = false;
var scoreBoostTimer = 0;
var scoreBoostMultiplier = 1;
var autoAimActive = false;
var autoAimTimer = 0;
var freezeBombPowerups = [];
var freezeBombActive = false;
var mirrorBalls = [];
var chainReactionPowerups = [];
var chainReactionBombActive = false;
var teleportPowerups = [];
var teleportActive = false;
var ballsDestroyed = 0;
var perfectHits = 0;
var missedShots = 0;
var powerupsCollected = 0;
var maxCombo = 0;
var timePlayed = 0;
var achievements = {
// Basic achievements
firstWin: false,
combo10: false,
score1000: false,
allWeapons: false,
bossKiller: false,
perfectStage: false,
shieldMaster: false,
lightningMaster: false,
ghostHunter: false,
reverseGravity: false,
// New achievements
stage10: false,
stage25: false,
stage50: false,
score5000: false,
score10000: false,
score50000: false,
combo20: false,
combo50: false,
multiKill5: false,
multiKill10: false,
projectiles50: false,
projectiles100: false,
fireballKills: false,
laserKills: false,
explosiveKills: false,
piercingKills: false,
rapidKills: false,
splitKills: false,
giantKills: false,
lightningChain: false,
bombExpert: false,
rainbowHunter: false,
starCollector: false,
powerupMaster: false,
dodgeMaster: false,
speedDemon: false,
slowMotionPro: false,
magnetMaster: false,
freezeMaster: false,
doubleTrouble: false,
tripleCombo: false,
chainReactionPro: false,
perfectAccuracy: false,
luckyShot: false,
survivor: false,
pacifist: false,
aggressive: false,
versatile: false,
persistent: false,
flawless: false,
comeback: false,
closeCall: false,
longShot: false,
richPlayer: false,
masterOfAll: false
};
var achievementDescriptions = {
firstWin: "Clear your first stage",
combo10: "Achieve a 10x combo",
score1000: "Score 1,000 points",
allWeapons: "Unlock all basic weapons",
bossKiller: "Defeat a boss",
perfectStage: "Clear a stage with only 1 projectile",
shieldMaster: "Use a shield power-up",
lightningMaster: "Use lightning power-up",
ghostHunter: "Defeat a ghost ball",
reverseGravity: "Use reverse gravity",
stage10: "Reach stage 10",
stage25: "Reach stage 25",
stage50: "Reach stage 50",
score5000: "Score 5,000 points",
score10000: "Score 10,000 points",
score50000: "Score 50,000 points",
combo20: "Achieve a 20x combo",
combo50: "Achieve a 50x combo",
multiKill5: "Destroy 5 balls with one shot",
multiKill10: "Destroy 10 balls with one shot",
projectiles50: "Collect 50 projectiles total",
projectiles100: "Collect 100 projectiles total",
fireballKills: "Destroy 100 balls with fireball",
laserKills: "Destroy 100 balls with laser",
explosiveKills: "Destroy 100 balls with explosive",
piercingKills: "Destroy 100 balls with piercing",
rapidKills: "Destroy 100 balls with rapid fire",
splitKills: "Destroy 100 balls with split shot",
giantKills: "Destroy 100 balls with giant ball",
lightningChain: "Chain lightning to 5 balls",
bombExpert: "Trigger 10 bomb explosions",
rainbowHunter: "Destroy 20 rainbow balls",
starCollector: "Collect 50 stars",
powerupMaster: "Use 100 power-ups",
dodgeMaster: "Survive with balls at bottom 10 times",
speedDemon: "Clear a stage in under 30 seconds",
slowMotionPro: "Use slow motion 20 times",
magnetMaster: "Use magnet 20 times",
freezeMaster: "Use freeze 20 times",
doubleTrouble: "Use double shot 20 times",
tripleCombo: "Get 3 different power-ups active",
chainReactionPro: "Trigger 50 chain reactions",
perfectAccuracy: "Hit 100 balls without missing",
luckyShot: "Hit a ball from max distance",
survivor: "Survive for 10 minutes",
pacifist: "Clear a stage without power-ups",
aggressive: "Clear a stage in under 10 shots",
versatile: "Use all weapon types in one game",
persistent: "Play 100 games",
flawless: "Clear 5 stages without taking damage",
comeback: "Win with 1 projectile left",
closeCall: "Survive with shield save 5 times",
longShot: "Hit a ball from bottom to top",
richPlayer: "Have 10+ projectiles at once",
masterOfAll: "Unlock all 50 achievements"
};
var achievementProgress = {
fireballKills: 0,
laserKills: 0,
explosiveKills: 0,
piercingKills: 0,
rapidKills: 0,
splitKills: 0,
giantKills: 0,
bombExpert: 0,
rainbowHunter: 0,
starCollector: 0,
powerupMaster: 0,
dodgeMaster: 0,
slowMotionPro: 0,
magnetMaster: 0,
freezeMaster: 0,
doubleTrouble: 0,
chainReactionPro: 0,
perfectAccuracy: 0,
persistent: 0,
flawless: 0,
closeCall: 0
};
// Load saved data
var savedData = storage['99balls_save'] || {};
if (savedData.highScore) {
var highScoreText = new Text2('Best: ' + savedData.highScore, {
size: 30,
fill: 0xFFD700
});
highScoreText.anchor.set(1, 0);
highScoreText.x = -20;
highScoreText.y = 70;
LK.gui.topRight.addChild(highScoreText);
}
// Load achievements from flattened structure
for (var key in achievements) {
if (savedData[key] !== undefined) {
achievements[key] = savedData[key];
}
}
// Load achievement progress
for (var key in achievementProgress) {
if (savedData[key + 'Progress'] !== undefined) {
achievementProgress[key] = savedData[key + 'Progress'];
}
}
var weaponText = new Text2('Normal', {
size: 40,
fill: 0xFFFFFF
});
weaponText.anchor.set(0.5, 1);
weaponText.y = -20;
LK.gui.bottom.addChild(weaponText);
var slowMotionOverlay = new Container();
var slowMotionBg = slowMotionOverlay.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 50,
scaleY: 50,
alpha: 0,
tint: 0x9b59b6
});
LK.gui.center.addChild(slowMotionOverlay);
var powerUpIndicator = new Text2('', {
size: 50,
fill: 0xFFFFFF
});
powerUpIndicator.anchor.set(0, 0);
powerUpIndicator.x = 20;
powerUpIndicator.y = 200;
LK.gui.topLeft.addChild(powerUpIndicator);
var doubleShotIndicator = new Text2('', {
size: 40,
fill: 0xffff00
});
doubleShotIndicator.anchor.set(0, 0);
doubleShotIndicator.x = 20;
doubleShotIndicator.y = 260;
LK.gui.topLeft.addChild(doubleShotIndicator);
var shieldIndicator = new Container();
var shieldBg = shieldIndicator.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3,
alpha: 0,
tint: 0x3498db
});
game.addChild(shieldIndicator);
function initializeLevel() {
// Reset game state
gameActive = true;
canShoot = true;
isAiming = false;
cannon = game.addChild(new Cannon());
cannon.x = 1024;
cannon.y = 2600;
aimLine = game.addChild(new AimLine());
aimLine.x = cannon.x;
aimLine.y = cannon.y;
aimLine.visible = false;
spawnBallRow();
}
function spawnBallRow() {
var spacing = 2048 / (ballsPerRow + 1);
for (var i = 0; i < ballsPerRow; i++) {
if (Math.random() < 0.8) {
var ball = new Ball();
ball.x = spacing * (i + 1);
ball.y = -50;
ball.setNumber(Math.floor(Math.random() * stage * 5) + stage);
balls.push(ball);
game.addChild(ball);
if (Math.random() < 0.15) {
var powerup = new PowerUp();
powerup.x = ball.x;
powerup.y = ball.y;
powerups.push(powerup);
game.addChild(powerup);
} else if (Math.random() < 0.07) {
// 7% chance for heart ball
var heartBall = new HeartBall();
heartBall.x = ball.x;
heartBall.y = ball.y;
stars.push(heartBall); // Use stars array for easy y-movement and removal
game.addChild(heartBall);
} else if (Math.random() < 0.1) {
var star = new Star();
star.x = ball.x;
star.y = ball.y;
stars.push(star);
game.addChild(star);
} else if (Math.random() < 0.05 && stage > 2) {
var slowPowerup = new SlowMotionPowerUp();
slowPowerup.x = ball.x;
slowPowerup.y = ball.y;
slowMotionPowerups.push(slowPowerup);
game.addChild(slowPowerup);
} else if (Math.random() < 0.04 && stage > 3) {
var multiballPowerup = new MultiballPowerUp();
multiballPowerup.x = ball.x;
multiballPowerup.y = ball.y;
multiballPowerups.push(multiballPowerup);
game.addChild(multiballPowerup);
} else if (Math.random() < 0.04 && stage > 1) {
var fireballPowerup = new FireBallPowerUp();
fireballPowerup.x = ball.x;
fireballPowerup.y = ball.y;
fireballPowerups.push(fireballPowerup);
game.addChild(fireballPowerup);
} else if (Math.random() < 0.03 && stage > 2) {
var giantBallPowerup = new GiantBallPowerUp();
giantBallPowerup.x = ball.x;
giantBallPowerup.y = ball.y;
giantBallPowerups.push(giantBallPowerup);
game.addChild(giantBallPowerup);
} else if (Math.random() < 0.03 && stage > 4) {
var splitBallPowerup = new SplitBallPowerUp();
splitBallPowerup.x = ball.x;
splitBallPowerup.y = ball.y;
splitBallPowerups.push(splitBallPowerup);
game.addChild(splitBallPowerup);
} else if (Math.random() < 0.02 && stage > 5) {
var laserPowerup = new LaserPowerUp();
laserPowerup.x = ball.x;
laserPowerup.y = ball.y;
laserPowerups.push(laserPowerup);
game.addChild(laserPowerup);
} else if (Math.random() < 0.03 && stage > 3) {
var shieldPowerup = new ShieldPowerUp();
shieldPowerup.x = ball.x;
shieldPowerup.y = ball.y;
shieldPowerups.push(shieldPowerup);
game.addChild(shieldPowerup);
} else if (Math.random() < 0.04 && stage > 2) {
var doubleShotPowerup = new DoubleShotPowerUp();
doubleShotPowerup.x = ball.x;
doubleShotPowerup.y = ball.y;
doubleShotPowerups.push(doubleShotPowerup);
game.addChild(doubleShotPowerup);
} else if (Math.random() < 0.03 && stage > 4) {
var lightningPowerup = new LightningPowerUp();
lightningPowerup.x = ball.x;
lightningPowerup.y = ball.y;
lightningPowerups.push(lightningPowerup);
game.addChild(lightningPowerup);
}
} else if (Math.random() < 0.05 && stage > 3) {
// Spawn rainbow ball
var rainbowBall = new RainbowBall();
rainbowBall.x = ball.x;
rainbowBall.y = ball.y;
rainbowBalls.push(rainbowBall);
game.addChild(rainbowBall);
} else if (Math.random() < 0.04 && stage > 4) {
// Spawn bomb ball
var bombBall = new BombBall();
bombBall.x = ball.x;
bombBall.y = ball.y;
bombBalls.push(bombBall);
game.addChild(bombBall);
} else if (Math.random() < 0.03 && stage > 5) {
// Spawn ghost ball
var ghostBall = new GhostBall();
ghostBall.x = ball.x;
ghostBall.y = ball.y;
ghostBalls.push(ghostBall);
game.addChild(ghostBall);
} else if (Math.random() < 0.02 && stage > 6) {
// Spawn mirror ball
var mirrorBall = new MirrorBall();
mirrorBall.x = ball.x;
mirrorBall.y = ball.y;
mirrorBalls.push(mirrorBall);
game.addChild(mirrorBall);
} else if (Math.random() < 0.03 && stage > 4) {
// Spawn freeze bomb power-up
var freezeBombPowerup = new FreezeBombPowerUp();
freezeBombPowerup.x = ball.x;
freezeBombPowerup.y = ball.y;
freezeBombPowerups.push(freezeBombPowerup);
game.addChild(freezeBombPowerup);
} else if (Math.random() < 0.02 && stage > 5) {
// Spawn chain reaction power-up
var chainReactionPowerup = new ChainReactionPowerUp();
chainReactionPowerup.x = ball.x;
chainReactionPowerup.y = ball.y;
chainReactionPowerups.push(chainReactionPowerup);
game.addChild(chainReactionPowerup);
} else if (Math.random() < 0.02 && stage > 7) {
// Spawn teleport power-up
var teleportPowerup = new TeleportPowerUp();
teleportPowerup.x = ball.x;
teleportPowerup.y = ball.y;
teleportPowerups.push(teleportPowerup);
game.addChild(teleportPowerup);
} else if (Math.random() < 0.03 && stage > 6) {
// Spawn magnet ball
var magnetBall = new MagnetBall();
magnetBall.x = ball.x;
magnetBall.y = ball.y;
magnetBalls.push(magnetBall);
game.addChild(magnetBall);
}
}
// Spawn boss every 5 stages
bossSpawnCounter++;
if (stage > 0 && stage % 5 === 0 && bossSpawnCounter === 1) {
var boss = new BossBall();
boss.x = 1024;
boss.y = 200;
bossBalls.push(boss);
game.addChild(boss);
var bossWarning = new Text2('BOSS INCOMING!', {
size: 100,
fill: 0xff1744
});
bossWarning.anchor.set(0.5, 0.5);
bossWarning.alpha = 0;
LK.gui.center.addChild(bossWarning);
tween(bossWarning, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
onFinish: function onFinish() {
tween(bossWarning, {
alpha: 0
}, {
duration: 500,
delay: 1000,
onFinish: function onFinish() {
bossWarning.destroy();
}
});
}
});
} else if (stage % 5 !== 0) {
bossSpawnCounter = 0;
}
}
function fireProjectiles(angle) {
var shotCount = projectileCount;
var delay = 100;
var weaponType = currentWeapon;
if (currentWeapon === 'rapid') {
shotCount = Math.min(projectileCount * 3, 15);
delay = 30;
}
// Double shot modifier
if (doubleShotActive) {
shotCount *= 2;
}
// Check for active power-ups
if (fireballActive) {
weaponType = 'fireball';
fireballActive = false;
} else if (giantBallActive) {
weaponType = 'giant';
giantBallActive = false;
} else if (splitBallActive) {
weaponType = 'split';
splitBallActive = false;
} else if (laserActive) {
weaponType = 'laser';
laserActive = false;
shotCount = 1;
} else if (lightningActive) {
weaponType = 'lightning';
lightningActive = false;
}
// Add cannon fire effect
var muzzleFlash = cannon.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
y: -40,
scaleX: 0.5,
scaleY: 0.5,
alpha: 0.8,
tint: weaponType === 'fireball' ? 0xff6600 : weaponType === 'laser' ? 0x00ffff : 0xffffff
});
// Special combo effects for weapon combinations
var activeEffects = 0;
if (fireballActive) activeEffects++;
if (giantBallActive) activeEffects++;
if (splitBallActive) activeEffects++;
if (laserActive) activeEffects++;
if (lightningActive) activeEffects++;
if (multiballActive) activeEffects++;
if (doubleShotActive) activeEffects++;
if (activeEffects >= 3) {
// Triple combo effect
var comboFlash = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: cannon.x,
y: cannon.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8,
tint: 0xff00ff
});
tween(comboFlash, {
scaleX: 10,
scaleY: 10,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
onFinish: function onFinish() {
comboFlash.destroy();
}
});
checkAchievement('tripleCombo');
}
tween(muzzleFlash, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
muzzleFlash.destroy();
}
});
if (multiballActive) {
// Fire in multiple directions
var angles = [-0.3, -0.15, 0, 0.15, 0.3];
for (var a = 0; a < angles.length; a++) {
(function (angleOffset) {
LK.setTimeout(function () {
var projectile = new SpecialProjectile();
projectile.x = cannon.x;
projectile.y = cannon.y - 40;
projectile.setType(weaponType);
projectile.velocityX = Math.cos(angle + angleOffset) * projectile.speed;
projectile.velocityY = Math.sin(angle + angleOffset) * projectile.speed;
projectiles.push(projectile);
game.addChild(projectile);
}, a * 50);
})(angles[a]);
}
multiballActive = false;
return;
}
for (var i = 0; i < shotCount; i++) {
LK.setTimeout(function () {
var projectile = new SpecialProjectile();
projectile.x = cannon.x;
projectile.y = cannon.y - 40;
projectile.setType(weaponType);
if (weaponType === 'rapid') {
var spread = (Math.random() - 0.5) * 0.2;
projectile.velocityX = Math.cos(angle + spread) * projectile.speed;
projectile.velocityY = Math.sin(angle + spread) * projectile.speed;
} else if (weaponType === 'laser') {
// Laser goes straight up
projectile.velocityX = 0;
projectile.velocityY = -projectile.speed;
} else {
projectile.velocityX = Math.cos(angle) * projectile.speed;
projectile.velocityY = Math.sin(angle) * projectile.speed;
}
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('shoot').play();
}, i * delay);
}
}
function checkCollision(obj1, obj2, radius1, radius2) {
var dx = obj1.x - obj2.x;
var dy = obj1.y - obj2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
return distance < radius1 + radius2;
}
function createExplosion(x, y, color, count) {
for (var i = 0; i < count; i++) {
var particle = new Particle();
particle.x = x;
particle.y = y;
var angle = Math.random() * Math.PI * 2;
var speed = Math.random() * 10 + 5;
particle.velocityX = Math.cos(angle) * speed;
particle.velocityY = Math.sin(angle) * speed;
particle.tint = color;
particles.push(particle);
game.addChild(particle);
}
// Create shockwave effect for chain reactions
if (chainReactionActive && count > 15) {
var shockwave = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 0.02,
scaleY: 0.02,
alpha: 0.8,
tint: color
});
tween(shockwave, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
shockwave.destroy();
}
});
}
}
function updateAchievementDisplay() {
// Clear existing achievement displays
for (var i = achievementPanel.children.length - 1; i >= 0; i--) {
var child = achievementPanel.children[i];
if (child !== panelBg && child !== achievementTitle && child !== closeButton) {
child.destroy();
}
}
var unlocked = 0;
var total = 0;
var yOffset = -500;
var xOffset = -400;
var row = 0;
var col = 0;
for (var key in achievements) {
total++;
if (achievements[key]) unlocked++;
var achContainer = new Container();
var achBg = achContainer.attachAsset('achievementItemBg', {
anchorX: 0.5,
anchorY: 0.5,
tint: achievements[key] ? 0x27ae60 : 0x7f8c8d,
alpha: 0.9
});
var achText = new Text2(key.replace(/([A-Z])/g, ' $1').trim(), {
size: 20,
fill: achievements[key] ? 0xFFFFFF : 0x95a5a6
});
achText.anchor.set(0.5, 0.5);
achText.y = -10;
achContainer.addChild(achText);
var achDesc = new Text2(achievementDescriptions[key] || '', {
size: 15,
fill: achievements[key] ? 0xecf0f1 : 0x7f8c8d
});
achDesc.anchor.set(0.5, 0.5);
achDesc.y = 10;
achContainer.addChild(achDesc);
achContainer.x = xOffset + col * 250;
achContainer.y = yOffset + row * 60;
achievementPanel.addChild(achContainer);
col++;
if (col > 3) {
col = 0;
row++;
}
}
var progressText = new Text2('Progress: ' + unlocked + '/' + total, {
size: 40,
fill: 0xFFD700
});
progressText.anchor.set(0.5, 0.5);
progressText.y = 600;
achievementPanel.addChild(progressText);
}
function checkAchievement(key) {
if (!achievements[key]) {
achievements[key] = true;
showAchievement(achievementDescriptions[key] || key, 0xFFD700);
saveAchievements();
// Check master achievement
var allUnlocked = true;
for (var k in achievements) {
if (k !== 'masterOfAll' && !achievements[k]) {
allUnlocked = false;
break;
}
}
if (allUnlocked && !achievements.masterOfAll) {
achievements.masterOfAll = true;
showAchievement("MASTER OF ALL ACHIEVEMENTS!", 0xFF00FF);
}
}
}
function saveAchievements() {
savedData.highScore = savedData.highScore || 0;
for (var key in achievements) {
savedData[key] = achievements[key];
}
for (var key in achievementProgress) {
savedData[key + 'Progress'] = achievementProgress[key];
}
storage['99balls_save'] = savedData;
}
function showAchievement(text, color) {
var achievementText = new Text2('Achievement: ' + text, {
size: 60,
fill: color
});
achievementText.anchor.set(0.5, 0.5);
achievementText.y = 200;
achievementText.alpha = 0;
LK.gui.center.addChild(achievementText);
tween(achievementText, {
alpha: 1,
y: 100
}, {
duration: 500,
onFinish: function onFinish() {
tween(achievementText, {
alpha: 0
}, {
duration: 1000,
delay: 2000,
onFinish: function onFinish() {
achievementText.destroy();
}
});
}
});
}
function updateCombo() {
combo++;
comboTimer = 120; // 2 seconds at 60 FPS
if (combo >= 5) {
scoreMultiplier = Math.min(combo / 5, 5);
comboText.setText('COMBO x' + Math.floor(scoreMultiplier));
comboText.alpha = 1;
// Enhanced visual feedback
var colors = [0xFFD700, 0xFF6347, 0x00CED1, 0xFF1493, 0x32CD32];
comboText.tint = colors[Math.min(Math.floor(scoreMultiplier) - 1, 4)];
tween(comboText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(comboText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Combo milestone effects
if (combo === 10 || combo === 20 || combo === 30 || combo === 50 || combo === 100) {
var message = combo === 100 ? 'LEGENDARY!' : combo === 50 ? 'UNSTOPPABLE!' : 'AMAZING!';
var comboFlash = new Text2(message, {
size: (80 + combo / 10) * 0.5,
fill: combo === 100 ? 0xff00ff : 0xFFD700
});
comboFlash.anchor.set(0.5, 0.5);
comboFlash.y = -100;
comboFlash.alpha = 0;
LK.gui.center.addChild(comboFlash);
tween(comboFlash, {
alpha: 1,
y: -150
}, {
duration: 300,
onFinish: function onFinish() {
tween(comboFlash, {
alpha: 0
}, {
duration: 500,
delay: 200,
onFinish: function onFinish() {
comboFlash.destroy();
}
});
}
});
}
}
}
function moveRow() {
chainReactionActive = false;
consecutiveHits = 0;
spawnBallRow();
}
game.down = function (x, y, obj) {
if (!canShoot || !gameActive) return;
isAiming = true;
aimLine.visible = true;
};
game.move = function (x, y, obj) {
if (!isAiming || !gameActive) return;
var dx = x - cannon.x;
var dy = y - cannon.y;
var angle = Math.atan2(dy, dx);
// Auto aim to nearest ball
if (autoAimActive && balls.length > 0) {
var closestBall = null;
var closestDist = 999999;
for (var i = 0; i < balls.length; i++) {
var ball = balls[i];
var ballDx = ball.x - cannon.x;
var ballDy = ball.y - cannon.y;
var dist = Math.sqrt(ballDx * ballDx + ballDy * ballDy);
if (dist < closestDist && ball.y < cannon.y) {
closestDist = dist;
closestBall = ball;
}
}
if (closestBall) {
dx = closestBall.x - cannon.x;
dy = closestBall.y - cannon.y;
angle = Math.atan2(dy, dx);
}
}
if (angle > -Math.PI && angle < 0) {
cannon.rotation = angle + Math.PI / 2;
aimLine.rotation = angle + Math.PI / 2;
}
};
game.up = function (x, y, obj) {
if (!isAiming || !gameActive) return;
isAiming = false;
aimLine.visible = false;
canShoot = false;
var dx = x - cannon.x;
var dy = y - cannon.y;
var angle = Math.atan2(dy, dx);
if (angle > -Math.PI && angle < 0) {
fireProjectiles(angle);
}
};
game.update = function () {
if (!gameActive) return;
// Update slow motion
if (slowMotionActive) {
slowMotionTimer--;
gameSpeed = 0.3;
if (slowMotionTimer <= 0) {
slowMotionActive = false;
gameSpeed = 1;
tween(slowMotionBg, {
alpha: 0
}, {
duration: 300
});
powerUpIndicator.setText('');
}
} else {
gameSpeed = 1;
}
// Update magnet effect
if (magnetActive) {
magnetTimer--;
if (magnetTimer <= 0) {
magnetActive = false;
}
}
// Update combo timer
if (comboTimer > 0) {
comboTimer--;
if (comboTimer === 0) {
combo = 0;
scoreMultiplier = 1;
consecutiveHits = 0;
tween(comboText, {
alpha: 0
}, {
duration: 300
});
}
} else if (combo > 0) {
// Add dynamic combo multiplier visual
var comboScale = 1 + Math.sin(LK.ticks * 0.2) * 0.1 * Math.min(combo / 10, 1);
comboText.scale.set(comboScale);
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i].update()) {
particles[i].destroy();
particles.splice(i, 1);
}
}
// Update slow motion powerups
for (var i = 0; i < slowMotionPowerups.length; i++) {
slowMotionPowerups[i].update();
}
// Update multiball powerups
for (var i = 0; i < multiballPowerups.length; i++) {
multiballPowerups[i].update();
}
// Update shield
if (shieldActive) {
shieldTimer--;
shieldIndicator.x = cannon.x;
shieldIndicator.y = cannon.y;
shieldBg.alpha = 0.3 + Math.sin(LK.ticks * 0.2) * 0.2;
shieldBg.rotation += 0.05;
if (shieldTimer <= 0) {
shieldActive = false;
tween(shieldBg, {
alpha: 0
}, {
duration: 300
});
powerUpIndicator.setText('');
}
}
// Update freeze
if (freezeActive) {
freezeTimer--;
if (freezeTimer <= 0) {
freezeActive = false;
gameSpeed = 1;
for (var i = 0; i < balls.length; i++) {
balls[i].tint = 0xffffff;
}
}
}
// Update new power-ups
for (var i = 0; i < shieldPowerups.length; i++) {
shieldPowerups[i].update();
}
for (var i = 0; i < fireballPowerups.length; i++) {
fireballPowerups[i].update();
}
for (var i = 0; i < giantBallPowerups.length; i++) {
giantBallPowerups[i].update();
}
for (var i = 0; i < splitBallPowerups.length; i++) {
splitBallPowerups[i].update();
}
for (var i = 0; i < laserPowerups.length; i++) {
laserPowerups[i].update();
}
for (var i = 0; i < doubleShotPowerups.length; i++) {
doubleShotPowerups[i].update();
}
// Update double shot timer
if (doubleShotActive) {
doubleShotTimer--;
if (doubleShotTimer <= 0) {
doubleShotActive = false;
doubleShotIndicator.setText('');
}
}
// Update lightning powerups
for (var i = 0; i < lightningPowerups.length; i++) {
lightningPowerups[i].update();
}
// Update ghost balls
for (var i = 0; i < ghostBalls.length; i++) {
ghostBalls[i].update();
}
// Update reverse gravity
if (reverseGravityActive) {
reverseGravityTimer--;
if (reverseGravityTimer <= 0) {
reverseGravityActive = false;
ballSpeed = Math.abs(ballSpeed);
powerUpIndicator.setText('');
}
}
// Update score boost
if (scoreBoostActive) {
scoreBoostTimer--;
scoreBoostMultiplier = 3;
if (scoreBoostTimer <= 0) {
scoreBoostActive = false;
scoreBoostMultiplier = 1;
powerUpIndicator.setText('');
}
} else {
scoreBoostMultiplier = 1;
}
// Update auto aim
if (autoAimActive) {
autoAimTimer--;
if (autoAimTimer <= 0) {
autoAimActive = false;
powerUpIndicator.setText('');
}
}
// Update freeze bomb powerups
for (var i = 0; i < freezeBombPowerups.length; i++) {
freezeBombPowerups[i].update();
}
// Update mirror balls
for (var i = 0; i < mirrorBalls.length; i++) {
if (mirrorBalls[i].update) {
mirrorBalls[i].update();
}
}
// Update magnet balls
for (var i = 0; i < magnetBalls.length; i++) {
if (magnetBalls[i].update) {
magnetBalls[i].update();
}
}
// Update chain reaction powerups
for (var i = 0; i < chainReactionPowerups.length; i++) {
chainReactionPowerups[i].update();
}
// Update teleport powerups
for (var i = 0; i < teleportPowerups.length; i++) {
teleportPowerups[i].update();
}
// Track time played
timePlayed++;
if (timePlayed % 3600 === 0) {
// Every minute
var minutes = timePlayed / 3600;
if (minutes === 5) checkAchievement('persistent');
}
// Track max combo
if (combo > maxCombo) {
maxCombo = combo;
}
// Update balls left text
ballsLeftText.setText('Balls Left: ' + balls.length);
// Update boss balls
for (var i = 0; i < bossBalls.length; i++) {
if (bossBalls[i].update) {
bossBalls[i].update();
}
bossBalls[i].y += ballSpeed * gameSpeed * 0.5; // Boss moves slower
}
// Update ball falling speed and call update, and destroy if off screen
for (var i = balls.length - 1; i >= 0; i--) {
balls[i].y += ballSpeed * gameSpeed;
if (balls[i].update) {
balls[i].update();
}
if (balls[i].y > 2732 + 100) {
balls[i].destroy();
balls.splice(i, 1);
}
}
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].y += ballSpeed * gameSpeed;
if (powerups[i].y > 2732 + 100) {
powerups[i].destroy();
powerups.splice(i, 1);
}
}
for (var i = stars.length - 1; i >= 0; i--) {
stars[i].y += ballSpeed * gameSpeed;
if (stars[i].update) {
stars[i].update();
}
if (stars[i].y > 2732 + 100) {
stars[i].destroy();
stars.splice(i, 1);
}
}
for (var i = slowMotionPowerups.length - 1; i >= 0; i--) {
slowMotionPowerups[i].y += ballSpeed * gameSpeed;
if (slowMotionPowerups[i].y > 2732 + 100) {
slowMotionPowerups[i].destroy();
slowMotionPowerups.splice(i, 1);
}
}
for (var i = multiballPowerups.length - 1; i >= 0; i--) {
multiballPowerups[i].y += ballSpeed * gameSpeed;
if (multiballPowerups[i].y > 2732 + 100) {
multiballPowerups[i].destroy();
multiballPowerups.splice(i, 1);
}
}
for (var i = fireballPowerups.length - 1; i >= 0; i--) {
fireballPowerups[i].y += ballSpeed * gameSpeed;
if (fireballPowerups[i].y > 2732 + 100) {
fireballPowerups[i].destroy();
fireballPowerups.splice(i, 1);
}
}
for (var i = giantBallPowerups.length - 1; i >= 0; i--) {
giantBallPowerups[i].y += ballSpeed * gameSpeed;
if (giantBallPowerups[i].y > 2732 + 100) {
giantBallPowerups[i].destroy();
giantBallPowerups.splice(i, 1);
}
}
for (var i = splitBallPowerups.length - 1; i >= 0; i--) {
splitBallPowerups[i].y += ballSpeed * gameSpeed;
if (splitBallPowerups[i].y > 2732 + 100) {
splitBallPowerups[i].destroy();
splitBallPowerups.splice(i, 1);
}
}
for (var i = laserPowerups.length - 1; i >= 0; i--) {
laserPowerups[i].y += ballSpeed * gameSpeed;
if (laserPowerups[i].y > 2732 + 100) {
laserPowerups[i].destroy();
laserPowerups.splice(i, 1);
}
}
for (var i = shieldPowerups.length - 1; i >= 0; i--) {
shieldPowerups[i].y += ballSpeed * gameSpeed;
if (shieldPowerups[i].y > 2732 + 100) {
shieldPowerups[i].destroy();
shieldPowerups.splice(i, 1);
}
}
for (var i = doubleShotPowerups.length - 1; i >= 0; i--) {
doubleShotPowerups[i].y += ballSpeed * gameSpeed;
if (doubleShotPowerups[i].y > 2732 + 100) {
doubleShotPowerups[i].destroy();
doubleShotPowerups.splice(i, 1);
}
}
for (var i = lightningPowerups.length - 1; i >= 0; i--) {
lightningPowerups[i].y += ballSpeed * gameSpeed;
if (lightningPowerups[i].y > 2732 + 100) {
lightningPowerups[i].destroy();
lightningPowerups.splice(i, 1);
}
}
for (var i = ghostBalls.length - 1; i >= 0; i--) {
ghostBalls[i].y += ballSpeed * gameSpeed;
if (ghostBalls[i].y > 2732 + 100) {
ghostBalls[i].destroy();
ghostBalls.splice(i, 1);
}
}
for (var i = mirrorBalls.length - 1; i >= 0; i--) {
mirrorBalls[i].y += ballSpeed * gameSpeed;
if (mirrorBalls[i].y > 2732 + 100) {
mirrorBalls[i].destroy();
mirrorBalls.splice(i, 1);
}
}
for (var i = magnetBalls.length - 1; i >= 0; i--) {
magnetBalls[i].y += ballSpeed * gameSpeed;
if (magnetBalls[i].y > 2732 + 100) {
magnetBalls[i].destroy();
magnetBalls.splice(i, 1);
}
}
for (var i = freezeBombPowerups.length - 1; i >= 0; i--) {
freezeBombPowerups[i].y += ballSpeed * gameSpeed;
if (freezeBombPowerups[i].y > 2732 + 100) {
freezeBombPowerups[i].destroy();
freezeBombPowerups.splice(i, 1);
}
}
for (var i = chainReactionPowerups.length - 1; i >= 0; i--) {
chainReactionPowerups[i].y += ballSpeed * gameSpeed;
if (chainReactionPowerups[i].y > 2732 + 100) {
chainReactionPowerups[i].destroy();
chainReactionPowerups.splice(i, 1);
}
}
for (var i = teleportPowerups.length - 1; i >= 0; i--) {
teleportPowerups[i].y += ballSpeed * gameSpeed;
if (teleportPowerups[i].y > 2732 + 100) {
teleportPowerups[i].destroy();
teleportPowerups.splice(i, 1);
}
}
// Update rainbow balls
for (var i = 0; i < rainbowBalls.length; i++) {
rainbowBalls[i].y += ballSpeed * gameSpeed;
if (rainbowBalls[i].update) {
rainbowBalls[i].update();
}
}
// Update bomb balls
for (var i = 0; i < bombBalls.length; i++) {
bombBalls[i].y += ballSpeed * gameSpeed;
if (bombBalls[i].update) {
bombBalls[i].update();
}
}
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
// Defensive: skip if projectile is undefined/null
if (!projectile) {
projectiles.splice(i, 1);
continue;
}
// Apply game speed to projectile movement (but only for update, do not overwrite velocity permanently)
var oldVelX = projectile.velocityX !== undefined ? projectile.velocityX : 0;
var oldVelY = projectile.velocityY !== undefined ? projectile.velocityY : 0;
projectile.x += oldVelX * (gameSpeed - 1);
projectile.y += oldVelY * (gameSpeed - 1);
if (typeof projectile.update === "function" ? projectile.update() : true || projectile.y > 2732 + 50) {
if (typeof projectile.destroy === "function") projectile.destroy();
projectiles.splice(i, 1);
continue;
}
// Apply magnet effect
if (magnetActive) {
var closestBall = null;
var closestDist = 200;
for (var j = 0; j < balls.length; j++) {
var ball = balls[j];
var dx = ball.x - projectile.x;
var dy = ball.y - projectile.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < closestDist) {
closestDist = dist;
closestBall = ball;
}
}
if (closestBall) {
var dx = closestBall.x - projectile.x;
var dy = closestBall.y - projectile.y;
var dist = Math.sqrt(dx * dx + dy * dy);
projectile.velocityX += dx / dist * 2;
projectile.velocityY += dy / dist * 2;
var speed = Math.sqrt(projectile.velocityX * projectile.velocityX + projectile.velocityY * projectile.velocityY);
if (speed > projectile.speed * 1.5) {
projectile.velocityX = projectile.velocityX / speed * projectile.speed * 1.5;
projectile.velocityY = projectile.velocityY / speed * projectile.speed * 1.5;
}
}
}
// Apply magnet ball attraction
for (var m = 0; m < magnetBalls.length; m++) {
var magnetBall = magnetBalls[m];
var dx = magnetBall.x - projectile.x;
var dy = magnetBall.y - projectile.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < magnetBall.magnetRadius && dist > magnetBall.radius) {
// Attract projectile
var force = (1 - dist / magnetBall.magnetRadius) * 3;
projectile.velocityX += dx / dist * force;
projectile.velocityY += dy / dist * force;
// Normalize speed
var speed = Math.sqrt(projectile.velocityX * projectile.velocityX + projectile.velocityY * projectile.velocityY);
if (speed > projectile.speed * 2) {
projectile.velocityX = projectile.velocityX / speed * projectile.speed * 2;
projectile.velocityY = projectile.velocityY / speed * projectile.speed * 2;
}
}
}
var hitBall = false;
// Check boss collisions first
for (var j = bossBalls.length - 1; j >= 0; j--) {
var boss = bossBalls[j];
if (checkCollision(projectile, boss, projectile.radius, boss.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
// Critical hit chance
var isCritical = Math.random() < criticalHitChance;
var damage = isCritical ? 5 : 1;
if (isCritical) {
var critText = new Text2('CRITICAL!', {
size: 60,
fill: 0xffff00
});
critText.anchor.set(0.5, 0.5);
critText.x = boss.x;
critText.y = boss.y - 100;
game.addChild(critText);
tween(critText, {
y: boss.y - 150,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
critText.destroy();
}
});
// Add critical hit effect
var critEffect = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: boss.x,
y: boss.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8,
tint: 0xffff00
});
tween(critEffect, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
critEffect.destroy();
}
});
}
for (var d = 0; d < damage; d++) {
if (boss.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + 500);
createExplosion(boss.x, boss.y, 0xff1744, 50);
boss.destroy();
bossBalls.splice(j, 1);
// Boss killed achievement
if (!achievements.bossKiller) {
achievements.bossKiller = true;
showAchievement('Boss Slayer!', 0xff1744);
}
break;
}
}
// Handle projectile after boss hit
if (projectile.type !== 'piercing' && projectile.type !== 'fireball' && projectile.type !== 'laser') {
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
}
}
}
// Check rainbow ball collisions
for (var j = rainbowBalls.length - 1; j >= 0; j--) {
var rainbowBall = rainbowBalls[j];
if (checkCollision(projectile, rainbowBall, projectile.radius, rainbowBall.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
// Rainbow balls give bonus points
var bonus = 50 * scoreMultiplier;
if (rainbowBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + bonus * 5);
createExplosion(rainbowBall.x, rainbowBall.y, 0xffffff, 40);
achievementProgress.rainbowHunter++;
if (achievementProgress.rainbowHunter >= 20) checkAchievement('rainbowHunter');
// Create rainbow particle effect
for (var p = 0; p < 20; p++) {
var particle = new Particle();
particle.x = rainbowBall.x;
particle.y = rainbowBall.y;
var angle = p / 20 * Math.PI * 2;
particle.velocityX = Math.cos(angle) * 8;
particle.velocityY = Math.sin(angle) * 8;
particle.tint = Math.random() * 0xffffff | 0;
particles.push(particle);
game.addChild(particle);
}
rainbowBall.destroy();
rainbowBalls.splice(j, 1);
}
// Projectile continues through rainbow balls
}
}
// Check ghost ball collisions
for (var j = ghostBalls.length - 1; j >= 0; j--) {
var ghostBall = ghostBalls[j];
if (!ghostBall.isPhased && checkCollision(projectile, ghostBall, projectile.radius, ghostBall.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
if (ghostBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + 100 * scoreMultiplier * scoreBoostMultiplier);
createExplosion(ghostBall.x, ghostBall.y, 0x8888ff, 30);
ghostBall.destroy();
ghostBalls.splice(j, 1);
ballsDestroyed++;
if (!achievements.ghostHunter) {
achievements.ghostHunter = true;
showAchievement('Ghost Hunter!', 0x8888ff);
}
}
}
}
// Check magnet ball collisions
for (var j = magnetBalls.length - 1; j >= 0; j--) {
var magnetBall = magnetBalls[j];
if (checkCollision(projectile, magnetBall, projectile.radius, magnetBall.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
if (magnetBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + 200 * scoreMultiplier * scoreBoostMultiplier);
createExplosion(magnetBall.x, magnetBall.y, 0x0066cc, 45);
// Create magnetic shockwave
var shockwave = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: magnetBall.x,
y: magnetBall.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.6,
tint: 0x0099ff
});
tween(shockwave, {
scaleX: 8,
scaleY: 8,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
shockwave.destroy();
}
});
magnetBall.destroy();
magnetBalls.splice(j, 1);
ballsDestroyed++;
checkAchievement('magnetMaster');
}
// Projectile behavior after magnet hit
if (projectile.type !== 'laser' && projectile.type !== 'piercing') {
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
}
}
}
// Check mirror ball collisions
for (var j = mirrorBalls.length - 1; j >= 0; j--) {
var mirrorBall = mirrorBalls[j];
if (checkCollision(projectile, mirrorBall, projectile.radius, mirrorBall.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
// Reflect projectile
var dx = projectile.x - mirrorBall.x;
var dy = projectile.y - mirrorBall.y;
var dist = Math.sqrt(dx * dx + dy * dy);
dx /= dist;
dy /= dist;
projectile.velocityX = dx * projectile.speed * 1.5;
projectile.velocityY = dy * projectile.speed * 1.5;
// Mirror flash effect
var flash = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: mirrorBall.x,
y: mirrorBall.y,
scaleX: 1,
scaleY: 1,
alpha: 0.8,
tint: 0xffffff
});
tween(flash, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
flash.destroy();
}
});
if (mirrorBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + 150 * scoreMultiplier * scoreBoostMultiplier);
createExplosion(mirrorBall.x, mirrorBall.y, 0xc0c0c0, 40);
mirrorBall.destroy();
mirrorBalls.splice(j, 1);
ballsDestroyed++;
}
// Projectile bounces off mirror balls
if (projectile.type !== 'laser') {
break;
}
}
}
// Check bomb ball collisions
for (var j = bombBalls.length - 1; j >= 0; j--) {
var bombBall = bombBalls[j];
if (checkCollision(projectile, bombBall, projectile.radius, bombBall.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
if (bombBall.takeDamage()) {
LK.getSound('destroy').play();
// Bomb explosion damages all nearby balls
createExplosion(bombBall.x, bombBall.y, 0xff0000, 50);
LK.effects.flashScreen(0xff0000, 300);
achievementProgress.bombExpert++;
if (achievementProgress.bombExpert >= 10) checkAchievement('bombExpert');
// Damage all balls in explosion radius (collect first, then destroy to avoid index skipping)
var toDestroy = [];
for (var k = 0; k < balls.length; k++) {
var nearbyBall = balls[k];
if (checkCollision(bombBall, nearbyBall, 200, nearbyBall.radius)) {
for (var d = 0; d < 3; d++) {
if (nearbyBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 2));
createExplosion(nearbyBall.x, nearbyBall.y, 0xffff00, 20);
toDestroy.push(nearbyBall);
break;
}
}
}
}
// Now destroy all marked balls (destroy objects, then remove from array)
for (var td = 0; td < toDestroy.length; td++) {
var obj = toDestroy[td];
var idx = balls.indexOf(obj);
if (idx !== -1) {
balls[idx].destroy();
balls.splice(idx, 1);
}
}
bombBall.destroy();
bombBalls.splice(j, 1);
}
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
}
}
// Check ball collisions
for (var j = balls.length - 1; j >= 0; j--) {
var ball = balls[j];
if (checkCollision(projectile, ball, projectile.radius, ball.radius)) {
LK.getSound('hit').play();
updateCombo();
hitBall = true;
// Set gravity to 1% per frame after hit
if (typeof projectile.gravity === "undefined" || projectile.gravity < 0.1) {
projectile.gravity = 0.1;
}
// Handle explosive projectiles
if (projectile.type === 'explosive') {
// No explosion effect, just damage nearby balls (loop backwards to avoid skipping)
// Also remove any projectiles that are inside the explosion radius to prevent stuck balls
for (var k = balls.length - 1; k >= 0; k--) {
var otherBall = balls[k];
if (checkCollision(ball, otherBall, 150, otherBall.radius)) {
if (otherBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier));
// No explosion effect here
otherBall.destroy();
balls.splice(k, 1);
}
}
}
// Remove any projectiles that are inside the explosion radius (except the current one)
for (var pk = projectiles.length - 1; pk >= 0; pk--) {
var otherProj = projectiles[pk];
if (otherProj !== projectile && checkCollision(ball, otherProj, 150, otherProj.radius)) {
otherProj.destroy();
projectiles.splice(pk, 1);
}
}
}
if (ball.takeDamage()) {
LK.getSound('destroy').play();
consecutiveHits++;
if (consecutiveHits >= 3) {
chainReactionActive = true;
achievementProgress.chainReactionPro++;
if (achievementProgress.chainReactionPro >= 50) checkAchievement('chainReactionPro');
}
// Track weapon kills
switch (projectile.type) {
case 'fireball':
achievementProgress.fireballKills++;
if (achievementProgress.fireballKills >= 100) checkAchievement('fireballKills');
break;
case 'laser':
achievementProgress.laserKills++;
if (achievementProgress.laserKills >= 100) checkAchievement('laserKills');
break;
case 'explosive':
achievementProgress.explosiveKills++;
if (achievementProgress.explosiveKills >= 100) checkAchievement('explosiveKills');
break;
case 'piercing':
achievementProgress.piercingKills++;
if (achievementProgress.piercingKills >= 100) checkAchievement('piercingKills');
break;
case 'rapid':
achievementProgress.rapidKills++;
if (achievementProgress.rapidKills >= 100) checkAchievement('rapidKills');
break;
case 'split':
achievementProgress.splitKills++;
if (achievementProgress.splitKills >= 100) checkAchievement('splitKills');
break;
case 'giant':
achievementProgress.giantKills++;
if (achievementProgress.giantKills >= 100) checkAchievement('giantKills');
break;
}
// Track perfect accuracy
achievementProgress.perfectAccuracy++;
if (achievementProgress.perfectAccuracy >= 100) checkAchievement('perfectAccuracy');
// Check for lucky long distance shot
var shotDistance = Math.sqrt(Math.pow(ball.x - cannon.x, 2) + Math.pow(ball.y - cannon.y, 2));
if (shotDistance > 2000) {
checkAchievement('luckyShot');
// Lucky shot visual effect
var luckyText = new Text2('LUCKY SHOT!', {
size: 20,
fill: 0xffd700
});
luckyText.anchor.set(0.5, 0.5);
luckyText.x = ball.x;
luckyText.y = ball.y - 100;
game.addChild(luckyText);
tween(luckyText, {
y: ball.y - 200,
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
luckyText.destroy();
}
});
}
var points = Math.floor(stage * scoreMultiplier * scoreBoostMultiplier * (chainReactionActive ? 2 : 1));
LK.setScore(LK.getScore() + points);
scoreText.setText('Score: ' + LK.getScore());
createExplosion(ball.x, ball.y, 0xffff00, chainReactionActive ? 25 : 15);
// Chain reaction damage (loop backwards to avoid skipping)
if (chainReactionActive) {
for (var k = balls.length - 1; k >= 0; k--) {
var nearbyBall = balls[k];
if (nearbyBall !== ball && checkCollision(ball, nearbyBall, 100, nearbyBall.radius)) {
if (nearbyBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 2));
createExplosion(nearbyBall.x, nearbyBall.y, 0xffff00, 20);
nearbyBall.destroy();
balls.splice(k, 1);
}
}
}
}
ball.destroy();
balls.splice(j, 1);
ballsDestroyed++;
perfectHits++;
}
// Handle projectile behavior after hit
if (projectile.type === 'lightning') {
// Chain to nearby balls
var chainTargets = [];
for (var k = 0; k < balls.length; k++) {
var nearbyBall = balls[k];
if (nearbyBall !== ball && checkCollision(ball, nearbyBall, 150, nearbyBall.radius)) {
chainTargets.push(nearbyBall);
}
}
// Create lightning visual effect
for (var c = 0; c < Math.min(chainTargets.length, 3); c++) {
var target = chainTargets[c];
var lightning = game.attachAsset('aimline', {
anchorX: 0.5,
anchorY: 0,
x: ball.x,
y: ball.y,
tint: 0x9966ff,
alpha: 0.8
});
var dx = target.x - ball.x;
var dy = target.y - ball.y;
var dist = Math.sqrt(dx * dx + dy * dy);
lightning.height = dist;
lightning.rotation = Math.atan2(dy, dx) + Math.PI / 2;
tween(lightning, {
alpha: 0,
scaleX: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
lightning.destroy();
}
});
// Damage chained balls
if (target.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * scoreBoostMultiplier));
createExplosion(target.x, target.y, 0x9966ff, 20);
target.destroy();
var idx = balls.indexOf(target);
if (idx > -1) balls.splice(idx, 1);
}
}
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
} else if (projectile.type === 'piercing' && projectile.piercing > 0) {
projectile.piercing--;
// Continue in same direction
} else if (projectile.type === 'explosive') {
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
} else if (projectile.type === 'fireball') {
// Fireball burns through everything
createExplosion(ball.x, ball.y, 0xff6600, 15);
} else if (projectile.type === 'split') {
// Split into 3 projectiles
for (var s = 0; s < 3; s++) {
var splitProjectile = new SpecialProjectile();
splitProjectile.x = projectile.x;
splitProjectile.y = projectile.y;
splitProjectile.setType('normal');
var splitAngle = Math.atan2(projectile.velocityY, projectile.velocityX) + (s - 1) * 0.5;
splitProjectile.velocityX = Math.cos(splitAngle) * splitProjectile.speed;
splitProjectile.velocityY = Math.sin(splitAngle) * splitProjectile.speed;
projectiles.push(splitProjectile);
game.addChild(splitProjectile);
}
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
} else if (projectile.type === 'laser') {
// Laser continues straight
} else {
// Normal bounce
var dx = projectile.x - ball.x;
var dy = projectile.y - ball.y;
var dist = Math.sqrt(dx * dx + dy * dy);
dx /= dist;
dy /= dist;
projectile.velocityX = dx * projectile.speed;
projectile.velocityY = dy * projectile.speed;
}
if (!projectile.type || projectile.type === 'normal' || projectile.type === 'rapid' || projectile.type === 'giant') {
break;
}
}
}
if (hitBall) {
// Perfect shot bonus
if (consecutiveHits >= 10 && consecutiveHits % 5 === 0) {
var perfectBonus = 100 * scoreMultiplier;
LK.setScore(LK.getScore() + perfectBonus);
var perfectText = new Text2('PERFECT SHOT! +' + perfectBonus, {
size: 60,
fill: 0x00ff00
});
perfectText.anchor.set(0.5, 0.5);
perfectText.alpha = 0;
LK.gui.center.addChild(perfectText);
tween(perfectText, {
alpha: 1,
y: -50
}, {
duration: 300,
onFinish: function onFinish() {
tween(perfectText, {
alpha: 0
}, {
duration: 500,
delay: 500,
onFinish: function onFinish() {
perfectText.destroy();
}
});
}
});
}
continue;
} else {
chainReactionActive = false;
consecutiveHits = 0;
}
// Check powerup collisions
for (var j = powerups.length - 1; j >= 0; j--) {
var powerup = powerups[j];
if (checkCollision(projectile, powerup, projectile.radius, powerup.radius)) {
LK.getSound('collect').play();
projectileCount++;
projectileCountText.setText('x' + projectileCount);
createExplosion(powerup.x, powerup.y, 0x4ecdc4, 10);
powerup.destroy();
powerups.splice(j, 1);
}
}
// Check slow motion power-up collisions
for (var j = slowMotionPowerups.length - 1; j >= 0; j--) {
var slowPowerup = slowMotionPowerups[j];
if (checkCollision(projectile, slowPowerup, projectile.radius, slowPowerup.radius)) {
LK.getSound('collect').play();
slowMotionActive = true;
slowMotionTimer = 300; // 5 seconds at 60 FPS
powerUpIndicator.setText('SLOW MOTION');
achievementProgress.slowMotionPro++;
achievementProgress.powerupMaster++;
if (achievementProgress.slowMotionPro >= 20) checkAchievement('slowMotionPro');
if (achievementProgress.powerupMaster >= 100) checkAchievement('powerupMaster');
tween(slowMotionBg, {
alpha: 0.1
}, {
duration: 300
});
createExplosion(slowPowerup.x, slowPowerup.y, 0x9b59b6, 20);
slowPowerup.destroy();
slowMotionPowerups.splice(j, 1);
}
}
// Check multiball power-up collisions
for (var j = multiballPowerups.length - 1; j >= 0; j--) {
var multiballPowerup = multiballPowerups[j];
if (checkCollision(projectile, multiballPowerup, projectile.radius, multiballPowerup.radius)) {
LK.getSound('collect').play();
multiballActive = true;
powerUpIndicator.setText('MULTIBALL!');
createExplosion(multiballPowerup.x, multiballPowerup.y, 0xe74c3c, 25);
multiballPowerup.destroy();
multiballPowerups.splice(j, 1);
}
}
// Check fireball power-up collisions
for (var j = fireballPowerups.length - 1; j >= 0; j--) {
var fireballPowerup = fireballPowerups[j];
if (checkCollision(projectile, fireballPowerup, projectile.radius, fireballPowerup.radius)) {
LK.getSound('collect').play();
fireballActive = true;
powerUpIndicator.setText('FIREBALL!');
createExplosion(fireballPowerup.x, fireballPowerup.y, 0xff6600, 30);
fireballPowerup.destroy();
fireballPowerups.splice(j, 1);
}
}
// Check giant ball power-up collisions
for (var j = giantBallPowerups.length - 1; j >= 0; j--) {
var giantBallPowerup = giantBallPowerups[j];
if (checkCollision(projectile, giantBallPowerup, projectile.radius, giantBallPowerup.radius)) {
LK.getSound('collect').play();
giantBallActive = true;
powerUpIndicator.setText('GIANT BALL!');
createExplosion(giantBallPowerup.x, giantBallPowerup.y, 0x00ff00, 35);
giantBallPowerup.destroy();
giantBallPowerups.splice(j, 1);
}
}
// Check split ball power-up collisions
for (var j = splitBallPowerups.length - 1; j >= 0; j--) {
var splitBallPowerup = splitBallPowerups[j];
if (checkCollision(projectile, splitBallPowerup, projectile.radius, splitBallPowerup.radius)) {
LK.getSound('collect').play();
splitBallActive = true;
powerUpIndicator.setText('SPLIT BALL!');
createExplosion(splitBallPowerup.x, splitBallPowerup.y, 0xff00ff, 30);
splitBallPowerup.destroy();
splitBallPowerups.splice(j, 1);
}
}
// Check laser power-up collisions
for (var j = laserPowerups.length - 1; j >= 0; j--) {
var laserPowerup = laserPowerups[j];
if (checkCollision(projectile, laserPowerup, projectile.radius, laserPowerup.radius)) {
LK.getSound('collect').play();
laserActive = true;
powerUpIndicator.setText('LASER BEAM!');
createExplosion(laserPowerup.x, laserPowerup.y, 0x00ffff, 40);
laserPowerup.destroy();
laserPowerups.splice(j, 1);
}
}
// Check shield power-up collisions
for (var j = shieldPowerups.length - 1; j >= 0; j--) {
var shieldPowerup = shieldPowerups[j];
if (checkCollision(projectile, shieldPowerup, projectile.radius, shieldPowerup.radius)) {
LK.getSound('collect').play();
shieldActive = true;
shieldTimer = 600; // 10 seconds
powerUpIndicator.setText('SHIELD ACTIVE!');
tween(shieldBg, {
alpha: 0.3
}, {
duration: 300
});
createExplosion(shieldPowerup.x, shieldPowerup.y, 0x3498db, 30);
shieldPowerup.destroy();
shieldPowerups.splice(j, 1);
// Shield achievement
if (!achievements.shieldMaster) {
achievements.shieldMaster = true;
showAchievement('Shield Master!', 0x3498db);
}
}
}
// Check double shot power-up collisions
for (var j = doubleShotPowerups.length - 1; j >= 0; j--) {
var doubleShotPowerup = doubleShotPowerups[j];
if (checkCollision(projectile, doubleShotPowerup, projectile.radius, doubleShotPowerup.radius)) {
LK.getSound('collect').play();
doubleShotActive = true;
doubleShotTimer = 600; // 10 seconds
doubleShotIndicator.setText('DOUBLE SHOT!');
createExplosion(doubleShotPowerup.x, doubleShotPowerup.y, 0xffff00, 35);
doubleShotPowerup.destroy();
doubleShotPowerups.splice(j, 1);
}
}
// Check lightning power-up collisions
for (var j = lightningPowerups.length - 1; j >= 0; j--) {
var lightningPowerup = lightningPowerups[j];
if (checkCollision(projectile, lightningPowerup, projectile.radius, lightningPowerup.radius)) {
LK.getSound('collect').play();
lightningActive = true;
powerUpIndicator.setText('LIGHTNING CHAIN!');
createExplosion(lightningPowerup.x, lightningPowerup.y, 0x9966ff, 40);
lightningPowerup.destroy();
lightningPowerups.splice(j, 1);
powerupsCollected++;
if (!achievements.lightningMaster) {
achievements.lightningMaster = true;
showAchievement('Lightning Master!', 0x9966ff);
}
}
}
// Check freeze bomb power-up collisions
for (var j = freezeBombPowerups.length - 1; j >= 0; j--) {
var freezeBombPowerup = freezeBombPowerups[j];
if (checkCollision(projectile, freezeBombPowerup, projectile.radius, freezeBombPowerup.radius)) {
LK.getSound('collect').play();
// Freeze explosion effect
createExplosion(freezeBombPowerup.x, freezeBombPowerup.y, 0x00ccff, 50);
LK.effects.flashScreen(0x00ccff, 500);
// Freeze all balls in radius (loop backwards to avoid skipping)
for (var k = balls.length - 1; k >= 0; k--) {
var ball = balls[k];
if (checkCollision(freezeBombPowerup, ball, 300, ball.radius)) {
ball.tint = 0x00ccff;
// Create ice effect on ball
var ice = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: ball.x,
y: ball.y,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.3,
tint: 0x00ffff
});
tween(ice, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 2000,
onFinish: function onFinish() {
ice.destroy();
}
});
// Damage frozen ball
for (var d = 0; d < 5; d++) {
if (ball.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 3));
createExplosion(ball.x, ball.y, 0x00ccff, 25);
ball.destroy();
balls.splice(k, 1);
ballsDestroyed++;
break;
}
}
}
}
freezeBombPowerup.destroy();
freezeBombPowerups.splice(j, 1);
powerupsCollected++;
}
}
// Check chain reaction power-up collisions
for (var j = chainReactionPowerups.length - 1; j >= 0; j--) {
var chainReactionPowerup = chainReactionPowerups[j];
if (checkCollision(projectile, chainReactionPowerup, projectile.radius, chainReactionPowerup.radius)) {
LK.getSound('collect').play();
chainReactionBombActive = true;
powerUpIndicator.setText('CHAIN BOMB!');
createExplosion(chainReactionPowerup.x, chainReactionPowerup.y, 0xff8800, 40);
// Make next hit cause massive chain reaction
consecutiveHits = 10;
chainReactionActive = true;
chainReactionPowerup.destroy();
chainReactionPowerups.splice(j, 1);
powerupsCollected++;
}
}
// Check teleport power-up collisions
for (var j = teleportPowerups.length - 1; j >= 0; j--) {
var teleportPowerup = teleportPowerups[j];
if (checkCollision(projectile, teleportPowerup, projectile.radius, teleportPowerup.radius)) {
LK.getSound('collect').play();
// Teleport effect
var portal1 = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: projectile.x,
y: projectile.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8,
tint: 0x8000ff
});
tween(portal1, {
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 500,
onFinish: function onFinish() {
portal1.destroy();
}
});
// Teleport projectile to random position
projectile.x = Math.random() * 1648 + 200;
projectile.y = Math.random() * 1000 + 500;
// Exit portal effect
var portal2 = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: projectile.x,
y: projectile.y,
scaleX: 2,
scaleY: 2,
alpha: 0,
tint: 0x8000ff
});
tween(portal2, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8,
rotation: -Math.PI * 2
}, {
duration: 500,
onFinish: function onFinish() {
portal2.destroy();
}
});
teleportPowerup.destroy();
teleportPowerups.splice(j, 1);
powerupsCollected++;
}
}
// Check star collisions
for (var j = stars.length - 1; j >= 0; j--) {
var star = stars[j];
// HeartBall: +10 HP, effect, destroy
if (star instanceof HeartBall && checkCollision(projectile, star, projectile.radius, star.radius)) {
LK.getSound('collect').play();
var oldHP = hp;
hp = Math.min(hp + 10, maxHP);
// Show +10 HP effect
var hpGainText = new Text2('+10 HP', {
size: 60,
fill: 0xff3366
});
hpGainText.anchor.set(0.5, 0.5);
hpGainText.x = star.x;
hpGainText.y = star.y;
game.addChild(hpGainText);
tween(hpGainText, {
y: star.y - 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
hpGainText.destroy();
}
});
hpText.setText('HP: ' + hp);
createExplosion(star.x, star.y, 0xff3366, 15);
star.destroy();
stars.splice(j, 1);
continue;
}
// Normal star
if (checkCollision(projectile, star, projectile.radius, star.radius)) {
LK.getSound('collect').play();
// Random bonus effect
var randomEffect = Math.random();
if (randomEffect < 0.15) {
magnetActive = true;
magnetTimer = 180; // 3 seconds
powerUpIndicator.setText('MAGNET ACTIVE');
} else if (randomEffect < 0.3) {
projectileCount += 2;
projectileCountText.setText('x' + projectileCount);
} else if (randomEffect < 0.45) {
// Freeze all balls temporarily
freezeActive = true;
freezeTimer = 180; // 3 seconds
powerUpIndicator.setText('FREEZE!');
for (var k = 0; k < balls.length; k++) {
balls[k].tint = 0x00ffff;
}
} else if (randomEffect < 0.6) {
// Reverse gravity
reverseGravityActive = true;
reverseGravityTimer = 300; // 5 seconds
ballSpeed = -Math.abs(ballSpeed);
powerUpIndicator.setText('REVERSE GRAVITY!');
LK.effects.flashScreen(0xff00ff, 500);
if (!achievements.reverseGravity) {
achievements.reverseGravity = true;
showAchievement('Gravity Master!', 0xff00ff);
}
} else if (randomEffect < 0.75) {
// Score boost
scoreBoostActive = true;
scoreBoostTimer = 600; // 10 seconds
powerUpIndicator.setText('3X SCORE!');
} else if (randomEffect < 0.9) {
// Auto aim
autoAimActive = true;
autoAimTimer = 300; // 5 seconds
powerUpIndicator.setText('AUTO AIM!');
} else {
// Random weapon power-up
var weapons = ['fireball', 'giant', 'split', 'laser', 'lightning'];
var randomWeapon = weapons[Math.floor(Math.random() * weapons.length)];
switch (randomWeapon) {
case 'fireball':
fireballActive = true;
break;
case 'giant':
giantBallActive = true;
break;
case 'split':
splitBallActive = true;
break;
case 'laser':
laserActive = true;
break;
case 'lightning':
lightningActive = true;
break;
}
powerUpIndicator.setText(randomWeapon.toUpperCase() + '!');
}
// Unlock weapons based on score
// Check achievements
if (combo >= 10 && !achievements.combo10) {
achievements.combo10 = true;
showAchievement('Combo Master!', 0xFF00FF);
}
if (LK.getScore() >= 1000 && !achievements.score1000) {
achievements.score1000 = true;
showAchievement('Score Champion!', 0xFFD700);
}
if (weaponUnlocks.piercing && weaponUnlocks.explosive && weaponUnlocks.rapid && !achievements.allWeapons) {
achievements.allWeapons = true;
showAchievement('Weapon Master!', 0x00FF00);
}
// Save high score
if (!savedData.highScore || LK.getScore() > savedData.highScore) {
savedData.highScore = LK.getScore();
// Flatten achievements into savedData directly
savedData.firstWin = achievements.firstWin;
savedData.combo10 = achievements.combo10;
savedData.score1000 = achievements.score1000;
savedData.allWeapons = achievements.allWeapons;
storage['99balls_save'] = savedData;
}
if (LK.getScore() >= 100 && !weaponUnlocks.piercing) {
weaponUnlocks.piercing = true;
var unlockText = new Text2('Piercing Weapon Unlocked!', {
size: 80,
fill: 0xFF00FF
});
unlockText.anchor.set(0.5, 0.5);
unlockText.alpha = 0;
LK.gui.center.addChild(unlockText);
tween(unlockText, {
alpha: 1,
y: -100
}, {
duration: 500,
onFinish: function onFinish() {
tween(unlockText, {
alpha: 0
}, {
duration: 1000,
delay: 1000,
onFinish: function onFinish() {
unlockText.destroy();
}
});
}
});
}
if (LK.getScore() >= 300 && !weaponUnlocks.explosive) {
weaponUnlocks.explosive = true;
var unlockText = new Text2('Explosive Weapon Unlocked!', {
size: 80,
fill: 0xFF4444
});
unlockText.anchor.set(0.5, 0.5);
unlockText.alpha = 0;
LK.gui.center.addChild(unlockText);
tween(unlockText, {
alpha: 1,
y: -100
}, {
duration: 500,
onFinish: function onFinish() {
tween(unlockText, {
alpha: 0
}, {
duration: 1000,
delay: 1000,
onFinish: function onFinish() {
unlockText.destroy();
}
});
}
});
}
if (LK.getScore() >= 500 && !weaponUnlocks.rapid) {
weaponUnlocks.rapid = true;
var unlockText = new Text2('Rapid Fire Unlocked!', {
size: 80,
fill: 0x44FF44
});
unlockText.anchor.set(0.5, 0.5);
unlockText.alpha = 0;
LK.gui.center.addChild(unlockText);
tween(unlockText, {
alpha: 1,
y: -100
}, {
duration: 500,
onFinish: function onFinish() {
tween(unlockText, {
alpha: 0
}, {
duration: 1000,
delay: 1000,
onFinish: function onFinish() {
unlockText.destroy();
}
});
}
});
}
LK.setScore(LK.getScore() + Math.floor(10 * scoreMultiplier));
scoreText.setText('Score: ' + LK.getScore());
createExplosion(star.x, star.y, 0xffd93d, 15);
star.destroy();
stars.splice(j, 1);
achievementProgress.starCollector++;
if (achievementProgress.starCollector >= 50) checkAchievement('starCollector');
}
}
}
// Check if all projectiles are gone
if (projectiles.length === 0 && !canShoot) {
canShoot = true;
moveRow();
if (balls.length === 0) {
stage++;
stageText.setText('Stage ' + stage);
ballSpeed += 0.1;
// Bonus for clearing stage
var bonus = stage * 50;
LK.setScore(LK.getScore() + bonus);
scoreText.setText('Score: ' + LK.getScore());
var bonusText = new Text2('Stage Clear! +' + bonus, {
size: 100,
fill: 0x00FF00
});
bonusText.anchor.set(0.5, 0.5);
bonusText.alpha = 0;
LK.gui.center.addChild(bonusText);
// Check if this is first stage clear
if (stage === 2 && !achievements.firstWin) {
achievements.firstWin = true;
showAchievement('First Victory!', 0x00FF00);
}
// Perfect stage bonus
if (projectileCount === 1) {
perfectStageBonus = true;
var perfectBonus = stage * 100;
LK.setScore(LK.getScore() + perfectBonus);
showAchievement('Perfect Stage! +' + perfectBonus, 0xFFD700);
if (!achievements.perfectStage) {
achievements.perfectStage = true;
showAchievement('Perfectionist!', 0xFFD700);
}
}
tween(bonusText, {
alpha: 1,
y: -200
}, {
duration: 500,
onFinish: function onFinish() {
tween(bonusText, {
alpha: 0
}, {
duration: 500,
delay: 500,
onFinish: function onFinish() {
bonusText.destroy();
}
});
}
});
}
}
// Check time-based achievements
if (LK.ticks % 60 === 0) {
var seconds = Math.floor(LK.ticks / 60);
if (seconds >= 600 && !achievements.survivor) {
checkAchievement('survivor');
}
}
// Check stage achievements
if (stage >= 10) checkAchievement('stage10');
if (stage >= 25) checkAchievement('stage25');
if (stage >= 50) checkAchievement('stage50');
// Check score achievements
if (LK.getScore() >= 5000) checkAchievement('score5000');
if (LK.getScore() >= 10000) checkAchievement('score10000');
if (LK.getScore() >= 50000) checkAchievement('score50000');
// Check combo achievements
if (combo >= 20) checkAchievement('combo20');
if (combo >= 50) checkAchievement('combo50');
// Check projectile achievements
if (projectileCount >= 10) checkAchievement('richPlayer');
if (achievementProgress.projectiles50 >= 50) checkAchievement('projectiles50');
if (achievementProgress.projectiles100 >= 100) checkAchievement('projectiles100');
// Special win condition - collect all power-up types in one game
var allPowerUpsCollected = fireballActive || giantBallActive || splitBallActive || laserActive || lightningActive || multiballActive || doubleShotActive || slowMotionActive || magnetActive || shieldActive || freezeActive;
if (allPowerUpsCollected && powerupsCollected >= 20 && !achievements.versatile) {
checkAchievement('versatile');
// Epic win effect
var epicWin = new Text2('POWER MASTER!', {
size: 120,
fill: 0xff00ff
});
epicWin.anchor.set(0.5, 0.5);
epicWin.alpha = 0;
LK.gui.center.addChild(epicWin);
tween(epicWin, {
alpha: 1,
rotation: Math.PI * 2
}, {
duration: 1000,
onFinish: function onFinish() {
tween(epicWin, {
alpha: 0,
scaleX: 3,
scaleY: 3
}, {
duration: 1000,
onFinish: function onFinish() {
epicWin.destroy();
}
});
}
});
}
// Check power-up master achievement
if (powerupsCollected >= 100) checkAchievement('powerupMaster');
// Special effects for high combos
if (combo > 30 && combo % 10 === 0) {
var rainbowFlash = game.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.5,
tint: Math.random() * 0xffffff | 0
});
tween(rainbowFlash, {
scaleX: 30,
scaleY: 30,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
onFinish: function onFinish() {
rainbowFlash.destroy();
}
});
}
// Check game over
if (gameActive) {
for (var i = 0; i < balls.length; i++) {
if (balls[i].y > 2400) {
if (shieldActive) {
// Shield protects from game over once
shieldActive = false;
shieldTimer = 0;
tween(shieldBg, {
alpha: 0
}, {
duration: 300
});
balls[i].destroy();
balls.splice(i, 1);
var shieldSaveText = new Text2('SHIELD SAVED YOU!', {
size: 80,
fill: 0x3498db
});
shieldSaveText.anchor.set(0.5, 0.5);
shieldSaveText.alpha = 0;
LK.gui.center.addChild(shieldSaveText);
tween(shieldSaveText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(shieldSaveText, {
alpha: 0
}, {
duration: 500,
delay: 1000,
onFinish: function onFinish() {
shieldSaveText.destroy();
}
});
}
});
LK.effects.flashScreen(0x3498db, 500);
continue;
}
// HP system: decrease HP by the number on the ball
var lostHP = 1;
if (typeof balls[i].hits === "number") {
lostHP = balls[i].hits;
} else if (_typeof(balls[i].numberText) === "object" && balls[i].numberText.text) {
var parsed = parseInt(balls[i].numberText.text, 10);
if (!isNaN(parsed)) lostHP = parsed;
}
hp -= lostHP;
if (hp < 0) hp = 0;
hpText.setText('HP: ' + hp);
// Visual feedback for HP loss
var hpLossText = new Text2('-' + lostHP + ' HP', {
size: 60,
fill: 0xff4444
});
hpLossText.anchor.set(0.5, 0.5);
hpLossText.x = balls[i].x;
hpLossText.y = balls[i].y;
game.addChild(hpLossText);
tween(hpLossText, {
y: balls[i].y - 100,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
hpLossText.destroy();
}
});
balls[i].destroy();
balls.splice(i, 1);
// Game over if HP is 0 or less
if (hp <= 0) {
gameActive = false;
// Save progress before game over
if (!savedData.highScore || LK.getScore() > savedData.highScore) {
savedData.highScore = LK.getScore();
// Flatten achievements into savedData directly
savedData.firstWin = achievements.firstWin;
savedData.combo10 = achievements.combo10;
savedData.score1000 = achievements.score1000;
savedData.allWeapons = achievements.allWeapons;
storage['99balls_save'] = savedData;
}
LK.showGameOver();
break;
}
}
}
}
};
// Add achievements button
var achievementsButton = game.addChild(new Container());
var achievementsBg = achievementsButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFD700,
scaleX: 1.2,
scaleY: 1.2
});
var achievementsButtonText = new Text2('Achievements', {
size: 25,
fill: 0x000000
});
achievementsButtonText.anchor.set(0.5, 0.5);
achievementsButton.addChild(achievementsButtonText);
achievementsButton.x = 1924;
achievementsButton.y = 200;
// Add glow effect to achievements button
achievementsButton.update = function () {
achievementsBg.alpha = 0.8 + Math.sin(LK.ticks * 0.05) * 0.2;
};
// Achievement panel
var achievementPanel = new Container();
var panelBg = achievementPanel.attachAsset('achievementPanelBg', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.95
});
achievementPanel.visible = false;
LK.gui.center.addChild(achievementPanel);
var achievementTitle = new Text2('ACHIEVEMENTS', {
size: 60,
fill: 0xFFD700
});
achievementTitle.anchor.set(0.5, 0.5);
achievementTitle.y = -600;
achievementPanel.addChild(achievementTitle);
var closeButton = new Container();
var closeBg = closeButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff4444
});
var closeText = new Text2('X', {
size: 40,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = 450;
closeButton.y = -600;
achievementPanel.addChild(closeButton);
closeButton.down = function () {
achievementPanel.visible = false;
gameActive = true;
};
achievementsButton.down = function () {
achievementPanel.visible = true;
gameActive = false;
updateAchievementDisplay();
};
// Add weapon switch button
var weaponButton = game.addChild(new Container());
var buttonBg = weaponButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2('Switch', {
size: 30,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
weaponButton.addChild(buttonText);
weaponButton.x = 1024;
weaponButton.y = 2400;
weaponButton.down = function () {
var weapons = ['normal'];
if (weaponUnlocks.piercing) weapons.push('piercing');
if (weaponUnlocks.explosive) weapons.push('explosive');
if (weaponUnlocks.rapid) weapons.push('rapid');
var currentIndex = weapons.indexOf(currentWeapon);
currentWeapon = weapons[(currentIndex + 1) % weapons.length];
switch (currentWeapon) {
case 'normal':
weaponText.setText('Normal');
weaponText.tint = 0xFFFFFF;
break;
case 'piercing':
weaponText.setText('Piercing');
weaponText.tint = 0xFF00FF;
break;
case 'explosive':
weaponText.setText('Explosive');
weaponText.tint = 0xFF4444;
break;
case 'rapid':
weaponText.setText('Rapid Fire');
weaponText.tint = 0x44FF44;
break;
}
tween(weaponButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(weaponButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
initializeLevel();
Renkli yuvarlak Balon, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. High contrast. No shadows
tek renk top, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. 2d. High contrast. No shadows
tek renk top, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. High contrast. No shadows
tek renk top, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. High contrast. No shadows
tek renk top, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. High contrast. No shadows
tek renk top, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. High contrast. No shadows
tek renk top, üstten görünüm, Gerçekçi, yazısız.. In-Game asset. High contrast. No shadows