/**** * 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { 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()); // Keep all balloons the same size ballGraphics.scale.set(1); self.radius = 40; }; 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { anchorX: 0.5, anchorY: 0.5, tint: 0x333333, scaleX: 1, scaleY: 1 }); 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 = 40; 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 * pulse); } }; return self; }); var BossBall = Container.expand(function () { var self = Container.call(this); var balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { anchorX: 0.5, anchorY: 0.5, tint: 0xff1744, scaleX: 1, scaleY: 1 }); 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 = 40; 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: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1, scaleY: 1 }, { 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { 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; }); // 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { anchorX: 0.5, anchorY: 0.5, tint: 0x0066cc, scaleX: 1, scaleY: 1 }); 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 = 40; 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: 0.85, scaleY: 0.85 }, { duration: 100, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1, scaleY: 1 }, { 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { anchorX: 0.5, anchorY: 0.5, tint: 0xc0c0c0, scaleX: 1, scaleY: 1 }); 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 = 40; 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1); var ballGraphics = self.attachAsset(balloonType, { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); 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 = 40; 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 '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: 35, fill: 0xff4444 }); hpText.anchor.set(0, 0); hpText.x = 20 + 2 * 80; hpText.y = 20; LK.gui.topLeft.addChild(hpText); // Stage timer text (below HP) var stageTimerText = new Text2('Next Stage: 2:00', { size: 35, fill: 0x00CCFF }); stageTimerText.anchor.set(0, 0); stageTimerText.x = 20 + 2 * 80; stageTimerText.y = 80; LK.gui.topLeft.addChild(stageTimerText); // 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: 28, fill: 0xFFD700 }); comboText.anchor.set(1, 0); comboText.x = -380; comboText.y = 20; LK.gui.topRight.addChild(comboText); var amazingText = new Text2('', { size: 28, fill: 0xFFD700 }); amazingText.anchor.set(1, 0); amazingText.x = -380; amazingText.y = 50; LK.gui.topRight.addChild(amazingText); 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 splitBallPowerups = []; var laserPowerups = []; var fireballActive = 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", 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, 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(); // Play background music LK.playMusic('bgmusic'); } 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 > 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 (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 (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); } } var currentAchievementPage = 1; var achievementsPerPage = 15; // 3x5 grid 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(); } } // Convert achievements object to array for easier pagination var achievementKeys = []; for (var key in achievements) { achievementKeys.push(key); } var totalPages = Math.ceil(achievementKeys.length / achievementsPerPage); // Make sure current page is valid if (currentAchievementPage > totalPages) currentAchievementPage = totalPages; if (currentAchievementPage < 1) currentAchievementPage = 1; var unlocked = 0; var total = achievementKeys.length; // Count unlocked achievements for (var i = 0; i < achievementKeys.length; i++) { if (achievements[achievementKeys[i]]) unlocked++; } // Display achievements for current page var startIndex = (currentAchievementPage - 1) * achievementsPerPage; var endIndex = Math.min(startIndex + achievementsPerPage, achievementKeys.length); var row = 0; var col = 0; var xSpacing = 400; var ySpacing = 250; var xOffset = -xSpacing; var yOffset = -550; for (var i = startIndex; i < endIndex; i++) { var key = achievementKeys[i]; var achContainer = new Container(); var achBg = achContainer.attachAsset('achievementItemBg', { anchorX: 0.5, anchorY: 0.5, tint: achievements[key] ? 0x27ae60 : 0x7f8c8d, alpha: 0.9, scaleX: 1.4, scaleY: 1.4 }); var achText = new Text2(key.replace(/([A-Z])/g, ' $1').trim(), { size: 28, fill: achievements[key] ? 0xFFFFFF : 0x95a5a6 }); achText.anchor.set(0.5, 0.5); achText.y = -14; achContainer.addChild(achText); var achDesc = new Text2(achievementDescriptions[key] || '', { size: 21, fill: achievements[key] ? 0xecf0f1 : 0x7f8c8d }); achDesc.anchor.set(0.5, 0.5); achDesc.y = 14; achContainer.addChild(achDesc); achContainer.x = xOffset + col * xSpacing; achContainer.y = yOffset + row * ySpacing; achievementPanel.addChild(achContainer); col++; if (col >= 3) { col = 0; row++; } } // Add page buttons var buttonY = 750; for (var p = 1; p <= totalPages; p++) { (function (page) { var pageButton = new Container(); var pageBg = pageButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5, tint: page === currentAchievementPage ? 0xFFD700 : 0x3498db, scaleX: 0.8, scaleY: 0.8 }); var pageText = new Text2(page.toString(), { size: 40, fill: page === currentAchievementPage ? 0x000000 : 0xFFFFFF }); pageText.anchor.set(0.5, 0.5); pageButton.addChild(pageText); pageButton.x = -100 + (page - 1) * 100; pageButton.y = buttonY; achievementPanel.addChild(pageButton); pageButton.down = function () { currentAchievementPage = page; updateAchievementDisplay(); }; })(p); } var progressText = new Text2('Progress: ' + unlocked + '/' + total + ' (Page ' + currentAchievementPage + '/' + totalPages + ')', { size: 56, 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 messages = { 10: ['AMAZING!', 'INCREDIBLE!', 'FANTASTIC!', 'AWESOME!', 'BRILLIANT!'], 20: ['UNSTOPPABLE!', 'ON FIRE!', 'PHENOMENAL!', 'SUPERB!', 'OUTSTANDING!'], 30: ['UNBELIEVABLE!', 'SPECTACULAR!', 'MAGNIFICENT!', 'SENSATIONAL!', 'EXTRAORDINARY!'], 50: ['GODLIKE!', 'SUPREME!', 'ULTRA COMBO!', 'INSANE!', 'UNREAL!'], 100: ['LEGENDARY!', 'MYTHICAL!', 'EPIC MASTER!', 'ULTIMATE!', 'TRANSCENDENT!'] }; var messageArray = messages[combo] || messages[10]; var message = messageArray[Math.floor(Math.random() * messageArray.length)]; amazingText.setText(message); amazingText.alpha = 1; amazingText.tint = combo === 100 ? 0xff00ff : combo >= 50 ? 0xff1493 : 0xFFD700; tween(amazingText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(amazingText, { scaleX: 1, scaleY: 1 }, { duration: 200, onFinish: function onFinish() { LK.setTimeout(function () { tween(amazingText, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { amazingText.setText(''); } }); }, 2000); } }); } }); } } } 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 }); amazingText.setText(''); amazingText.alpha = 0; } } 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 < 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'); } // Update stage timer var timeUntilNextStage = 7200 - timePlayed % 7200; var minutes = Math.floor(timeUntilNextStage / 3600); var seconds = Math.floor(timeUntilNextStage % 3600 / 60); stageTimerText.setText('Next Stage: ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds); // Auto increase stage every 2 minutes (7200 ticks at 60 FPS) if (timePlayed % 7200 === 0 && timePlayed > 0) { stage++; stageText.setText('Stage ' + stage); ballSpeed += 0.1; // Increase MaxHP by 20 for time-based stage increase maxHP += 20; hp += 20; // Also increase current HP by 20 hpText.setText('HP: ' + hp); // Show stage increase notification var stageUpText = new Text2('Stage ' + stage + ' (Time Bonus)', { size: 100, fill: 0x00FFFF }); stageUpText.anchor.set(0.5, 0.5); stageUpText.alpha = 0; LK.gui.center.addChild(stageUpText); tween(stageUpText, { alpha: 1, y: -100 }, { duration: 500, onFinish: function onFinish() { // Show MaxHP increase notification var hpBonusText = new Text2('Max HP +20!', { size: 60, fill: 0xff3366 }); hpBonusText.anchor.set(0.5, 0.5); hpBonusText.y = 0; hpBonusText.alpha = 0; LK.gui.center.addChild(hpBonusText); tween(hpBonusText, { alpha: 1, y: 50 }, { duration: 300, onFinish: function onFinish() { tween(hpBonusText, { alpha: 0 }, { duration: 500, delay: 800, onFinish: function onFinish() { hpBonusText.destroy(); } }); } }); tween(stageUpText, { alpha: 0 }, { duration: 500, delay: 1000, onFinish: function onFinish() { stageUpText.destroy(); } }); } }); } // 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 = 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]; // Apply game speed to projectile movement var oldVelX = projectile.velocityX; var oldVelY = projectile.velocityY; projectile.velocityX *= gameSpeed; projectile.velocityY *= gameSpeed; if (projectile.update() || projectile.y > 2732 + 50) { projectile.destroy(); projectiles.splice(i, 1); continue; } projectile.velocityX = oldVelX; projectile.velocityY = oldVelY; // 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 critMessages = ['CRITICAL!', 'DEVASTATING!', 'CRUSHING HIT!', 'POWER STRIKE!', 'LUCY POWER!', 'MEGA HIT!', 'BRUTAL!', 'DESTRUCTION!', 'OBLITERATE!', 'ANNIHILATE!', 'DEMOLISH!', 'SAVAGE!']; var critMessage = critMessages[Math.floor(Math.random() * critMessages.length)]; var critText = new Text2(critMessage, { 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); achievementProgress.bombExpert++; if (achievementProgress.bombExpert >= 10) checkAchievement('bombExpert'); // Collect all balls that need explosion damage var ballsToExplode = []; // Check all balls for explosion damage for (var k = 0; k < balls.length; k++) { var nearbyBall = balls[k]; if (checkCollision(bombBall, nearbyBall, 200, nearbyBall.radius)) { ballsToExplode.push(nearbyBall); } } // Now apply damage to all marked balls for (var be = 0; be < ballsToExplode.length; be++) { var explodeBall = ballsToExplode[be]; // Apply up to 3 damage for (var d = 0; d < 3; d++) { if (explodeBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 2)); createExplosion(explodeBall.x, explodeBall.y, 0xffff00, 20); explodeBall.destroy(); // Find and remove from balls array var ballIndex = balls.indexOf(explodeBall); if (ballIndex !== -1) { balls.splice(ballIndex, 1); } break; } } } // Remove the bomb ball 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') { // Create explosion effect at impact point createExplosion(ball.x, ball.y, 0xff4444, 30); LK.effects.flashScreen(0xff4444, 200); // Collect all balls that need to be destroyed var ballsToDestroy = []; // Check all balls for explosion damage for (var k = 0; k < balls.length; k++) { var otherBall = balls[k]; if (checkCollision(ball, otherBall, 150, otherBall.radius)) { // Store reference to ball that needs destruction ballsToDestroy.push(otherBall); } } // Now destroy all marked balls for (var bd = 0; bd < ballsToDestroy.length; bd++) { var destroyBall = ballsToDestroy[bd]; // Apply damage if (destroyBall.takeDamage()) { LK.getSound('destroy').play(); LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier)); createExplosion(destroyBall.x, destroyBall.y, 0xffff00, 15); destroyBall.destroy(); // Find and remove from balls array var ballIndex = balls.indexOf(destroyBall); if (ballIndex !== -1) { balls.splice(ballIndex, 1); } } } // Remove the projectile projectile.destroy(); projectiles.splice(i, 1); i--; break; } // Skip the regular ball damage check for explosive projectiles if (projectile.type !== 'explosive' && 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; } // 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 luckyMessages = ['LUCKY SHOT!', 'LONG RANGE!', 'SNIPER SHOT!', 'DISTANCE MASTER!', 'FAR SHOT!', 'SHARPSHOOTER!', 'EAGLE STRIKE!', 'REACH SHOT!', 'LUCY SPECIAL!', 'MIRACLE SHOT!', 'IMPOSSIBLE!', 'UNREAL SHOT!']; var luckyMessage = luckyMessages[Math.floor(Math.random() * luckyMessages.length)]; var luckyText = new Text2(luckyMessage, { 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') { break; } } } if (hitBall) { // Perfect shot bonus if (consecutiveHits >= 10 && consecutiveHits % 5 === 0) { var perfectBonus = 100 * scoreMultiplier; LK.setScore(LK.getScore() + perfectBonus); var shotMessages = ['PERFECT SHOT!', 'LUCY SHOT!', 'MASTER SHOT!', 'DIVINE SHOT!', 'FLAWLESS!', 'PRECISION!', 'BULLSEYE!', 'SHARP SHOOTER!', 'SNIPER!', 'EAGLE EYE!', 'DEAD CENTER!', 'PINPOINT!']; var selectedMessage = shotMessages[Math.floor(Math.random() * shotMessages.length)]; var perfectText = new Text2(selectedMessage + ' +' + 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 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', 'split', 'laser', 'lightning']; var randomWeapon = weapons[Math.floor(Math.random() * weapons.length)]; switch (randomWeapon) { case 'fireball': fireballActive = 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; // Increase MaxHP by 20 after each stage maxHP += 20; hp += 20; // Also increase current HP by 20 hpText.setText('HP: ' + hp); // 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() { // Show MaxHP increase notification var hpBonusText = new Text2('Max HP +20!', { size: 80, fill: 0xff3366 }); hpBonusText.anchor.set(0.5, 0.5); hpBonusText.y = -100; hpBonusText.alpha = 0; LK.gui.center.addChild(hpBonusText); tween(hpBonusText, { alpha: 1, y: -50 }, { duration: 300, onFinish: function onFinish() { tween(hpBonusText, { alpha: 0 }, { duration: 500, delay: 1000, onFinish: function onFinish() { hpBonusText.destroy(); } }); } }); 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 || 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; }; // Add music button below achievements var musicButton = game.addChild(new Container()); var musicBg = musicButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5, tint: 0x3498db, scaleX: 1.2, scaleY: 1.2 }); var musicText = new Text2('♪', { size: 40, fill: 0xFFFFFF }); musicText.anchor.set(0.5, 0.5); musicButton.addChild(musicText); musicButton.x = 1924; musicButton.y = 300; // Music button functionality (visual only - LK handles actual music control) var musicEnabled = true; musicButton.down = function () { musicEnabled = !musicEnabled; if (musicEnabled) { // Resume music LK.playMusic('bgmusic'); musicBg.tint = 0x3498db; musicText.setText('♪'); musicText.alpha = 1; } else { // Stop music LK.stopMusic(); musicBg.tint = 0x7f8c8d; musicText.setText('♪'); musicText.alpha = 0.5; } tween(musicButton, { scaleX: 1.3, scaleY: 1.3 }, { duration: 100, onFinish: function onFinish() { tween(musicButton, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100 }); } }); }; // Achievement panel var achievementPanel = new Container(); var panelBg = achievementPanel.attachAsset('achievementPanelBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.95, scaleX: 1.4, scaleY: 1.4 }); achievementPanel.visible = false; LK.gui.center.addChild(achievementPanel); var achievementTitle = new Text2('ACHIEVEMENTS', { size: 84, fill: 0xFFD700 }); achievementTitle.anchor.set(0.5, 0.5); achievementTitle.y = -840; achievementPanel.addChild(achievementTitle); var closeButton = new Container(); var closeBg = closeButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5, tint: 0xff4444, scaleX: 1.4, scaleY: 1.4 }); var closeText = new Text2('X', { size: 56, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeButton.addChild(closeText); closeButton.x = 630; closeButton.y = -840; achievementPanel.addChild(closeButton); closeButton.down = function () { achievementPanel.visible = false; gameActive = true; }; achievementsButton.down = function () { achievementPanel.visible = true; gameActive = false; updateAchievementDisplay(); }; // Add reset button to bottom right var resetButton = new Container(); var resetBg = resetButton.attachAsset('addBallButton', { anchorX: 0.5, anchorY: 0.5, tint: 0xff4444, scaleX: 1.2, scaleY: 1.2 }); var resetText = new Text2('Reset', { size: 35, fill: 0xFFFFFF }); resetText.anchor.set(0.5, 0.5); resetButton.addChild(resetText); resetButton.x = -120; resetButton.y = -120; LK.gui.bottomRight.addChild(resetButton); resetButton.down = function () { // Clear all saved data storage['99balls_save'] = {}; savedData = {}; // Reset all achievements for (var key in achievements) { achievements[key] = false; } // Reset all achievement progress for (var key in achievementProgress) { achievementProgress[key] = 0; } // Reset game state LK.setScore(0); stage = 1; ballSpeed = 0.5; projectileCount = 1; maxHP = 20; hp = maxHP; combo = 0; comboTimer = 0; scoreMultiplier = 1; ballsDestroyed = 0; perfectHits = 0; missedShots = 0; powerupsCollected = 0; maxCombo = 0; timePlayed = 0; // Reset weapon unlocks weaponUnlocks.piercing = false; weaponUnlocks.explosive = false; weaponUnlocks.rapid = false; currentWeapon = 'normal'; // Reset all power-up states slowMotionActive = false; slowMotionTimer = 0; gameSpeed = 1; magnetActive = false; magnetTimer = 0; multiballActive = false; fireballActive = false; splitBallActive = false; laserActive = false; shieldActive = false; shieldTimer = 0; doubleShotActive = false; doubleShotTimer = 0; lightningActive = false; freezeActive = false; freezeTimer = 0; reverseGravityActive = false; reverseGravityTimer = 0; scoreBoostActive = false; scoreBoostTimer = 0; scoreBoostMultiplier = 1; autoAimActive = false; autoAimTimer = 0; freezeBombActive = false; chainReactionBombActive = false; teleportActive = false; chainReactionActive = false; consecutiveHits = 0; perfectStageBonus = false; // Update UI hpText.setText('HP: ' + hp); stageText.setText('Stage 1'); projectileCountText.setText('x1'); scoreText.setText('Score: 0'); weaponText.setText('Normal'); weaponText.tint = 0xFFFFFF; powerUpIndicator.setText(''); doubleShotIndicator.setText(''); comboText.setText(''); comboText.alpha = 0; amazingText.setText(''); amazingText.alpha = 0; ballsLeftText.setText('Balls Left: 0'); // Remove high score text if exists if (LK.gui.topRight.children.length > 1) { LK.gui.topRight.children[1].destroy(); } // Show reset notification var resetNotification = new Text2('All Progress Reset!', { size: 100, fill: 0xff4444 }); resetNotification.anchor.set(0.5, 0.5); resetNotification.alpha = 0; LK.gui.center.addChild(resetNotification); tween(resetNotification, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, onFinish: function onFinish() { tween(resetNotification, { alpha: 0 }, { duration: 500, delay: 1000, onFinish: function onFinish() { resetNotification.destroy(); } }); } }); // Flash effect LK.effects.flashScreen(0xff4444, 500); // Restart the game LK.showGameOver(); }; // 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
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());
// Keep all balloons the same size
ballGraphics.scale.set(1);
self.radius = 40;
};
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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333,
scaleX: 1,
scaleY: 1
});
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 = 40;
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 * pulse);
}
};
return self;
});
var BossBall = Container.expand(function () {
var self = Container.call(this);
var balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff1744,
scaleX: 1,
scaleY: 1
});
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 = 40;
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: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1,
scaleY: 1
}, {
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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
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;
});
// 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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x0066cc,
scaleX: 1,
scaleY: 1
});
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 = 40;
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: 0.85,
scaleY: 0.85
}, {
duration: 100,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1,
scaleY: 1
}, {
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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xc0c0c0,
scaleX: 1,
scaleY: 1
});
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 = 40;
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 balloonType = 'balloon' + Math.floor(Math.random() * 20 + 1);
var ballGraphics = self.attachAsset(balloonType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
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 = 40;
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 '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: 35,
fill: 0xff4444
});
hpText.anchor.set(0, 0);
hpText.x = 20 + 2 * 80;
hpText.y = 20;
LK.gui.topLeft.addChild(hpText);
// Stage timer text (below HP)
var stageTimerText = new Text2('Next Stage: 2:00', {
size: 35,
fill: 0x00CCFF
});
stageTimerText.anchor.set(0, 0);
stageTimerText.x = 20 + 2 * 80;
stageTimerText.y = 80;
LK.gui.topLeft.addChild(stageTimerText);
// 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: 28,
fill: 0xFFD700
});
comboText.anchor.set(1, 0);
comboText.x = -380;
comboText.y = 20;
LK.gui.topRight.addChild(comboText);
var amazingText = new Text2('', {
size: 28,
fill: 0xFFD700
});
amazingText.anchor.set(1, 0);
amazingText.x = -380;
amazingText.y = 50;
LK.gui.topRight.addChild(amazingText);
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 splitBallPowerups = [];
var laserPowerups = [];
var fireballActive = 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",
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,
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();
// Play background music
LK.playMusic('bgmusic');
}
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 > 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 (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 (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);
}
}
var currentAchievementPage = 1;
var achievementsPerPage = 15; // 3x5 grid
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();
}
}
// Convert achievements object to array for easier pagination
var achievementKeys = [];
for (var key in achievements) {
achievementKeys.push(key);
}
var totalPages = Math.ceil(achievementKeys.length / achievementsPerPage);
// Make sure current page is valid
if (currentAchievementPage > totalPages) currentAchievementPage = totalPages;
if (currentAchievementPage < 1) currentAchievementPage = 1;
var unlocked = 0;
var total = achievementKeys.length;
// Count unlocked achievements
for (var i = 0; i < achievementKeys.length; i++) {
if (achievements[achievementKeys[i]]) unlocked++;
}
// Display achievements for current page
var startIndex = (currentAchievementPage - 1) * achievementsPerPage;
var endIndex = Math.min(startIndex + achievementsPerPage, achievementKeys.length);
var row = 0;
var col = 0;
var xSpacing = 400;
var ySpacing = 250;
var xOffset = -xSpacing;
var yOffset = -550;
for (var i = startIndex; i < endIndex; i++) {
var key = achievementKeys[i];
var achContainer = new Container();
var achBg = achContainer.attachAsset('achievementItemBg', {
anchorX: 0.5,
anchorY: 0.5,
tint: achievements[key] ? 0x27ae60 : 0x7f8c8d,
alpha: 0.9,
scaleX: 1.4,
scaleY: 1.4
});
var achText = new Text2(key.replace(/([A-Z])/g, ' $1').trim(), {
size: 28,
fill: achievements[key] ? 0xFFFFFF : 0x95a5a6
});
achText.anchor.set(0.5, 0.5);
achText.y = -14;
achContainer.addChild(achText);
var achDesc = new Text2(achievementDescriptions[key] || '', {
size: 21,
fill: achievements[key] ? 0xecf0f1 : 0x7f8c8d
});
achDesc.anchor.set(0.5, 0.5);
achDesc.y = 14;
achContainer.addChild(achDesc);
achContainer.x = xOffset + col * xSpacing;
achContainer.y = yOffset + row * ySpacing;
achievementPanel.addChild(achContainer);
col++;
if (col >= 3) {
col = 0;
row++;
}
}
// Add page buttons
var buttonY = 750;
for (var p = 1; p <= totalPages; p++) {
(function (page) {
var pageButton = new Container();
var pageBg = pageButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: page === currentAchievementPage ? 0xFFD700 : 0x3498db,
scaleX: 0.8,
scaleY: 0.8
});
var pageText = new Text2(page.toString(), {
size: 40,
fill: page === currentAchievementPage ? 0x000000 : 0xFFFFFF
});
pageText.anchor.set(0.5, 0.5);
pageButton.addChild(pageText);
pageButton.x = -100 + (page - 1) * 100;
pageButton.y = buttonY;
achievementPanel.addChild(pageButton);
pageButton.down = function () {
currentAchievementPage = page;
updateAchievementDisplay();
};
})(p);
}
var progressText = new Text2('Progress: ' + unlocked + '/' + total + ' (Page ' + currentAchievementPage + '/' + totalPages + ')', {
size: 56,
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 messages = {
10: ['AMAZING!', 'INCREDIBLE!', 'FANTASTIC!', 'AWESOME!', 'BRILLIANT!'],
20: ['UNSTOPPABLE!', 'ON FIRE!', 'PHENOMENAL!', 'SUPERB!', 'OUTSTANDING!'],
30: ['UNBELIEVABLE!', 'SPECTACULAR!', 'MAGNIFICENT!', 'SENSATIONAL!', 'EXTRAORDINARY!'],
50: ['GODLIKE!', 'SUPREME!', 'ULTRA COMBO!', 'INSANE!', 'UNREAL!'],
100: ['LEGENDARY!', 'MYTHICAL!', 'EPIC MASTER!', 'ULTIMATE!', 'TRANSCENDENT!']
};
var messageArray = messages[combo] || messages[10];
var message = messageArray[Math.floor(Math.random() * messageArray.length)];
amazingText.setText(message);
amazingText.alpha = 1;
amazingText.tint = combo === 100 ? 0xff00ff : combo >= 50 ? 0xff1493 : 0xFFD700;
tween(amazingText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(amazingText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(amazingText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
amazingText.setText('');
}
});
}, 2000);
}
});
}
});
}
}
}
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
});
amazingText.setText('');
amazingText.alpha = 0;
}
} 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 < 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');
}
// Update stage timer
var timeUntilNextStage = 7200 - timePlayed % 7200;
var minutes = Math.floor(timeUntilNextStage / 3600);
var seconds = Math.floor(timeUntilNextStage % 3600 / 60);
stageTimerText.setText('Next Stage: ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
// Auto increase stage every 2 minutes (7200 ticks at 60 FPS)
if (timePlayed % 7200 === 0 && timePlayed > 0) {
stage++;
stageText.setText('Stage ' + stage);
ballSpeed += 0.1;
// Increase MaxHP by 20 for time-based stage increase
maxHP += 20;
hp += 20; // Also increase current HP by 20
hpText.setText('HP: ' + hp);
// Show stage increase notification
var stageUpText = new Text2('Stage ' + stage + ' (Time Bonus)', {
size: 100,
fill: 0x00FFFF
});
stageUpText.anchor.set(0.5, 0.5);
stageUpText.alpha = 0;
LK.gui.center.addChild(stageUpText);
tween(stageUpText, {
alpha: 1,
y: -100
}, {
duration: 500,
onFinish: function onFinish() {
// Show MaxHP increase notification
var hpBonusText = new Text2('Max HP +20!', {
size: 60,
fill: 0xff3366
});
hpBonusText.anchor.set(0.5, 0.5);
hpBonusText.y = 0;
hpBonusText.alpha = 0;
LK.gui.center.addChild(hpBonusText);
tween(hpBonusText, {
alpha: 1,
y: 50
}, {
duration: 300,
onFinish: function onFinish() {
tween(hpBonusText, {
alpha: 0
}, {
duration: 500,
delay: 800,
onFinish: function onFinish() {
hpBonusText.destroy();
}
});
}
});
tween(stageUpText, {
alpha: 0
}, {
duration: 500,
delay: 1000,
onFinish: function onFinish() {
stageUpText.destroy();
}
});
}
});
}
// 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 = 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];
// Apply game speed to projectile movement
var oldVelX = projectile.velocityX;
var oldVelY = projectile.velocityY;
projectile.velocityX *= gameSpeed;
projectile.velocityY *= gameSpeed;
if (projectile.update() || projectile.y > 2732 + 50) {
projectile.destroy();
projectiles.splice(i, 1);
continue;
}
projectile.velocityX = oldVelX;
projectile.velocityY = oldVelY;
// 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 critMessages = ['CRITICAL!', 'DEVASTATING!', 'CRUSHING HIT!', 'POWER STRIKE!', 'LUCY POWER!', 'MEGA HIT!', 'BRUTAL!', 'DESTRUCTION!', 'OBLITERATE!', 'ANNIHILATE!', 'DEMOLISH!', 'SAVAGE!'];
var critMessage = critMessages[Math.floor(Math.random() * critMessages.length)];
var critText = new Text2(critMessage, {
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);
achievementProgress.bombExpert++;
if (achievementProgress.bombExpert >= 10) checkAchievement('bombExpert');
// Collect all balls that need explosion damage
var ballsToExplode = [];
// Check all balls for explosion damage
for (var k = 0; k < balls.length; k++) {
var nearbyBall = balls[k];
if (checkCollision(bombBall, nearbyBall, 200, nearbyBall.radius)) {
ballsToExplode.push(nearbyBall);
}
}
// Now apply damage to all marked balls
for (var be = 0; be < ballsToExplode.length; be++) {
var explodeBall = ballsToExplode[be];
// Apply up to 3 damage
for (var d = 0; d < 3; d++) {
if (explodeBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier * 2));
createExplosion(explodeBall.x, explodeBall.y, 0xffff00, 20);
explodeBall.destroy();
// Find and remove from balls array
var ballIndex = balls.indexOf(explodeBall);
if (ballIndex !== -1) {
balls.splice(ballIndex, 1);
}
break;
}
}
}
// Remove the bomb ball
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') {
// Create explosion effect at impact point
createExplosion(ball.x, ball.y, 0xff4444, 30);
LK.effects.flashScreen(0xff4444, 200);
// Collect all balls that need to be destroyed
var ballsToDestroy = [];
// Check all balls for explosion damage
for (var k = 0; k < balls.length; k++) {
var otherBall = balls[k];
if (checkCollision(ball, otherBall, 150, otherBall.radius)) {
// Store reference to ball that needs destruction
ballsToDestroy.push(otherBall);
}
}
// Now destroy all marked balls
for (var bd = 0; bd < ballsToDestroy.length; bd++) {
var destroyBall = ballsToDestroy[bd];
// Apply damage
if (destroyBall.takeDamage()) {
LK.getSound('destroy').play();
LK.setScore(LK.getScore() + Math.floor(stage * scoreMultiplier));
createExplosion(destroyBall.x, destroyBall.y, 0xffff00, 15);
destroyBall.destroy();
// Find and remove from balls array
var ballIndex = balls.indexOf(destroyBall);
if (ballIndex !== -1) {
balls.splice(ballIndex, 1);
}
}
}
// Remove the projectile
projectile.destroy();
projectiles.splice(i, 1);
i--;
break;
}
// Skip the regular ball damage check for explosive projectiles
if (projectile.type !== 'explosive' && 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;
}
// 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 luckyMessages = ['LUCKY SHOT!', 'LONG RANGE!', 'SNIPER SHOT!', 'DISTANCE MASTER!', 'FAR SHOT!', 'SHARPSHOOTER!', 'EAGLE STRIKE!', 'REACH SHOT!', 'LUCY SPECIAL!', 'MIRACLE SHOT!', 'IMPOSSIBLE!', 'UNREAL SHOT!'];
var luckyMessage = luckyMessages[Math.floor(Math.random() * luckyMessages.length)];
var luckyText = new Text2(luckyMessage, {
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') {
break;
}
}
}
if (hitBall) {
// Perfect shot bonus
if (consecutiveHits >= 10 && consecutiveHits % 5 === 0) {
var perfectBonus = 100 * scoreMultiplier;
LK.setScore(LK.getScore() + perfectBonus);
var shotMessages = ['PERFECT SHOT!', 'LUCY SHOT!', 'MASTER SHOT!', 'DIVINE SHOT!', 'FLAWLESS!', 'PRECISION!', 'BULLSEYE!', 'SHARP SHOOTER!', 'SNIPER!', 'EAGLE EYE!', 'DEAD CENTER!', 'PINPOINT!'];
var selectedMessage = shotMessages[Math.floor(Math.random() * shotMessages.length)];
var perfectText = new Text2(selectedMessage + ' +' + 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 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', 'split', 'laser', 'lightning'];
var randomWeapon = weapons[Math.floor(Math.random() * weapons.length)];
switch (randomWeapon) {
case 'fireball':
fireballActive = 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;
// Increase MaxHP by 20 after each stage
maxHP += 20;
hp += 20; // Also increase current HP by 20
hpText.setText('HP: ' + hp);
// 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() {
// Show MaxHP increase notification
var hpBonusText = new Text2('Max HP +20!', {
size: 80,
fill: 0xff3366
});
hpBonusText.anchor.set(0.5, 0.5);
hpBonusText.y = -100;
hpBonusText.alpha = 0;
LK.gui.center.addChild(hpBonusText);
tween(hpBonusText, {
alpha: 1,
y: -50
}, {
duration: 300,
onFinish: function onFinish() {
tween(hpBonusText, {
alpha: 0
}, {
duration: 500,
delay: 1000,
onFinish: function onFinish() {
hpBonusText.destroy();
}
});
}
});
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 || 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;
};
// Add music button below achievements
var musicButton = game.addChild(new Container());
var musicBg = musicButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x3498db,
scaleX: 1.2,
scaleY: 1.2
});
var musicText = new Text2('♪', {
size: 40,
fill: 0xFFFFFF
});
musicText.anchor.set(0.5, 0.5);
musicButton.addChild(musicText);
musicButton.x = 1924;
musicButton.y = 300;
// Music button functionality (visual only - LK handles actual music control)
var musicEnabled = true;
musicButton.down = function () {
musicEnabled = !musicEnabled;
if (musicEnabled) {
// Resume music
LK.playMusic('bgmusic');
musicBg.tint = 0x3498db;
musicText.setText('♪');
musicText.alpha = 1;
} else {
// Stop music
LK.stopMusic();
musicBg.tint = 0x7f8c8d;
musicText.setText('♪');
musicText.alpha = 0.5;
}
tween(musicButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(musicButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100
});
}
});
};
// Achievement panel
var achievementPanel = new Container();
var panelBg = achievementPanel.attachAsset('achievementPanelBg', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.95,
scaleX: 1.4,
scaleY: 1.4
});
achievementPanel.visible = false;
LK.gui.center.addChild(achievementPanel);
var achievementTitle = new Text2('ACHIEVEMENTS', {
size: 84,
fill: 0xFFD700
});
achievementTitle.anchor.set(0.5, 0.5);
achievementTitle.y = -840;
achievementPanel.addChild(achievementTitle);
var closeButton = new Container();
var closeBg = closeButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff4444,
scaleX: 1.4,
scaleY: 1.4
});
var closeText = new Text2('X', {
size: 56,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = 630;
closeButton.y = -840;
achievementPanel.addChild(closeButton);
closeButton.down = function () {
achievementPanel.visible = false;
gameActive = true;
};
achievementsButton.down = function () {
achievementPanel.visible = true;
gameActive = false;
updateAchievementDisplay();
};
// Add reset button to bottom right
var resetButton = new Container();
var resetBg = resetButton.attachAsset('addBallButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff4444,
scaleX: 1.2,
scaleY: 1.2
});
var resetText = new Text2('Reset', {
size: 35,
fill: 0xFFFFFF
});
resetText.anchor.set(0.5, 0.5);
resetButton.addChild(resetText);
resetButton.x = -120;
resetButton.y = -120;
LK.gui.bottomRight.addChild(resetButton);
resetButton.down = function () {
// Clear all saved data
storage['99balls_save'] = {};
savedData = {};
// Reset all achievements
for (var key in achievements) {
achievements[key] = false;
}
// Reset all achievement progress
for (var key in achievementProgress) {
achievementProgress[key] = 0;
}
// Reset game state
LK.setScore(0);
stage = 1;
ballSpeed = 0.5;
projectileCount = 1;
maxHP = 20;
hp = maxHP;
combo = 0;
comboTimer = 0;
scoreMultiplier = 1;
ballsDestroyed = 0;
perfectHits = 0;
missedShots = 0;
powerupsCollected = 0;
maxCombo = 0;
timePlayed = 0;
// Reset weapon unlocks
weaponUnlocks.piercing = false;
weaponUnlocks.explosive = false;
weaponUnlocks.rapid = false;
currentWeapon = 'normal';
// Reset all power-up states
slowMotionActive = false;
slowMotionTimer = 0;
gameSpeed = 1;
magnetActive = false;
magnetTimer = 0;
multiballActive = false;
fireballActive = false;
splitBallActive = false;
laserActive = false;
shieldActive = false;
shieldTimer = 0;
doubleShotActive = false;
doubleShotTimer = 0;
lightningActive = false;
freezeActive = false;
freezeTimer = 0;
reverseGravityActive = false;
reverseGravityTimer = 0;
scoreBoostActive = false;
scoreBoostTimer = 0;
scoreBoostMultiplier = 1;
autoAimActive = false;
autoAimTimer = 0;
freezeBombActive = false;
chainReactionBombActive = false;
teleportActive = false;
chainReactionActive = false;
consecutiveHits = 0;
perfectStageBonus = false;
// Update UI
hpText.setText('HP: ' + hp);
stageText.setText('Stage 1');
projectileCountText.setText('x1');
scoreText.setText('Score: 0');
weaponText.setText('Normal');
weaponText.tint = 0xFFFFFF;
powerUpIndicator.setText('');
doubleShotIndicator.setText('');
comboText.setText('');
comboText.alpha = 0;
amazingText.setText('');
amazingText.alpha = 0;
ballsLeftText.setText('Balls Left: 0');
// Remove high score text if exists
if (LK.gui.topRight.children.length > 1) {
LK.gui.topRight.children[1].destroy();
}
// Show reset notification
var resetNotification = new Text2('All Progress Reset!', {
size: 100,
fill: 0xff4444
});
resetNotification.anchor.set(0.5, 0.5);
resetNotification.alpha = 0;
LK.gui.center.addChild(resetNotification);
tween(resetNotification, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
onFinish: function onFinish() {
tween(resetNotification, {
alpha: 0
}, {
duration: 500,
delay: 1000,
onFinish: function onFinish() {
resetNotification.destroy();
}
});
}
});
// Flash effect
LK.effects.flashScreen(0xff4444, 500);
// Restart the game
LK.showGameOver();
};
// 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