User prompt
Add a new feature: Krusty Burger! Unlock weapons using the gold you obtain from games! (Weapons: Slingshot: The Default Weapon; Dart gun: Deals high damage but has a slow fire rate; Ducky Triple barrel: shoots 3 strong projectiles like if you had a shotgun; Krusty's flower flower: A water beam that deals low damage every 0.10 seconds)
User prompt
Add a title screen into the game
User prompt
Add a title screen into the game
User prompt
Now there are INFINITE waves
User prompt
Now there's 2 different sounds for collecting powerups and collecting coins
User prompt
Aliens are now invincible for the first 3 seconds of their lifetime to prevent cheesing the game ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make it 2567 pixels
User prompt
Shooter mutant should have a higher range...
User prompt
Add new Enemies: Fast mutant (a mutant that is faster than any other mutant but is fragile: starts spawning at wave 2 alongside all other enemies that appear), Shooter mutant (shoots bowling balls st Bart! That's a bowling problem! Starts appearing at wave 7)
User prompt
Add 15 more waves!
User prompt
Bart now says the hut sound effect when hit
Code edit (1 edits merged)
Please save this source code
User prompt
Bart vs the Space Mutants
Initial prompt
Bart vs the space mutants: an RPG game where Bart Simpson goes on a mission to stop the space mutants, kind of like the NES game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AlienMeal = Container.expand(function () { var self = Container.call(this); var mealGraphics = self.attachAsset('alien_meal', { anchorX: 0.5, anchorY: 0.5 }); self.invincibilityDuration = 600; // 10 seconds at 60fps self.checkRadius = 80; self.lifetime = 600; // 10 seconds self.consumed = false; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } // Pulsing effect to show it's active mealGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.2) * 0.3; // Check for non-cook mutants touching the meal if (!self.consumed) { for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; // Skip cook mutants - they can't consume their own meals if (enemy instanceof CookMutant) continue; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.checkRadius) { // Give invincibility to this enemy enemy.invincible = true; enemy.invincibilityTimer = self.invincibilityDuration; // Visual effect for invincibility gain LK.effects.flashObject(enemy, 0x00FFFF, 500); tween(enemy, { tint: 0x00FFFF }, { duration: 200, easing: tween.easeOut }); tween(enemy, { tint: 0xFFFFFF }, { duration: 200, easing: tween.easeIn }); // Mark meal as consumed self.consumed = true; self.shouldDestroy = true; return; } } } }; return self; }); var Bart = Container.expand(function () { var self = Container.call(this); var bartGraphics = self.attachAsset('bart_slingshot', { anchorX: 0.5, anchorY: 0.5 }); self.bartGraphics = bartGraphics; self.currentWeapon = 'slingshot'; self.updateWeaponVisual = function (weaponId) { if (self.currentWeapon === weaponId) return; self.currentWeapon = weaponId; var oldGraphics = self.bartGraphics; var newGraphics = self.attachAsset('bart_' + weaponId, { anchorX: 0.5, anchorY: 0.5 }); newGraphics.x = oldGraphics.x; newGraphics.y = oldGraphics.y; newGraphics.rotation = oldGraphics.rotation; newGraphics.alpha = oldGraphics.alpha; newGraphics.scaleX = oldGraphics.scaleX; newGraphics.scaleY = oldGraphics.scaleY; self.removeChild(oldGraphics); self.bartGraphics = newGraphics; }; self.maxHealth = 100; self.health = self.maxHealth; self.level = 1; self.xp = 0; self.xpToNext = 100; self.damage = 10; self.fireRate = 30; self.fireTimer = 0; self.coins = 0; self.stunned = false; self.stunnedTimer = 0; self.takeDamage = function (damage) { self.health -= damage; LK.getSound('hut').play(); LK.effects.flashObject(self, 0xFF0000, 500); if (healthBarFill) { healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth); } if (self.health <= 0) { try { storage.coins = self.coins; } catch (e) { console.log('Could not save coins on game over:', e); } LK.showGameOver(); } }; self.gainXP = function (amount) { self.xp += amount; while (self.xp >= self.xpToNext) { self.xp -= self.xpToNext; self.level++; self.xpToNext = self.level * 100; self.maxHealth += 20; self.health = self.maxHealth; if (healthBarFill) { healthBarFill.scaleX = 1; } self.damage += 5; self.fireRate = Math.max(10, self.fireRate - 2); LK.getSound('levelup').play(); LK.effects.flashScreen(0xFFFF00, 300); } }; self.update = function () { if (self.stunned) { self.stunnedTimer--; if (self.stunnedTimer <= 0) { self.stunned = false; } } self.fireTimer--; }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 500; self.health = self.maxHealth; self.speed = 1; self.xpValue = 100; self.coinChance = 1; self.powerupChance = 0.5; self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps var healthBarBg = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, y: -100 }); self.healthBarFill = self.attachAsset('healthbar_fill', { anchorX: 0, anchorY: 0.5, x: -100, y: -100 }); self.takeDamage = function (damage) { if (self.invincible) return; // No damage during invincibility self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; bossGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; bossGraphics.alpha = 1; // Reset to full opacity } } if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } }; return self; }); var BowlingBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('bowling_ball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 15; self.targetX = 0; self.targetY = 0; self.directionSet = false; self.velocityX = 0; self.velocityY = 0; self.lifetime = 180; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (!self.directionSet) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.velocityX = dx / dist * self.speed; self.velocityY = dy / dist * self.speed; } self.directionSet = true; } self.x += self.velocityX; self.y += self.velocityY; self.rotation += 0.2; }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 10; self.speed = 15; self.target = null; self.lifetime = 60; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } else { self.y -= self.speed; } }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.value = 5; self.lifetime = 300; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; } self.rotation += 0.05; }; return self; }); var Concert = Container.expand(function () { var self = Container.call(this); var concertGraphics = self.attachAsset('concert', { anchorX: 0.5, anchorY: 0.5 }); // Band members self.drummer = self.attachAsset('drummer', { anchorX: 0.5, anchorY: 0.5, x: -250, y: -100 }); self.vocal = self.attachAsset('vocal', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -120 }); self.rocker = self.attachAsset('rocker', { anchorX: 0.5, anchorY: 0.5, x: 250, y: -100 }); self.maxHealth = 25750; self.health = self.maxHealth; self.speed = 0; // Cannot move self.xpValue = 2500; self.coinChance = 1; self.powerupChance = 1; self.isInstantKillBoss = true; // Special flag to not destroy on contact // Timers for abilities self.drummerTimer = 225; // 3.75 seconds self.swearTimer = 600; // 10 seconds self.rockMusicTimer = 300; // 5 seconds self.damageMultiplier = 1.0; // Starts at 100% damage self.maxDamageMultiplier = 1.9; // Max 190% (90% increase) // Regular mutant spawn timer self.regularSpawnTimer = 120; // 2 seconds // New attack timers self.noisyDrummingTimer = 600; // 10 seconds self.risingRockstarsTimer = 900; // 15 seconds self.stereoSoundsTimer = 3600; // 60 seconds // Health bar var healthBarBg = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, y: -350, scaleX: 2 }); self.healthBarFill = self.attachAsset('healthbar_fill', { anchorX: 0, anchorY: 0.5, x: -200, y: -350, scaleX: 2 }); self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth) * 2; if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); // Drop tons of coins for (var i = 0; i < 30; i++) { spawnItem(self.x + (Math.random() - 0.5) * 400, self.y + (Math.random() - 0.5) * 300, 'coin'); } } }; self.update = function () { // Update timers self.drummerTimer--; self.swearTimer--; self.rockMusicTimer--; self.regularSpawnTimer--; self.noisyDrummingTimer--; self.risingRockstarsTimer--; self.stereoSoundsTimer--; // Excessive Drumming - shoot 3 soundwaves in spread if (self.drummerTimer <= 0 && bart) { for (var i = -1; i <= 1; i++) { var soundWave = new SoundWave(); soundWave.x = self.x + self.drummer.x; soundWave.y = self.y + self.drummer.y; // Calculate spread angle var angle = Math.atan2(bart.y - soundWave.y, bart.x - soundWave.x); angle += i * 0.3; // 0.3 radians spread soundWave.targetX = soundWave.x + Math.cos(angle) * 1000; soundWave.targetY = soundWave.y + Math.sin(angle) * 1000; soundWave.damage = 15 * self.damageMultiplier; // Slightly more damage than regular enemyProjectiles.push(soundWave); game.addChild(soundWave); } self.drummerTimer = 225; // Reset to 3.75 seconds LK.effects.flashObject(self.drummer, 0xFF00FF, 500); // Drummer animation tween(self.drummer, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut }); tween(self.drummer, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } // Noisy Drumming - shoot 10 sound waves really fast if (self.noisyDrummingTimer <= 0 && bart) { for (var i = 0; i < 10; i++) { // Delay each sound wave slightly for rapid fire effect LK.setTimeout(function (index) { return function () { if (bart && !self.destroyed) { var soundWave = new SoundWave(); soundWave.x = self.x + self.drummer.x; soundWave.y = self.y + self.drummer.y; // Random spread pattern var angle = Math.atan2(bart.y - soundWave.y, bart.x - soundWave.x); angle += (Math.random() - 0.5) * 0.8; // Random spread soundWave.targetX = soundWave.x + Math.cos(angle) * 1000; soundWave.targetY = soundWave.y + Math.sin(angle) * 1000; soundWave.damage = 20 * self.damageMultiplier; // More damage soundWave.speed = 10; // Faster enemyProjectiles.push(soundWave); game.addChild(soundWave); LK.effects.flashObject(self.drummer, 0xFFFF00, 100); } }; }(i), i * 100); // 100ms between each wave } self.noisyDrummingTimer = 600; // Reset to 10 seconds } // Swear-fest - increase damage multiplier if (self.swearTimer <= 0) { if (self.damageMultiplier < self.maxDamageMultiplier) { self.damageMultiplier += 0.15; // 15% increase self.damageMultiplier = Math.min(self.damageMultiplier, self.maxDamageMultiplier); } self.swearTimer = 600; // Reset to 10 seconds LK.effects.flashScreen(0xFF0000, 300); LK.effects.flashObject(self.vocal, 0xFF0000, 1000); // Vocal animation tween(self.vocal, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut }); tween(self.vocal, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeIn }); // Update all enemies' damage for (var i = 0; i < enemies.length; i++) { if (enemies[i] !== self) { enemies[i].damageMultiplier = self.damageMultiplier; } } } // Rock Music - make all mutants faster if (self.rockMusicTimer <= 0) { for (var i = 0; i < enemies.length; i++) { if (enemies[i] !== self && !enemies[i].rockerBoosted) { enemies[i].originalSpeed = enemies[i].speed; enemies[i].speed *= 1.3; // 30% speed boost enemies[i].rockerBoosted = true; enemies[i].rockerBoostTimer = 300; // 5 seconds LK.effects.flashObject(enemies[i], 0x00FF00, 500); } } self.rockMusicTimer = 300; // Reset to 5 seconds LK.effects.flashObject(self.rocker, 0x00FF00, 1000); // Rocker animation tween(self.rocker, { scaleX: 1.4, scaleY: 1.4, rotation: 0.3 }, { duration: 250, easing: tween.easeOut }); tween(self.rocker, { scaleX: 1, scaleY: 1, rotation: 0 }, { duration: 250, easing: tween.easeIn }); } // Rising Rockstars - summon band member mutants if (self.risingRockstarsTimer <= 0) { // Spawn Drummer Mutant var drummer = new DrummerMutant(); drummer.x = self.x - 300; drummer.y = self.y + 300; drummer.invincible = false; drummer.invincibilityTimer = 0; drummer.damageMultiplier = self.damageMultiplier; enemies.push(drummer); game.addChild(drummer); // Spawn Vocal Mutant var vocal = new VocalMutant(); vocal.x = self.x; vocal.y = self.y + 350; vocal.invincible = false; vocal.invincibilityTimer = 0; vocal.damageMultiplier = self.damageMultiplier; enemies.push(vocal); game.addChild(vocal); // Spawn Rocker Mutant var rocker = new RockerMutant(); rocker.x = self.x + 300; rocker.y = self.y + 300; rocker.invincible = false; rocker.invincibilityTimer = 0; rocker.damageMultiplier = self.damageMultiplier; enemies.push(rocker); game.addChild(rocker); self.risingRockstarsTimer = 900; // Reset to 15 seconds LK.effects.flashScreen(0xFF00FF, 500); // Animation for summoning tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut }); tween(self, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeIn }); } // Rock fans - spawn regular mutants continuously if (self.regularSpawnTimer <= 0) { var mutant = new Mutant(); mutant.x = self.x + (Math.random() - 0.5) * 600; mutant.y = self.y + 200; // Apply current damage multiplier mutant.damageMultiplier = self.damageMultiplier; // Scale mutant stats based on wave mutant.speed = 2 + wave * 0.3; mutant.maxHealth = 30 + wave * 15; mutant.health = mutant.maxHealth; mutant.xpValue = 10 + wave * 2; mutant.invincible = false; mutant.invincibilityTimer = 0; enemies.push(mutant); game.addChild(mutant); self.regularSpawnTimer = 120; // Reset to 2 seconds } // Handle rocker boost timers for all enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i].rockerBoosted && enemies[i].rockerBoostTimer) { enemies[i].rockerBoostTimer--; if (enemies[i].rockerBoostTimer <= 0) { enemies[i].speed = enemies[i].originalSpeed; enemies[i].rockerBoosted = false; } } } // Stereo Sounds - all band members shoot homing instakill soundwaves if (self.stereoSoundsTimer <= 0 && bart) { // Warning flash LK.effects.flashScreen(0xFF0000, 1000); // Drummer shoots homing soundwave var drummerWave = new SoundWave(); drummerWave.x = self.x + self.drummer.x; drummerWave.y = self.y + self.drummer.y; drummerWave.damage = 9999; // Instakill drummerWave.speed = 4; // Slower but homing drummerWave.isHoming = true; // Mark as homing drummerWave.target = bart; enemyProjectiles.push(drummerWave); game.addChild(drummerWave); // Vocal shoots homing soundwave var vocalWave = new SoundWave(); vocalWave.x = self.x + self.vocal.x; vocalWave.y = self.y + self.vocal.y; vocalWave.damage = 9999; // Instakill vocalWave.speed = 4; // Slower but homing vocalWave.isHoming = true; // Mark as homing vocalWave.target = bart; enemyProjectiles.push(vocalWave); game.addChild(vocalWave); // Rocker shoots homing soundwave var rockerWave = new SoundWave(); rockerWave.x = self.x + self.rocker.x; rockerWave.y = self.y + self.rocker.y; rockerWave.damage = 9999; // Instakill rockerWave.speed = 4; // Slower but homing rockerWave.isHoming = true; // Mark as homing rockerWave.target = bart; enemyProjectiles.push(rockerWave); game.addChild(rockerWave); self.stereoSoundsTimer = 3600; // Reset to 60 seconds // Epic animation for all band members tween(self.drummer, { scaleX: 2, scaleY: 2, tint: 0xFF0000 }, { duration: 500, easing: tween.easeOut }); tween(self.vocal, { scaleX: 2, scaleY: 2, tint: 0xFF0000 }, { duration: 500, easing: tween.easeOut }); tween(self.rocker, { scaleX: 2, scaleY: 2, tint: 0xFF0000 }, { duration: 500, easing: tween.easeOut }); // Reset after animation tween(self.drummer, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 500, easing: tween.easeIn }); tween(self.vocal, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 500, easing: tween.easeIn }); tween(self.rocker, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 500, easing: tween.easeIn }); } // Pulsing effect for band members self.drummer.y = -100 + Math.sin(LK.ticks * 0.1) * 10; self.vocal.y = -120 + Math.sin(LK.ticks * 0.15) * 8; self.rocker.y = -100 + Math.sin(LK.ticks * 0.12) * 12; }; return self; }); var CookMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('cook_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 60; self.health = self.maxHealth; self.speed = 1.5; self.xpValue = 30; self.coinChance = 0.5; self.powerupChance = 0.2; self.cookTimer = 0; self.cookInterval = 240; // 4 seconds self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps self.takeDamage = function (damage) { if (self.invincible) return; // No damage during invincibility self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; // Reset to full opacity } } self.cookTimer--; if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Cook alien meals when close to other enemies if (self.cookTimer <= 0) { var nearbyEnemies = []; for (var i = 0; i < enemies.length; i++) { if (enemies[i] !== self) { var eDx = enemies[i].x - self.x; var eDy = enemies[i].y - self.y; var eDist = Math.sqrt(eDx * eDx + eDy * eDy); if (eDist < 300) { nearbyEnemies.push(enemies[i]); } } } if (nearbyEnemies.length > 0) { // Create an alien meal var meal = new AlienMeal(); meal.x = self.x + (Math.random() - 0.5) * 100; meal.y = self.y + (Math.random() - 0.5) * 100; alienMeals.push(meal); game.addChild(meal); self.cookTimer = self.cookInterval; LK.effects.flashObject(self, 0x00FF00, 300); } } } }; return self; }); var Dart = Container.expand(function () { var self = Container.call(this); var dartGraphics = self.attachAsset('dart', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 10; self.speed = 20; self.target = null; self.lifetime = 60; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; self.rotation = Math.atan2(dy, dx) + Math.PI / 2; // Point towards target } } else { self.y -= self.speed; } }; return self; }); var DrummerMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('drummer_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 150; self.health = self.maxHealth; self.speed = 0.8; self.xpValue = 45; self.coinChance = 0.6; self.powerupChance = 0.3; self.shootTimer = 0; self.shootInterval = 90; // 1.5 seconds base self.invincible = true; self.invincibilityTimer = 180; self.takeDamage = function (damage) { if (self.invincible) return; self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; } } self.shootTimer--; // Check if Vocal is on screen to double attack speed var vocalOnScreen = false; for (var i = 0; i < enemies.length; i++) { if (enemies[i] instanceof VocalMutant && enemies[i] !== self) { vocalOnScreen = true; break; } } var currentInterval = vocalOnScreen ? self.shootInterval / 2 : self.shootInterval; if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Shoot sound waves at Bart (infinite range) if (self.shootTimer <= 0) { var soundWave = new SoundWave(); soundWave.x = self.x; soundWave.y = self.y; soundWave.targetX = bart.x; soundWave.targetY = bart.y; enemyProjectiles.push(soundWave); game.addChild(soundWave); self.shootTimer = currentInterval; // Visual effect when shooting LK.effects.flashObject(self, 0xFF00FF, 300); } } }; return self; }); var Encyclopedia = Container.expand(function () { var self = Container.call(this); // Background var bg = self.attachAsset('encyclopedia', { anchorX: 0.5, anchorY: 0.5 }); // Title self.titleText = new Text2('ENCYCLOPEDIA', { size: 80, fill: 0xFFFF00 }); self.titleText.anchor.set(0.5, 0.5); self.titleText.y = -300; self.addChild(self.titleText); // Page content container self.pageContainer = new Container(); self.addChild(self.pageContainer); // Close button var closeButton = self.attachAsset('info_button', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 350 }); var closeText = new Text2('CLOSE', { size: 40, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeText.y = 350; self.addChild(closeText); // Navigation buttons var prevButton = self.attachAsset('info_button', { anchorX: 0.5, anchorY: 0.5, x: -200, y: 280, scaleX: 0.8 }); var prevText = new Text2('< PREV', { size: 35, fill: 0xFFFFFF }); prevText.anchor.set(0.5, 0.5); prevText.x = -200; prevText.y = 280; self.addChild(prevText); var nextButton = self.attachAsset('info_button', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 280, scaleX: 0.8 }); var nextText = new Text2('NEXT >', { size: 35, fill: 0xFFFFFF }); nextText.anchor.set(0.5, 0.5); nextText.x = 200; nextText.y = 280; self.addChild(nextText); // Page indicator self.pageIndicator = new Text2('Page 1/1', { size: 30, fill: 0xAAAAAA }); self.pageIndicator.anchor.set(0.5, 0.5); self.pageIndicator.y = 320; self.addChild(self.pageIndicator); self.currentPage = 0; self.pages = []; // Initialize encyclopedia content self.initializePages = function () { self.pages = [ // Enemies { title: "MUTANT", content: "Basic enemy that moves towards Bart.\nHealth: 30 + (wave × 15)\nSpeed: 2 + (wave × 0.3)\nXP Value: 10 + (wave × 2)\nAppears from: Wave 1" }, { title: "FAST MUTANT", content: "Quick enemy that rushes at Bart.\nHealth: 15 + (wave × 8)\nSpeed: 4 + (wave × 0.4)\nXP Value: 15 + (wave × 2)\nAppears from: Wave 2" }, { title: "SHOOTER MUTANT", content: "Fires bowling balls at Bart.\nHealth: 50 + (wave × 10)\nSpeed: 1.5 + (wave × 0.2)\nXP Value: 25 + (wave × 3)\nAppears from: Wave 7" }, { title: "COOK MUTANT", content: "Creates alien meals that grant invincibility.\nHealth: 60 + (wave × 10)\nSpeed: 1.5 + (wave × 0.2)\nXP Value: 30 + (wave × 4)\nAppears from: Wave 6" }, { title: "POET MUTANT", content: "Summons other mutants to help!\nHealth: 80 + (wave × 12)\nSpeed: 1 + (wave × 0.15)\nXP Value: 40 + (wave × 5)\nAppears from: Wave 8" }, { title: "SAMURAI MUTANT", content: "Has a spinning katana that reflects projectiles.\nHealth: 100 + (wave × 15)\nSpeed: 1.2 + (wave × 0.2)\nXP Value: 50 + (wave × 6)\nAppears from: Wave 8" }, { title: "DRUMMER MUTANT", content: "High HP, shoots sound waves. Attack speed doubles if Vocal is present.\nHealth: 150 + (wave × 20)\nSpeed: 0.8 + (wave × 0.1)\nXP Value: 45 + (wave × 5)\nAppears from: Wave 13" }, { title: "VOCAL MUTANT", content: "Fast with low HP. Damage doubles if Rocker is present.\nHealth: 40 + (wave × 10)\nSpeed: 5 + (wave × 0.5)\nXP Value: 35 + (wave × 4)\nAppears from: Wave 13" }, { title: "ROCKER MUTANT", content: "Boosts ally speed for 5 seconds. Enhanced boost if Drummer is present.\nHealth: 70 + (wave × 15)\nSpeed: 2.5 + (wave × 0.3)\nXP Value: 40 + (wave × 5)\nAppears from: Wave 13" }, { title: "BOSS", content: "Powerful enemy that appears every 5 waves.\nHealth: 500 + ((wave-5) × 200)\nSpeed: 1 + (wave × 0.1)\nXP Value: 100 + (wave × 20)\nAppears: Waves 5, 10, 15, 20..." }, // Weapons { title: "SLINGSHOT", content: "The default weapon.\nDamage: 10\nFire Rate: Medium\nProjectiles: 1\nCost: FREE (Starting weapon)" }, { title: "DART GUN", content: "High damage, slow fire rate.\nDamage: 50\nFire Rate: Slow\nProjectiles: 1\nCost: 100 coins" }, { title: "SCATTERSHOT", content: "Shoots peanuts that split.\nDamage: 15 (5 per split)\nFire Rate: Medium-Slow\nProjectiles: 1→3\nCost: 250 coins" }, { title: "DUCKY TRIPLE", content: "Shoots 3 projectiles in a spread.\nDamage: 25\nFire Rate: Medium\nProjectiles: 3\nCost: 500 coins" }, { title: "SPRAYCAN", content: "Stuns enemies on hit.\nDamage: 8\nFire Rate: Slow\nStun: 1.2 seconds\nCost: 750 coins" }, { title: "KRUSTY'S FLOWER", content: "Water beam with rapid fire.\nDamage: 3\nFire Rate: Very Fast\nProjectiles: 1 (continuous)\nCost: 1000 coins" }, { title: "TOY BOW", content: "Bart is now armed with a bow! Lower damage but 100% more XP.\nDamage: 12\nFire Rate: Medium-Fast\nSpecial: Double XP from all enemies\nCost: 600 coins" }, { title: "POT-A-BOMB", content: "Bart holds a pot! Area damage with explosive potential.\nDamage: 35 (area effect)\nFire Rate: Slow\nSpecial: 30% chance to split into 4 diagonal shards\nCost: 800 coins" }, // Subweapons { title: "SANTA'S LITTLE HELPER", content: "Fast ally that bites enemies.\nDamage: 15 per bite\nSpeed: 12\nSight Range: 800 pixels\nCost: 750 coins" }, { title: "KRUSTY BURGER SHOP", content: "Spawns powerups periodically.\nSpawn Rate: Every 15 seconds\nPowerup Types: Damage/Fire Rate\nCost: 1200 coins" }, { title: "SNOWBALL II", content: "Sneaky cat that distracts enemies.\nDistraction Range: 600 pixels\nReduces invincibility by 50%\nSpeed: 8\nCost: 900 coins" }, // Game Features { title: "POWER-UPS", content: "Dropped by enemies randomly.\n• Damage Boost: +5 damage\n• Fire Rate: -5 fire rate delay\nDrop chance varies by enemy type." }, { title: "COINS", content: "Currency for buying weapons.\nValue: 5 coins each\nDropped by defeated enemies.\nCoins are saved between games!" }, { title: "ALIEN MEALS", content: "Created by Cook Mutants.\nGrants 10 seconds invincibility.\nCan be destroyed by shooting.\nOnly non-cook mutants can consume." }, { title: "INVINCIBILITY", content: "Enemy spawn protection:\n• Waves 1-9: 3 seconds\n• Waves 10-14: 1.5 seconds\n• Wave 15+: No invincibility" }, { title: "LEVELING SYSTEM", content: "Gain XP from defeating enemies.\nEach level grants:\n• +20 max health\n• +5 damage\n• -2 fire rate delay\nFull heal on level up!" }, { title: "WAVE PROGRESSION", content: "Infinite waves with scaling difficulty.\nBosses appear every 5 waves.\nEnemies get stronger each wave.\nNew enemy types unlock at higher waves." }]; }; self.showPage = function (pageIndex) { // Clear previous content self.pageContainer.removeChildren(); if (pageIndex >= 0 && pageIndex < self.pages.length) { var page = self.pages[pageIndex]; // Page title var pageTitle = new Text2(page.title, { size: 60, fill: 0x00FFFF }); pageTitle.anchor.set(0.5, 0.5); pageTitle.y = -200; self.pageContainer.addChild(pageTitle); // Page content var lines = page.content.split('\n'); var yOffset = -100; for (var i = 0; i < lines.length; i++) { var contentLine = new Text2(lines[i], { size: 35, fill: 0xFFFFFF }); contentLine.anchor.set(0.5, 0.5); contentLine.y = yOffset; self.pageContainer.addChild(contentLine); yOffset += 45; } self.currentPage = pageIndex; self.pageIndicator.setText('Page ' + (pageIndex + 1) + '/' + self.pages.length); } }; self.nextPage = function () { if (self.currentPage < self.pages.length - 1) { self.showPage(self.currentPage + 1); } }; self.prevPage = function () { if (self.currentPage > 0) { self.showPage(self.currentPage - 1); } }; self.initializePages(); self.showPage(0); return self; }); var FastMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('fast_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 15; self.health = self.maxHealth; self.speed = 4; self.xpValue = 15; self.coinChance = 0.2; self.powerupChance = 0.05; self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps self.takeDamage = function (damage) { if (self.invincible) return; // No damage during invincibility self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { // Handle sleep effect if (self.sleeping) { self.sleepTimer--; if (self.sleepTimer <= 0) { self.sleeping = false; self.speed = self.originalSpeed; tween(self, { alpha: 1 }, { duration: 200, easing: tween.easeIn }); } return; // Don't move when sleeping } if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; // Reset to full opacity } } var target = self.distractedBy || bart; if (target) { var dx = target.x - self.x; var dy = target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } if (self.distractedBy && dist < 100) { self.distractedBy = null; } } }; return self; }); var FlowerBeam = Container.expand(function () { var self = Container.call(this); var beamGraphics = self.attachAsset('flower_beam', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 10; self.speed = 25; self.target = null; self.lifetime = 60; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; self.rotation = Math.atan2(dy, dx) + Math.PI / 2; // Point towards target } } else { self.y -= self.speed; } }; return self; }); var HorseBetting = Container.expand(function () { var self = Container.call(this); // Game state self.selectedHorse = null; self.raceStarted = false; self.gameOver = false; self.onComplete = null; self.horsePositions = { itchy: 0, scratchy: 0 }; // Title self.titleText = new Text2('HORSE BETTING', { size: 60, fill: 0xFFFFFF }); self.titleText.anchor.set(0.5, 0.5); self.titleText.y = -400; self.addChild(self.titleText); // Instructions self.instructionText = new Text2('Pick a horse to bet on!', { size: 40, fill: 0xAAAAAA }); self.instructionText.anchor.set(0.5, 0.5); self.instructionText.y = -340; self.addChild(self.instructionText); // Betting buttons var itchyButton = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: -200, y: -200, scaleX: 2, scaleY: 2 }); itchyButton.tint = 0xFF6666; var itchyText = new Text2('Bet on Itchy', { size: 40, fill: 0xFFFFFF }); itchyText.anchor.set(0.5, 0.5); itchyText.x = -200; itchyText.y = -200; self.addChild(itchyText); var scratchyButton = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 200, y: -200, scaleX: 2, scaleY: 2 }); scratchyButton.tint = 0x6666FF; var scratchyText = new Text2('Bet on Scratchy', { size: 40, fill: 0xFFFFFF }); scratchyText.anchor.set(0.5, 0.5); scratchyText.x = 200; scratchyText.y = -200; self.addChild(scratchyText); // Track var track = self.attachAsset('horse_track', { anchorX: 0.5, anchorY: 0.5, y: 100 }); // Finish line var finishLine = self.attachAsset('finish_line', { anchorX: 0.5, anchorY: 0.5, x: 600, y: 100 }); // Horses self.itchyHorse = self.attachAsset('horse_itchy', { anchorX: 0.5, anchorY: 0.5, x: -600, y: 50 }); self.scratchyHorse = self.attachAsset('horse_scratchy', { anchorX: 0.5, anchorY: 0.5, x: -600, y: 150 }); // Result text self.resultText = new Text2('', { size: 60, fill: 0xFFD700 }); self.resultText.anchor.set(0.5, 0.5); self.resultText.y = 350; self.addChild(self.resultText); self.selectHorse = function (horse) { if (self.raceStarted || self.gameOver) return; self.selectedHorse = horse; self.instructionText.setText('You bet on ' + (horse === 'itchy' ? 'Itchy' : 'Scratchy') + '!'); // Start race after delay LK.setTimeout(function () { self.startRace(); }, 1000); }; self.startRace = function () { self.raceStarted = true; self.instructionText.setText('They\'re off!'); // Hide betting buttons itchyButton.visible = false; itchyText.visible = false; scratchyButton.visible = false; scratchyText.visible = false; }; self.update = function () { if (!self.raceStarted || self.gameOver) return; // Move horses with random speeds var itchySpeed = 3 + Math.random() * 4; var scratchySpeed = 3 + Math.random() * 4; self.horsePositions.itchy += itchySpeed; self.horsePositions.scratchy += scratchySpeed; self.itchyHorse.x = -600 + self.horsePositions.itchy; self.scratchyHorse.x = -600 + self.horsePositions.scratchy; // Galloping animation self.itchyHorse.y = 50 + Math.sin(LK.ticks * 0.3) * 10; self.scratchyHorse.y = 150 + Math.sin(LK.ticks * 0.3 + 1) * 10; // Check for winner if (self.horsePositions.itchy >= 1200 || self.horsePositions.scratchy >= 1200) { self.gameOver = true; var winner = self.horsePositions.itchy >= 1200 ? 'itchy' : 'scratchy'; if (winner === self.selectedHorse) { self.resultText.setText('You Win! +40 Coins!'); LK.getSound('carnival_win').play(); if (self.onComplete) self.onComplete(true, 40); } else { self.resultText.setText((winner === 'itchy' ? 'Itchy' : 'Scratchy') + ' Wins!'); LK.getSound('carnival_lose').play(); if (self.onComplete) self.onComplete(false, 0); } } }; return self; }); var KrustyShop = Container.expand(function () { var self = Container.call(this); var shopGraphics = self.attachAsset('krusty_shop', { anchorX: 0.5, anchorY: 0.5 }); self.powerupTimer = 900; // 15 seconds at 60fps self.update = function () { self.powerupTimer--; // Pulse effect when close to spawning powerup if (self.powerupTimer < 60) { shopGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.5) * 0.5; } else { shopGraphics.alpha = 1; } if (self.powerupTimer <= 0) { // Spawn powerup spawnItem(self.x, self.y, 'powerup'); self.powerupTimer = 900; // Reset timer LK.effects.flashObject(self, 0xFFFF00, 500); } // Gentle floating animation self.y += Math.sin(LK.ticks * 0.03) * 0.3; }; return self; }); var LeaderBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('leader_bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 90; self.targetX = 0; self.targetY = 0; self.directionSet = false; self.velocityX = 0; self.velocityY = 0; self.lifetime = 180; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (!self.directionSet) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.velocityX = dx / dist * self.speed; self.velocityY = dy / dist * self.speed; } self.directionSet = true; } self.x += self.velocityX; self.y += self.velocityY; self.rotation += 0.15; }; return self; }); var Mutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 30; self.health = self.maxHealth; self.speed = 2; self.xpValue = 10; self.coinChance = 0.3; self.powerupChance = 0.1; self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps self.stunned = false; self.stunnedTimer = 0; self.takeDamage = function (damage, stunDuration) { if (self.invincible) return; // No damage during invincibility self.health -= damage; if (!isLowQualityMode) { LK.effects.flashObject(self, 0xFFFFFF, 200); } if (stunDuration && stunDuration > 0) { self.stunned = true; self.stunnedTimer = stunDuration; } if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { // Handle sleep effect if (self.sleeping) { self.sleepTimer--; if (self.sleepTimer <= 0) { self.sleeping = false; self.speed = self.originalSpeed; tween(self, { alpha: 1 }, { duration: 200, easing: tween.easeIn }); } return; // Don't move when sleeping } if (self.stunned) { self.stunnedTimer--; mutantGraphics.tint = 0x00FF00; // Green tint when stunned if (self.stunnedTimer <= 0) { self.stunned = false; mutantGraphics.tint = 0xFFFFFF; } return; // Don't move when stunned } if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; // Reset to full opacity } } // Check if distracted by Snowball II var target = self.distractedBy || bart; if (target) { var dx = target.x - self.x; var dy = target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Reset distraction after getting close if (self.distractedBy && dist < 100) { self.distractedBy = null; } } }; return self; }); var MutantLeader = Container.expand(function () { var self = Container.call(this); var leaderGraphics = self.attachAsset('mutant_leader', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.maxHealth = 20000; self.health = self.maxHealth; self.speed = 3; self.xpValue = 1000; self.coinChance = 1; self.coinValue = 100; // Drops 100 coins self.powerupChance = 1; self.isInstantKillBoss = true; // Special flag to not destroy on contact self.rageMode = false; self.originalSpeed = self.speed; // Timers for abilities self.callForHelpTimer = 600; // 10 seconds self.gunAttackTimer = 300; // 5 seconds self.whistleTimer = 1200; // 20 seconds // Health bar var healthBarBg = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, y: -150, scaleX: 1.5 }); self.healthBarFill = self.attachAsset('healthbar_fill', { anchorX: 0, anchorY: 0.5, x: -150, y: -150, scaleX: 1.5 }); self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth) * 1.5; if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); // Drop tons of coins for (var i = 0; i < 20; i++) { spawnItem(self.x + (Math.random() - 0.5) * 200, self.y + (Math.random() - 0.5) * 200, 'coin'); } } }; self.update = function () { // Update timers self.callForHelpTimer--; self.gunAttackTimer--; self.whistleTimer--; // Check for rage mode activation at 50% health if (!self.rageMode && self.health <= self.maxHealth / 2) { self.rageMode = true; self.speed = self.originalSpeed * 1.5; // 50% faster LK.effects.flashObject(self, 0xFF0000, 1000); LK.effects.flashScreen(0xFF0000, 500); // Visual effect for rage activation tween(leaderGraphics, { scaleX: 2.5, scaleY: 2.5 }, { duration: 500, easing: tween.easeOut }); tween(leaderGraphics, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeIn }); } if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); // Move towards Bart if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Call for help ability - faster in rage mode var helpInterval = self.rageMode ? 270 : 600; // 4.5 seconds in rage, 10 seconds normal if (self.callForHelpTimer <= 0) { // Summon 3 random enemies for (var i = 0; i < 3; i++) { var enemyType = Math.random(); var enemy; if (enemyType < 0.33) { enemy = new Mutant(); } else if (enemyType < 0.66) { enemy = new FastMutant(); } else { enemy = new ShooterMutant(); } // Spawn on opposite side of screen from Bart enemy.x = bart.x < 1024 ? 1800 : 200; enemy.y = Math.random() * 1800 + 400; enemy.invincible = false; enemy.invincibilityTimer = 0; enemies.push(enemy); game.addChild(enemy); } self.callForHelpTimer = helpInterval; LK.effects.flashObject(self, 0x00FF00, 500); // Play call help sound LK.getSound('Callhelp').play(); } // Gun attack ability if (self.gunAttackTimer <= 0) { var bullet = new LeaderBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = bart.x; bullet.targetY = bart.y; bullet.damage = 90; // Insane damage but not instant kill bullet.speed = 12; enemyProjectiles.push(bullet); game.addChild(bullet); self.gunAttackTimer = 300; LK.effects.flashObject(self, 0xFF0000, 300); } // Whistle ability - reduce Bart's attack speed if (self.whistleTimer <= 0) { bart.originalFireRate = bart.fireRate; bart.fireRate = bart.fireRate * 2; // Double fire rate delay (slower) bart.attackSpeedDebuffTimer = 285; // 4.75 seconds self.whistleTimer = 1200; LK.effects.flashScreen(0x0000FF, 500); LK.effects.flashObject(self, 0x0000FF, 1000); // Change Bart to debuffed visual bart.updateWeaponVisual('debuffed'); // Play whistle sound LK.getSound('Whistleblow').play(); // Visual effect on Bart tween(leaderGraphics, { scaleX: 2, scaleY: 2 }, { duration: 300, easing: tween.easeOut }); tween(leaderGraphics, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeIn }); } } }; return self; }); var Peanut = Container.expand(function () { var self = Container.call(this); var peanutGraphics = self.attachAsset('peanut', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 15; self.speed = 12; self.target = null; self.lifetime = 60; self.hasSplit = false; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } else { self.y -= self.speed; } self.rotation += 0.1; }; return self; }); var PoetMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('poet_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 80; self.health = self.maxHealth; self.speed = 1; self.xpValue = 40; self.coinChance = 0.6; self.powerupChance = 0.25; self.summonTimer = 0; self.summonInterval = 180; // 3 seconds self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps self.takeDamage = function (damage) { if (self.invincible) return; // No damage during invincibility self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; // Reset to full opacity } } self.summonTimer--; // Apply damage multiplier if it exists var actualDamage = 10; if (self.damageMultiplier) { actualDamage = Math.floor(10 * self.damageMultiplier); } if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Summon mutants when close to player if (self.summonTimer <= 0 && dist < 800) { // Summon a basic mutant var summonedMutant = new Mutant(); summonedMutant.x = self.x + (Math.random() - 0.5) * 200; summonedMutant.y = self.y + (Math.random() - 0.5) * 200; summonedMutant.maxHealth = 20 + wave * 8; summonedMutant.health = summonedMutant.maxHealth; summonedMutant.speed = 2 + wave * 0.2; enemies.push(summonedMutant); game.addChild(summonedMutant); self.summonTimer = self.summonInterval; LK.effects.flashObject(self, 0xFF00FF, 300); } } }; return self; }); var PotBomb = Container.expand(function () { var self = Container.call(this); var potGraphics = self.attachAsset('pot_bomb', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 35; self.speed = 12; self.target = null; self.lifetime = 240; // 4 seconds at 60fps - auto-explode to reduce lag self.exploded = false; self.explosionRadius = 120; self.splitChance = 0.3; // 30% chance to split into shards self.update = function () { self.lifetime--; // Auto-explode after 4 seconds (240 frames at 60fps) to reduce lag if (self.lifetime <= 0) { self.explode(); return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; self.rotation += 0.15; // Spinning pot effect } } else { self.y -= self.speed; } }; self.explode = function () { if (self.exploded) return; self.exploded = true; // Hide the pot immediately potGraphics.visible = false; // Visual explosion effect LK.effects.flashScreen(0xFF8C00, 300); // Area damage to all enemies within radius for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.explosionRadius) { enemy.takeDamage(self.damage); LK.effects.flashObject(enemy, 0xFF8C00, 300); } } // Always split into pottery shards for (var i = 0; i < 4; i++) { var shard = new PotteryShard(); shard.x = self.x; shard.y = self.y; // Set diagonal directions: NE, NW, SE, SW var angle = i * Math.PI / 2 + Math.PI / 4; // 45, 135, 225, 315 degrees shard.velocityX = Math.cos(angle) * shard.speed; shard.velocityY = Math.sin(angle) * shard.speed; bullets.push(shard); game.addChild(shard); } self.shouldDestroy = true; }; return self; }); var PotteryShard = Container.expand(function () { var self = Container.call(this); var shardGraphics = self.attachAsset('pottery_shard', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 15; self.speed = 10; self.velocityX = 0; self.velocityY = 0; self.lifetime = 60; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } self.x += self.velocityX; self.y += self.velocityY; self.rotation += 0.2; // Spinning shard effect }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.type = Math.random() < 0.5 ? 'damage' : 'firerate'; self.lifetime = 300; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; } self.rotation += 0.03; self.y += Math.sin(LK.ticks * 0.05) * 0.5; }; return self; }); var RockerMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('rocker_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 70; self.health = self.maxHealth; self.speed = 2.5; self.xpValue = 40; self.coinChance = 0.5; self.powerupChance = 0.2; self.boostTimer = 0; self.boostInterval = 300; // 5 seconds self.invincible = true; self.invincibilityTimer = 180; self.takeDamage = function (damage) { if (self.invincible) return; self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; } } self.boostTimer--; // Check if Drummer is on screen for enhanced boost var drummerOnScreen = false; for (var i = 0; i < enemies.length; i++) { if (enemies[i] instanceof DrummerMutant && enemies[i] !== self) { drummerOnScreen = true; break; } } // Apply speed boost to all allies if (self.boostTimer <= 0) { var boostAmount = drummerOnScreen ? 1.5 : 1; // Extra boost if drummer present for (var i = 0; i < enemies.length; i++) { if (enemies[i] !== self && !enemies[i].speedBoosted) { enemies[i].originalSpeed = enemies[i].speed; enemies[i].speed += boostAmount; enemies[i].speedBoosted = true; enemies[i].speedBoostTimer = 300; // 5 seconds // Visual effect for boosted enemies LK.effects.flashObject(enemies[i], 0x00FF00, 500); } } self.boostTimer = self.boostInterval; // Visual effect when boosting LK.effects.flashObject(self, 0x00FF00, 1000); mutantGraphics.tint = 0x00FF00; tween(mutantGraphics, { tint: 0xFFFFFF }, { duration: 500, easing: tween.easeOut }); } if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } }; return self; }); var RubberArrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('rubber_arrow', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 20; self.speed = 18; self.target = null; self.lifetime = 80; self.pierceCount = 0; self.maxPierce = 3; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; self.rotation = Math.atan2(dy, dx); } } else { self.y -= self.speed; } }; return self; }); var SamuraiMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('samurai_mutant', { anchorX: 0.5, anchorY: 0.5 }); // Create katana - much bigger self.katana = self.attachAsset('katana', { anchorX: 0.5, anchorY: 0.5, x: 300, y: 0, scaleX: 2.5, scaleY: 2.5 }); self.maxHealth = 100; self.health = self.maxHealth; self.speed = 1.2; self.xpValue = 50; self.coinChance = 0.7; self.powerupChance = 0.3; self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps self.katanaAngle = 0; self.katanaRadius = 300; // Much farther from mutant self.reflectRadius = 350; // Increased to match farther katana self.takeDamage = function (damage) { if (self.invincible) return; // No damage during invincibility self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; // Reset to full opacity } } // Rotate katana around the mutant - much faster self.katanaAngle += 0.3; // Much faster rotation speed self.katana.x = Math.cos(self.katanaAngle) * self.katanaRadius; self.katana.y = Math.sin(self.katanaAngle) * self.katanaRadius; self.katana.rotation = self.katanaAngle + Math.PI / 2; // Orient katana tangentially // Move towards Bart if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } }; return self; }); var SantaHelper = Container.expand(function () { var self = Container.call(this); var helperGraphics = self.attachAsset('santa_helper', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.damage = 15; self.target = null; self.attackCooldown = 0; self.findTarget = function () { var closestEnemy = null; var closestDist = Infinity; for (var i = 0; i < enemies.length; i++) { var dx = enemies[i].x - self.x; var dy = enemies[i].y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < closestDist && dist < 800) { closestDist = dist; closestEnemy = enemies[i]; } } return closestEnemy; }; self.update = function () { self.attackCooldown--; // Find new target if current target is destroyed if (!self.target || self.target.shouldDestroy || self.target.destroyed) { self.target = self.findTarget(); } if (self.target) { // Move towards target aggressively var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Attack if close enough if (dist < 60 && self.attackCooldown <= 0) { self.target.takeDamage(self.damage); self.attackCooldown = 20; // Attack every 0.33 seconds LK.effects.flashObject(self, 0xFF0000, 200); // Bite animation effect tween(helperGraphics, { scaleX: 1.3, scaleY: 1.3 }, { duration: 100, easing: tween.easeOut }); tween(helperGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); } } else { // Follow Bart if no enemies if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 80) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } } }; return self; }); var ShooterMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('shooter_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 50; self.health = self.maxHealth; self.speed = 1.5; self.xpValue = 25; self.coinChance = 0.4; self.powerupChance = 0.15; self.shootTimer = 0; self.shootInterval = 120; self.invincible = true; self.invincibilityTimer = 180; // 3 seconds at 60fps self.takeDamage = function (damage) { if (self.invincible) return; // No damage during invincibility self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; // Reset to full opacity } } self.shootTimer--; if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } if (self.shootTimer <= 0 && dist < 2567) { var bowlingBall = new BowlingBall(); bowlingBall.x = self.x; bowlingBall.y = self.y; bowlingBall.targetX = bart.x; bowlingBall.targetY = bart.y; enemyProjectiles.push(bowlingBall); game.addChild(bowlingBall); self.shootTimer = self.shootInterval; } } }; return self; }); var SmallNut = Container.expand(function () { var self = Container.call(this); var nutGraphics = self.attachAsset('small_nut', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 5; self.speed = 10; self.velocityX = 0; self.velocityY = 0; self.lifetime = 40; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } self.x += self.velocityX; self.y += self.velocityY; self.rotation += 0.2; }; return self; }); var SnowballCat = Container.expand(function () { var self = Container.call(this); var catGraphics = self.attachAsset('snowball_cat', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.distractionRadius = 600; self.runDirection = 1; self.runTimer = 0; self.invincibilityReduction = 0.5; // Reduces invincibility time by 50% self.velocityX = (Math.random() - 0.5) * self.speed * 2; // Random X velocity self.velocityY = (Math.random() - 0.5) * self.speed * 2; // Random Y velocity self.directionChangeTimer = 0; self.update = function () { // Change direction randomly every 1-3 seconds self.directionChangeTimer++; if (self.directionChangeTimer > 60 + Math.random() * 120) { self.velocityX = (Math.random() - 0.5) * self.speed * 2; self.velocityY = (Math.random() - 0.5) * self.speed * 2; self.directionChangeTimer = 0; } // Move in current direction self.x += self.velocityX; self.y += self.velocityY; // Bounce off edges with some randomness if (self.x < 50) { self.x = 50; self.velocityX = Math.abs(self.velocityX) * (0.8 + Math.random() * 0.4); self.velocityY = (Math.random() - 0.5) * self.speed; } else if (self.x > 1998) { self.x = 1998; self.velocityX = -Math.abs(self.velocityX) * (0.8 + Math.random() * 0.4); self.velocityY = (Math.random() - 0.5) * self.speed; } if (self.y < 50) { self.y = 50; self.velocityY = Math.abs(self.velocityY) * (0.8 + Math.random() * 0.4); self.velocityX = (Math.random() - 0.5) * self.speed; } else if (self.y > 2682) { self.y = 2682; self.velocityY = -Math.abs(self.velocityY) * (0.8 + Math.random() * 0.4); self.velocityX = (Math.random() - 0.5) * self.speed; } // Check for nearby enemies to distract for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = self.x - enemy.x; var dy = self.y - enemy.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.distractionRadius) { // Make enemy follow the cat instead of Bart enemy.distractedBy = self; // Reduce invincibility time if enemy is invincible if (enemy.invincible && enemy.invincibilityTimer > 0) { enemy.invincibilityTimer = Math.floor(enemy.invincibilityTimer * self.invincibilityReduction); } } } // Animated running effect with rotation based on movement direction var catGraphics = self.children[0]; catGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.1; catGraphics.rotation = Math.atan2(self.velocityY, self.velocityX) * 0.2; // Face movement direction }; return self; }); var SoundBarrier = Container.expand(function () { var self = Container.call(this); // Create a wide barrier using multiple sound waves self.waves = []; for (var i = 0; i < 5; i++) { var wave = self.attachAsset('sound_wave', { anchorX: 0.5, anchorY: 0.5, x: (i - 2) * 80, y: 0, scaleX: 1.2, scaleY: 0.8, tint: 0xFFD700, alpha: 0.6 }); self.waves.push(wave); } self.health = 150; self.lifetime = 600; // 10 seconds self.width = 400; self.height = 80; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFF0000, 200); if (self.health <= 0) { self.shouldDestroy = true; } }; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } // Pulsing effect for (var i = 0; i < self.waves.length; i++) { self.waves[i].alpha = 0.4 + Math.sin(LK.ticks * 0.1 + i * 0.5) * 0.2; self.waves[i].scaleY = 0.8 + Math.sin(LK.ticks * 0.15 + i * 0.3) * 0.1; } // Block enemy projectiles for (var i = enemyProjectiles.length - 1; i >= 0; i--) { var projectile = enemyProjectiles[i]; var dx = Math.abs(projectile.x - self.x); var dy = Math.abs(projectile.y - self.y); if (dx < self.width / 2 && dy < self.height / 2) { self.takeDamage(projectile.damage || 10); projectile.destroy(); enemyProjectiles.splice(i, 1); } } // Slow down enemies passing through for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = Math.abs(enemy.x - self.x); var dy = Math.abs(enemy.y - self.y); if (dx < self.width / 2 && dy < self.height / 2) { if (!enemy.barrierSlowed) { enemy.barrierSlowed = true; enemy.originalBarrierSpeed = enemy.speed; enemy.speed *= 0.3; // 70% speed reduction } } else if (enemy.barrierSlowed) { enemy.speed = enemy.originalBarrierSpeed; enemy.barrierSlowed = false; } } }; return self; }); var SoundWave = Container.expand(function () { var self = Container.call(this); var waveGraphics = self.attachAsset('sound_wave', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 20; // Much faster than before self.damage = 12; self.targetX = 0; self.targetY = 0; self.directionSet = false; self.velocityX = 0; self.velocityY = 0; self.lifetime = 300; // Much longer lifespan self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } // Homing behavior for instakill soundwaves if (self.isHoming && self.target && !self.target.destroyed) { // Make homing sound waves smaller and faster with longer lifespan if (self.lifetime === 300) { // Initialize on first frame waveGraphics.scaleX = 0.7; // Smaller than regular sound waves waveGraphics.scaleY = 0.7; self.lifetime = 350; // Slightly bigger lifespan than regular } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * (self.speed * 1.2); // Faster than regular speed self.y += dy / dist * (self.speed * 1.2); } // Make it glow red for instakill waves if (self.damage >= 9999) { waveGraphics.tint = 0xFF0000; } } else { // Standard projectile movement like bowling balls if (!self.directionSet) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.velocityX = dx / dist * self.speed; self.velocityY = dy / dist * self.speed; } self.directionSet = true; } self.x += self.velocityX; self.y += self.velocityY; } // Enhanced glowing effect using tween waveGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.3) * 0.2; // Continuous scaling glow effect tween(waveGraphics, { scaleX: 1.2, scaleY: 1.2, alpha: 0.9 }, { duration: 500, easing: tween.easeInOut }); tween(waveGraphics, { scaleX: 1.0, scaleY: 1.0, alpha: 0.6 }, { duration: 500, easing: tween.easeInOut }); }; return self; }); var Spray = Container.expand(function () { var self = Container.call(this); var sprayGraphics = self.attachAsset('spray', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 8; self.speed = 15; self.target = null; self.lifetime = 45; self.stunDuration = 72; // 1.2 seconds at 60fps self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (self.target && !self.target.destroyed) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; self.rotation = Math.atan2(dy, dx); } } else { self.y -= self.speed; } sprayGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.3) * 0.3; }; return self; }); var StunRay = Container.expand(function () { var self = Container.call(this); var rayGraphics = self.attachAsset('sound_wave', { anchorX: 0.5, anchorY: 0.5, tint: 0x9400D3 // Purple color for stun ray }); self.speed = 12; self.damage = 30; self.stunDuration = 45; // 0.75 seconds at 60fps self.targetX = 0; self.targetY = 0; self.directionSet = false; self.velocityX = 0; self.velocityY = 0; self.lifetime = 240; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.shouldDestroy = true; return; } if (!self.directionSet) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.velocityX = dx / dist * self.speed; self.velocityY = dy / dist * self.speed; } self.directionSet = true; } self.x += self.velocityX; self.y += self.velocityY; // Pulsing effect rayGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.4) * 0.4; rayGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.2; rayGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.3) * 0.2; }; return self; }); var TicTacToe = Container.expand(function () { var self = Container.call(this); // Game state self.board = [[null, null, null], [null, null, null], [null, null, null]]; self.currentPlayer = 'X'; // Player is X, AI is O self.gameOver = false; self.onComplete = null; // Background var bg = self.attachAsset('tictactoe_grid', { anchorX: 0.5, anchorY: 0.5 }); // Draw grid lines var vLine1 = self.attachAsset('grid_line', { anchorX: 0.5, anchorY: 0.5, x: -100, scaleX: 0.017, scaleY: 40 }); var vLine2 = self.attachAsset('grid_line', { anchorX: 0.5, anchorY: 0.5, x: 100, scaleX: 0.017, scaleY: 40 }); var hLine1 = self.attachAsset('grid_line', { anchorX: 0.5, anchorY: 0.5, y: -100, scaleY: 0.67 }); var hLine2 = self.attachAsset('grid_line', { anchorX: 0.5, anchorY: 0.5, y: 100, scaleY: 0.67 }); // Title self.titleText = new Text2('TIC TAC TOE', { size: 60, fill: 0xFFFFFF }); self.titleText.anchor.set(0.5, 0.5); self.titleText.y = -380; self.addChild(self.titleText); // Instruction self.instructionText = new Text2('You are Itchy (X), beat Scratchy (O)!', { size: 40, fill: 0xAAAAAA }); self.instructionText.anchor.set(0.5, 0.5); self.instructionText.y = -320; self.addChild(self.instructionText); // Result text self.resultText = new Text2('', { size: 60, fill: 0xFFD700 }); self.resultText.anchor.set(0.5, 0.5); self.resultText.y = 380; self.addChild(self.resultText); // Grid cells for interaction self.cells = []; for (var row = 0; row < 3; row++) { self.cells[row] = []; for (var col = 0; col < 3; col++) { var cellBg = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: (col - 1) * 200, y: (row - 1) * 200, scaleX: 0.9, scaleY: 4.5, alpha: 0.01 }); cellBg.row = row; cellBg.col = col; self.cells[row][col] = cellBg; } } self.makeMove = function (row, col) { if (self.gameOver || self.board[row][col] !== null) return false; self.board[row][col] = self.currentPlayer; // Add visual mark if (self.currentPlayer === 'X') { var itchy = self.attachAsset('itchy', { anchorX: 0.5, anchorY: 0.5, x: (col - 1) * 200, y: (row - 1) * 200 }); } else { var scratchy = self.attachAsset('scratchy', { anchorX: 0.5, anchorY: 0.5, x: (col - 1) * 200, y: (row - 1) * 200 }); } // Check for winner var winner = self.checkWinner(); if (winner) { self.gameOver = true; if (winner === 'X') { self.resultText.setText('You Win! +25 Coins!'); LK.getSound('carnival_win').play(); if (self.onComplete) self.onComplete(true, 25); } else { self.resultText.setText('Scratchy Wins!'); LK.getSound('carnival_lose').play(); if (self.onComplete) self.onComplete(false, 0); } return true; } // Check for tie if (self.isBoardFull()) { self.gameOver = true; self.resultText.setText('It\'s a Tie!'); LK.getSound('carnival_lose').play(); if (self.onComplete) self.onComplete(false, 0); return true; } // Switch player self.currentPlayer = self.currentPlayer === 'X' ? 'O' : 'X'; // AI move if (self.currentPlayer === 'O' && !self.gameOver) { LK.setTimeout(function () { self.makeAIMove(); }, 500); } return true; }; self.makeAIMove = function () { // Simple AI - tries to win, block, or take center/corners var bestMove = self.findBestMove(); if (bestMove) { self.makeMove(bestMove.row, bestMove.col); } }; self.findBestMove = function () { // Try to win for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (self.board[row][col] === null) { self.board[row][col] = 'O'; if (self.checkWinner() === 'O') { self.board[row][col] = null; return { row: row, col: col }; } self.board[row][col] = null; } } } // Try to block for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (self.board[row][col] === null) { self.board[row][col] = 'X'; if (self.checkWinner() === 'X') { self.board[row][col] = null; return { row: row, col: col }; } self.board[row][col] = null; } } } // Take center if (self.board[1][1] === null) { return { row: 1, col: 1 }; } // Take corners var corners = [[0, 0], [0, 2], [2, 0], [2, 2]]; for (var i = 0; i < corners.length; i++) { if (self.board[corners[i][0]][corners[i][1]] === null) { return { row: corners[i][0], col: corners[i][1] }; } } // Take any available for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (self.board[row][col] === null) { return { row: row, col: col }; } } } return null; }; self.checkWinner = function () { // Check rows for (var row = 0; row < 3; row++) { if (self.board[row][0] && self.board[row][0] === self.board[row][1] && self.board[row][1] === self.board[row][2]) { return self.board[row][0]; } } // Check columns for (var col = 0; col < 3; col++) { if (self.board[0][col] && self.board[0][col] === self.board[1][col] && self.board[1][col] === self.board[2][col]) { return self.board[0][col]; } } // Check diagonals if (self.board[1][1]) { if (self.board[0][0] === self.board[1][1] && self.board[1][1] === self.board[2][2]) { return self.board[1][1]; } if (self.board[0][2] === self.board[1][1] && self.board[1][1] === self.board[2][0]) { return self.board[1][1]; } } return null; }; self.isBoardFull = function () { for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (self.board[row][col] === null) { return false; } } } return true; }; return self; }); var UFOStriker = Container.expand(function () { var self = Container.call(this); // Create UFO body using proper UFO asset var ufoBody = self.attachAsset('ufo_striker', { anchorX: 0.5, anchorY: 0.5 }); // Add a dome on top var ufoDome = self.attachAsset('ufo_dome', { anchorX: 0.5, anchorY: 0.5, y: -60, alpha: 0.8 }); self.maxHealth = 30550; self.health = self.maxHealth; self.speed = 2; // Faster speed (was 0.5) self.xpValue = 3000; self.coinChance = 1; self.coinValue = 200; self.powerupChance = 1; self.isInstantKillBoss = true; // Timers for abilities self.stunRayTimer = 180; // 3 seconds self.replicaTimer = 450; // 7.5 seconds self.cloneTimer = 6000; // 100 seconds self.kidnappingTarget = null; self.kidnappingProgress = 0; self.clones = []; // Health bar var healthBarBg = self.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, y: -180, scaleX: 2 }); self.healthBarFill = self.attachAsset('healthbar_fill', { anchorX: 0, anchorY: 0.5, x: -200, y: -180, scaleX: 2 }); self.takeDamage = function (damage) { // Can't take damage while kidnapping if (self.kidnappingTarget) return; self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth) * 2; if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); // Drop many coins for (var i = 0; i < 40; i++) { spawnItem(self.x + (Math.random() - 0.5) * 300, self.y + (Math.random() - 0.5) * 300, 'coin'); } } }; self.startKidnapping = function (target) { self.kidnappingTarget = target; self.kidnappingProgress = 0; // Freeze Bart target.stunned = true; target.stunnedTimer = 300; // 5 seconds // Create tractor beam effect var tractorBeam = self.attachAsset('tractor_beam', { anchorX: 0.5, anchorY: 0, y: 50, scaleY: 1, tint: 0x00FF00, alpha: 0.6 }); self.tractorBeam = tractorBeam; // Start pulling animation tween(target, { y: self.y + 100 }, { duration: 5000, easing: tween.linear, onFinish: function onFinish() { // Kidnapping complete - game over target.health = 0; target.takeDamage(0); } }); }; self.executeRandomBossMove = function () { // List of possible boss moves to replicate var moves = ['summonEnemies', 'shootProjectiles', 'areaAttack', 'speedBoost']; var selectedMove = moves[Math.floor(Math.random() * moves.length)]; switch (selectedMove) { case 'summonEnemies': // Summon 2 random enemies (like Mutant Leader) for (var i = 0; i < 2; i++) { var enemyType = Math.random(); var enemy; if (enemyType < 0.5) { enemy = new Mutant(); } else { enemy = new FastMutant(); } enemy.x = self.x + (Math.random() - 0.5) * 400; enemy.y = self.y + 200; enemy.invincible = false; enemy.invincibilityTimer = 0; enemies.push(enemy); game.addChild(enemy); } LK.effects.flashObject(self, 0x00FF00, 500); break; case 'shootProjectiles': // Shoot multiple sound waves (like Concert) if (bart) { for (var i = -2; i <= 2; i++) { var soundWave = new SoundWave(); soundWave.x = self.x; soundWave.y = self.y; var angle = Math.atan2(bart.y - soundWave.y, bart.x - soundWave.x); angle += i * 0.3; soundWave.targetX = soundWave.x + Math.cos(angle) * 1000; soundWave.targetY = soundWave.y + Math.sin(angle) * 1000; soundWave.damage = 25; enemyProjectiles.push(soundWave); game.addChild(soundWave); } } LK.effects.flashObject(self, 0xFF00FF, 500); break; case 'areaAttack': // Flash area damage (like pot explosion) LK.effects.flashScreen(0xFF0000, 300); if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 400) { bart.takeDamage(40); } } break; case 'speedBoost': // Boost all enemy speeds (like Concert's Rock Music) for (var i = 0; i < enemies.length; i++) { if (enemies[i] !== self && !enemies[i].ufoSpeedBoosted) { enemies[i].originalSpeed = enemies[i].speed; enemies[i].speed *= 1.5; enemies[i].ufoSpeedBoosted = true; enemies[i].ufoSpeedBoostTimer = 300; LK.effects.flashObject(enemies[i], 0x00FF00, 500); } } break; } }; self.createClone = function () { var clone = new UFOStrikerClone(); clone.x = self.x + (Math.random() - 0.5) * 300; clone.y = self.y + (Math.random() - 0.5) * 300; self.clones.push(clone); enemies.push(clone); game.addChild(clone); LK.effects.flashScreen(0x0000FF, 500); // Animation for cloning tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 300, easing: tween.easeOut }); tween(self, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeIn }); }; self.update = function () { // Update timers self.stunRayTimer--; self.replicaTimer--; self.cloneTimer--; // Clean up destroyed clones self.clones = self.clones.filter(function (clone) { return !clone.destroyed && !clone.shouldDestroy; }); // Handle UFO speed boost timers for (var i = 0; i < enemies.length; i++) { if (enemies[i].ufoSpeedBoosted && enemies[i].ufoSpeedBoostTimer) { enemies[i].ufoSpeedBoostTimer--; if (enemies[i].ufoSpeedBoostTimer <= 0) { enemies[i].speed = enemies[i].originalSpeed; enemies[i].ufoSpeedBoosted = false; } } } // Kidnapping logic if (self.kidnappingTarget) { self.kidnappingProgress++; // Update tractor beam if (self.tractorBeam) { var dx = self.kidnappingTarget.x - self.x; var dy = self.kidnappingTarget.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); self.tractorBeam.rotation = Math.atan2(dy, dx) + Math.PI / 2; self.tractorBeam.scaleY = dist / 600; // Adjust beam length based on tractor beam height } if (self.kidnappingProgress >= 300) { // Kidnapping complete self.kidnappingTarget = null; if (self.tractorBeam) { self.removeChild(self.tractorBeam); self.tractorBeam = null; } } return; // Don't do other actions while kidnapping } if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); // Try to kidnap if touching Bart if (dist < 100 && !bart.stunned) { self.startKidnapping(bart); return; } // Move towards Bart slowly if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Stun-Ray ability if (self.stunRayTimer <= 0) { var stunRay = new StunRay(); stunRay.x = self.x; stunRay.y = self.y; stunRay.targetX = bart.x; stunRay.targetY = bart.y; enemyProjectiles.push(stunRay); game.addChild(stunRay); self.stunRayTimer = 180; LK.effects.flashObject(self, 0x9400D3, 300); } // Replica ability if (self.replicaTimer <= 0) { self.executeRandomBossMove(); self.replicaTimer = 450; } // Clone ability if (self.cloneTimer <= 0 && self.clones.length < 3) { self.createClone(); self.cloneTimer = 6000; } } // UFO hovering animation ufoBody.y = Math.sin(LK.ticks * 0.05) * 10; ufoDome.y = -60 + Math.sin(LK.ticks * 0.05) * 10; // Add pulsing glow effect to dome ufoDome.alpha = 0.6 + Math.sin(LK.ticks * 0.1) * 0.2; }; return self; }); var UFOStrikerClone = Container.expand(function () { var self = Container.call(this); // Create UFO shape with blue tint var ufoBody = self.attachAsset('ufo_striker', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, tint: 0x0000FF // Blue tint for clone }); var ufoDome = self.attachAsset('ufo_dome', { anchorX: 0.5, anchorY: 0.5, y: -50, scaleX: 0.8, scaleY: 0.8, tint: 0x00BFFF, alpha: 0.7 }); self.maxHealth = 10000; self.health = self.maxHealth; self.speed = 0.8; self.xpValue = 500; self.coinChance = 0.8; self.powerupChance = 0.5; // Simple AI - just move and shoot self.shootTimer = 120; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.update = function () { self.shootTimer--; if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Shoot stun rays if (self.shootTimer <= 0) { var stunRay = new StunRay(); stunRay.x = self.x; stunRay.y = self.y; stunRay.targetX = bart.x; stunRay.targetY = bart.y; stunRay.damage = 15; // Less damage than original stunRay.stunDuration = 30; // 0.5 seconds enemyProjectiles.push(stunRay); game.addChild(stunRay); self.shootTimer = 120; } } // UFO hovering animation ufoBody.y = Math.sin(LK.ticks * 0.05 + self.x) * 8; ufoDome.y = -50 + Math.sin(LK.ticks * 0.05 + self.x) * 8; // Pulsing glow effect for clone dome ufoDome.alpha = 0.5 + Math.sin(LK.ticks * 0.12) * 0.2; }; return self; }); var VocalMutant = Container.expand(function () { var self = Container.call(this); var mutantGraphics = self.attachAsset('vocal_mutant', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 40; self.health = self.maxHealth; self.speed = 5; self.xpValue = 35; self.coinChance = 0.4; self.powerupChance = 0.15; self.baseDamage = 15; // Base damage when swearing at Bart self.invincible = true; self.invincibilityTimer = 180; self.takeDamage = function (damage) { if (self.invincible) return; self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.shouldDestroy = true; LK.getSound('hit').play(); } }; self.getDamage = function () { // Check if Rocker is on screen to double damage var rockerOnScreen = false; for (var i = 0; i < enemies.length; i++) { if (enemies[i] instanceof RockerMutant && enemies[i] !== self) { rockerOnScreen = true; break; } } return rockerOnScreen ? self.baseDamage * 2 : self.baseDamage; }; self.update = function () { if (self.invincible) { self.invincibilityTimer--; mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; if (self.invincibilityTimer <= 0) { self.invincible = false; mutantGraphics.alpha = 1; } } if (bart) { var dx = bart.x - self.x; var dy = bart.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } }; return self; }); var WhackAMole = Container.expand(function () { var self = Container.call(this); // Game state self.score = 0; self.timeLeft = 30; // 30 seconds self.gameOver = false; self.onComplete = null; self.moles = []; // Title self.titleText = new Text2('HIT THE MOLE', { size: 60, fill: 0xFFFFFF }); self.titleText.anchor.set(0.5, 0.5); self.titleText.y = -400; self.addChild(self.titleText); // Instructions self.instructionText = new Text2('Hit 5 Scratchys to win! Avoid Itchys!', { size: 40, fill: 0xAAAAAA }); self.instructionText.anchor.set(0.5, 0.5); self.instructionText.y = -340; self.addChild(self.instructionText); // Score text self.scoreText = new Text2('Score: 0/5', { size: 50, fill: 0xFFD700 }); self.scoreText.anchor.set(0.5, 0.5); self.scoreText.y = -280; self.addChild(self.scoreText); // Timer text self.timerText = new Text2('Time: 30', { size: 50, fill: 0xFFFFFF }); self.timerText.anchor.set(0.5, 0.5); self.timerText.y = 350; self.addChild(self.timerText); // Create mole holes self.holes = []; var positions = [{ x: -300, y: -150 }, { x: 0, y: -150 }, { x: 300, y: -150 }, { x: -300, y: 50 }, { x: 0, y: 50 }, { x: 300, y: 50 }, { x: -300, y: 250 }, { x: 0, y: 250 }, { x: 300, y: 250 }]; for (var i = 0; i < positions.length; i++) { var hole = self.attachAsset('mole_hole', { anchorX: 0.5, anchorY: 0.5, x: positions[i].x, y: positions[i].y }); self.holes.push(hole); } // Result text self.resultText = new Text2('', { size: 60, fill: 0xFFD700 }); self.resultText.anchor.set(0.5, 0.5); self.resultText.y = 420; self.addChild(self.resultText); self.spawnMole = function () { if (self.gameOver) return; var holeIndex = Math.floor(Math.random() * self.holes.length); var isItchy = Math.random() < 0.3; // 30% chance for Itchy var mole = self.attachAsset(isItchy ? 'itchy' : 'scratchy', { anchorX: 0.5, anchorY: 0.5, x: self.holes[holeIndex].x, y: self.holes[holeIndex].y }); mole.isItchy = isItchy; mole.lifetime = 120; // 2 seconds mole.clicked = false; // Pop up animation mole.scaleY = 0; tween(mole, { scaleY: 1 }, { duration: 200, easing: tween.easeOut }); self.moles.push(mole); }; self.hitMole = function (mole) { if (mole.clicked || self.gameOver) return; mole.clicked = true; LK.getSound('whack').play(); if (mole.isItchy) { // Hit Itchy - lose! self.gameOver = true; self.resultText.setText('You hit Itchy! Game Over!'); LK.getSound('carnival_lose').play(); if (self.onComplete) self.onComplete(false, 0); } else { // Hit Scratchy - score! self.score++; self.scoreText.setText('Score: ' + self.score + '/5'); if (self.score >= 5) { self.gameOver = true; self.resultText.setText('You Win! +30 Coins!'); LK.getSound('carnival_win').play(); if (self.onComplete) self.onComplete(true, 30); } } // Hide mole tween(mole, { scaleY: 0 }, { duration: 100, easing: tween.easeIn, onFinish: function onFinish() { self.removeChild(mole); } }); }; self.update = function () { if (self.gameOver) return; // Update timer if (LK.ticks % 60 === 0) { self.timeLeft--; self.timerText.setText('Time: ' + self.timeLeft); if (self.timeLeft <= 0) { self.gameOver = true; self.resultText.setText('Time\'s Up!'); LK.getSound('carnival_lose').play(); if (self.onComplete) self.onComplete(false, 0); } } // Spawn moles if (LK.ticks % 45 === 0) { self.spawnMole(); } // Update moles for (var i = self.moles.length - 1; i >= 0; i--) { var mole = self.moles[i]; mole.lifetime--; if (mole.lifetime <= 0) { tween(mole, { scaleY: 0 }, { duration: 100, easing: tween.easeIn, onFinish: function onFinish() { self.removeChild(mole); } }); self.moles.splice(i, 1); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000080, width: isLowQualityMode ? 1080 : 2048, height: isLowQualityMode ? 1920 : 2732 }); /**** * Game Code ****/ var bart; var enemies = []; var bullets = []; var items = []; var enemyProjectiles = []; var alienMeals = []; var wave = 1; var enemiesKilled = 0; var spawnTimer = 0; var dragTarget = null; var gameStarted = false; var titleScreen; var startButton; var titleText; var shopScreen; var shopButton; var selectedWeapon = 'slingshot'; var unlockedWeapons = ['slingshot']; var weaponPrices = { dartgun: 100, scattershot: 250, ducky: 500, spraycan: 750, flower: 1000, bow: 600, pot: 800 }; var isGiantMutantRush = false; var giantMutantRushButton; var mutantLeaderSpawned = false; var isLowQualityMode = false; var savedQualityMode = false; // Load saved quality mode try { savedQualityMode = storage.qualityMode === 'low'; isLowQualityMode = savedQualityMode; } catch (e) { console.log('Could not load quality mode:', e); } // Joystick variables var joystick = null; var joystickKnob = null; var joystickPressed = false; var joystickCenter = { x: 200, y: 2400 }; var joystickRadius = 80; var joystickDirection = { x: 0, y: 0 }; var joystickSpeed = 8; function updateJoystick(touchX, touchY) { if (!joystickKnob) return; var joystickScreenX = joystickCenter.x; var joystickScreenY = 2732 - 150; // Convert GUI coordinate to screen coordinate var deltaX = touchX - joystickScreenX; var deltaY = touchY - joystickScreenY; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // Limit knob movement to joystick radius if (distance > joystickRadius) { deltaX = deltaX / distance * joystickRadius; deltaY = deltaY / distance * joystickRadius; distance = joystickRadius; } // Update knob position joystickKnob.x = joystickCenter.x + deltaX; joystickKnob.y = -150 + deltaY; // Calculate movement direction (normalized) if (distance > 10) { // Dead zone joystickDirection.x = deltaX / joystickRadius; joystickDirection.y = deltaY / joystickRadius; } else { joystickDirection.x = 0; joystickDirection.y = 0; } } function toggleQualityMode() { isLowQualityMode = !isLowQualityMode; // Update button appearance var qualityButton = titleScreen.children.find(function (child) { return child.tint === 0x00FF00 || child.tint === 0xFF0000; }); var qualityText = titleScreen.children.find(function (child) { return child instanceof Text2 && (child.text === 'HD' || child.text === 'FHD'); }); if (isLowQualityMode) { if (qualityButton) qualityButton.tint = 0xFF0000; // Red for low quality if (qualityText) qualityText.setText('FHD'); // Low quality mode is now handled through conditional checks in game logic } else { if (qualityButton) qualityButton.tint = 0x00FF00; // Green for high quality if (qualityText) qualityText.setText('HD'); // High quality mode is the default } // Save preference try { storage.qualityMode = isLowQualityMode ? 'low' : 'high'; } catch (e) { console.log('Could not save quality mode:', e); } } // Apply saved quality mode on startup if (isLowQualityMode) { LK.setTimeout(function () { toggleQualityMode(); toggleQualityMode(); // Toggle twice to properly set initial state }, 100); } var weaponStats = { slingshot: { damage: 10, fireRate: 30, projectileCount: 1 }, dartgun: { damage: 50, fireRate: 60, projectileCount: 1 }, scattershot: { damage: 15, fireRate: 40, projectileCount: 1 }, ducky: { damage: 25, fireRate: 45, projectileCount: 3 }, spraycan: { damage: 8, fireRate: 50, projectileCount: 1 }, flower: { damage: 3, fireRate: 6, projectileCount: 1 }, bow: { damage: 12, fireRate: 35, projectileCount: 1 }, pot: { damage: 35, fireRate: 55, projectileCount: 1 } }; var selectedSubweapon = null; var unlockedSubweapons = []; var subweaponPrices = { santa_helper: 750, krusty_shop: 1200, snowball_cat: 900 }; var activeSubweapon = null; var encyclopediaScreen; // Create title screen titleScreen = new Container(); game.addChild(titleScreen); // Title text titleText = new Text2('BART vs MUTANTS', { size: 120, fill: 0xFFFF00 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; titleScreen.addChild(titleText); // Start button background startButton = titleScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1400, scaleX: 2, scaleY: 3 }); // Start button text var startText = new Text2('START', { size: 80, fill: 0xFFFFFF }); startText.anchor.set(0.5, 0.5); startText.x = 1024; startText.y = 1400; titleScreen.addChild(startText); // Instructions text var instructionsText = new Text2('Drag to move • Auto-shoot enemies', { size: 50, fill: 0xAAAAAA }); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 1024; instructionsText.y = 1600; titleScreen.addChild(instructionsText); // Title screen coins display var titleCoinsText = new Text2('Coins: 0', { size: 60, fill: 0xFFD700 }); titleCoinsText.anchor.set(1, 0); titleCoinsText.x = 1948; titleCoinsText.y = 100; titleScreen.addChild(titleCoinsText); // Shop button background shopButton = titleScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1800, scaleX: 2, scaleY: 2 }); // Shop button text var shopButtonText = new Text2('KRUSTY BURGER', { size: 60, fill: 0xFFFF00 }); shopButtonText.anchor.set(0.5, 0.5); shopButtonText.x = 1024; shopButtonText.y = 1800; titleScreen.addChild(shopButtonText); // Encyclopedia button background var encyclopediaButton = titleScreen.attachAsset('info_button', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2100, scaleX: 2, scaleY: 2 }); // Encyclopedia button text var encyclopediaButtonText = new Text2('ENCYCLOPEDIA', { size: 60, fill: 0x00FFFF }); encyclopediaButtonText.anchor.set(0.5, 0.5); encyclopediaButtonText.x = 1024; encyclopediaButtonText.y = 2100; titleScreen.addChild(encyclopediaButtonText); // Carnival button background var carnivalButton = titleScreen.attachAsset('carnival_tent', { anchorX: 0.5, anchorY: 0.5, x: 512, y: 2100, scaleX: 0.8, scaleY: 0.8 }); // Carnival button text var carnivalText = new Text2('CARNIVAL', { size: 50, fill: 0xFFD700 }); carnivalText.anchor.set(0.5, 0.5); carnivalText.x = 512; carnivalText.y = 2250; titleScreen.addChild(carnivalText); // Carnival entry fee text var carnivalFeeText = new Text2('10 coins per game', { size: 30, fill: 0xAAAAAA }); carnivalFeeText.anchor.set(0.5, 0.5); carnivalFeeText.x = 512; carnivalFeeText.y = 2300; titleScreen.addChild(carnivalFeeText); // Quality mode toggle button var qualityButton = titleScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 400, scaleX: 2, scaleY: 1.5 }); qualityButton.tint = isLowQualityMode ? 0xFF0000 : 0x00FF00; // Red for low quality, green for high quality var qualityText = new Text2(isLowQualityMode ? 'FHD' : 'HD', { size: 50, fill: 0xFFFFFF }); qualityText.anchor.set(0.5, 0.5); qualityText.x = 200; qualityText.y = 400; titleScreen.addChild(qualityText); var qualityLabel = new Text2('Quality', { size: 30, fill: 0xAAAAAA }); qualityLabel.anchor.set(0.5, 0.5); qualityLabel.x = 200; qualityLabel.y = 450; titleScreen.addChild(qualityLabel); // Giant Mutant Rush button background giantMutantRushButton = titleScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1536, y: 2100, scaleX: 2.5, scaleY: 2 }); giantMutantRushButton.tint = 0xFF0000; // Giant Mutant Rush button text var giantRushText = new Text2('GIANT MUTANT RUSH!', { size: 50, fill: 0xFFFF00 }); giantRushText.anchor.set(0.5, 0.5); giantRushText.x = 1536; giantRushText.y = 2100; titleScreen.addChild(giantRushText); // Boss selection screen var bossSelectionScreen = new Container(); bossSelectionScreen.visible = false; game.addChild(bossSelectionScreen); // Boss selection title var bossSelectionTitle = new Text2('SELECT YOUR OPPONENT', { size: 100, fill: 0xFF0000 }); bossSelectionTitle.anchor.set(0.5, 0.5); bossSelectionTitle.x = 1024; bossSelectionTitle.y = 200; bossSelectionScreen.addChild(bossSelectionTitle); // Boss selection coins display var bossSelectionCoinsText = new Text2('Coins: 0', { size: 60, fill: 0xFFD700 }); bossSelectionCoinsText.anchor.set(1, 0); bossSelectionCoinsText.x = 1948; bossSelectionCoinsText.y = 100; bossSelectionScreen.addChild(bossSelectionCoinsText); // Entry fee text var entryFeeText = new Text2('Entry Fee: 50 Coins', { size: 50, fill: 0xFFD700 }); entryFeeText.anchor.set(0.5, 0.5); entryFeeText.x = 1024; entryFeeText.y = 350; bossSelectionScreen.addChild(entryFeeText); // Watch ad button var watchAdButton = bossSelectionScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 450, scaleX: 3.5, scaleY: 1.5 }); watchAdButton.tint = 0x00FF00; var watchAdText = new Text2('Watch Itchy & Scratchy Ad', { size: 45, fill: 0xFFFFFF }); watchAdText.anchor.set(0.5, 0.5); watchAdText.x = 1024; watchAdText.y = 430; bossSelectionScreen.addChild(watchAdText); var watchAdSubtext = new Text2('30 seconds to skip fee', { size: 30, fill: 0xAAAAAA }); watchAdSubtext.anchor.set(0.5, 0.5); watchAdSubtext.x = 1024; watchAdSubtext.y = 470; bossSelectionScreen.addChild(watchAdSubtext); // Mutant Leader selection button var mutantLeaderButton = bossSelectionScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 600, scaleX: 3, scaleY: 2 }); mutantLeaderButton.tint = 0x800080; var mutantLeaderText = new Text2('MUTANT LEADER', { size: 60, fill: 0xFFFFFF }); mutantLeaderText.anchor.set(0.5, 0.5); mutantLeaderText.x = 1024; mutantLeaderText.y = 570; bossSelectionScreen.addChild(mutantLeaderText); var mutantLeaderDesc = new Text2('HP: 20000 | Summons allies & debuffs', { size: 35, fill: 0xAAAAAA }); mutantLeaderDesc.anchor.set(0.5, 0.5); mutantLeaderDesc.x = 1024; mutantLeaderDesc.y = 630; bossSelectionScreen.addChild(mutantLeaderDesc); // Concert selection button var concertButton = bossSelectionScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 850, scaleX: 3, scaleY: 2 }); concertButton.tint = 0x2678d7; var concertText = new Text2('CONCERT', { size: 60, fill: 0xFFFFFF }); concertText.anchor.set(0.5, 0.5); concertText.x = 1024; concertText.y = 820; bossSelectionScreen.addChild(concertText); var concertDesc = new Text2('HP: 25750 | Band attacks & buffs', { size: 35, fill: 0xAAAAAA }); concertDesc.anchor.set(0.5, 0.5); concertDesc.x = 1024; concertDesc.y = 880; bossSelectionScreen.addChild(concertDesc); // UFO Striker selection button var ufoButton = bossSelectionScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1100, scaleX: 3, scaleY: 2 }); ufoButton.tint = 0x4B0082; var ufoText = new Text2('UFO STRIKER', { size: 60, fill: 0xFFFFFF }); ufoText.anchor.set(0.5, 0.5); ufoText.x = 1024; ufoText.y = 1070; bossSelectionScreen.addChild(ufoText); var ufoDesc = new Text2('HP: 30550 | Kidnapping & cloning', { size: 35, fill: 0xAAAAAA }); ufoDesc.anchor.set(0.5, 0.5); ufoDesc.x = 1024; ufoDesc.y = 1130; bossSelectionScreen.addChild(ufoDesc); // Random boss selection button var randomBossButton = bossSelectionScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1350, scaleX: 3, scaleY: 2 }); randomBossButton.tint = 0xFFD700; var randomBossText = new Text2('RANDOM BOSS', { size: 60, fill: 0x000000 }); randomBossText.anchor.set(0.5, 0.5); randomBossText.x = 1024; randomBossText.y = 1320; bossSelectionScreen.addChild(randomBossText); var randomBossDesc = new Text2('Let fate decide your opponent!', { size: 35, fill: 0x666666 }); randomBossDesc.anchor.set(0.5, 0.5); randomBossDesc.x = 1024; randomBossDesc.y = 1380; bossSelectionScreen.addChild(randomBossDesc); // Back button for boss selection var bossBackButton = bossSelectionScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 200, scaleX: 1.5, scaleY: 1.5 }); var bossBackText = new Text2('BACK', { size: 50, fill: 0xFFFFFF }); bossBackText.anchor.set(0.5, 0.5); bossBackText.x = 200; bossBackText.y = 200; bossSelectionScreen.addChild(bossBackText); // Variable to store selected boss var selectedGiantMutant = null; // Ad watching state var isWatchingAd = false; var adCountdown = 0; var adCountdownText = null; var adOverlay = null; // Ad overlay screen var adOverlay = new Container(); adOverlay.visible = false; game.addChild(adOverlay); // Ad background var adBg = adOverlay.attachAsset('info_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); // Ad title var adTitle = new Text2('ITCHY & SCRATCHY SHOW', { size: 100, fill: 0xFF0000 }); adTitle.anchor.set(0.5, 0.5); adTitle.x = 1024; adTitle.y = 400; adOverlay.addChild(adTitle); // Ad content area var adContent = new Text2('Advertisement Playing...', { size: 60, fill: 0xFFFFFF }); adContent.anchor.set(0.5, 0.5); adContent.x = 1024; adContent.y = 800; adOverlay.addChild(adContent); // Ad countdown text adCountdownText = new Text2('30', { size: 120, fill: 0xFFFF00 }); adCountdownText.anchor.set(0.5, 0.5); adCountdownText.x = 1024; adCountdownText.y = 1200; adOverlay.addChild(adCountdownText); // Ad skip notice var adSkipNotice = new Text2('Please wait for ad to complete', { size: 40, fill: 0xAAAAAA }); adSkipNotice.anchor.set(0.5, 0.5); adSkipNotice.x = 1024; adSkipNotice.y = 1600; adOverlay.addChild(adSkipNotice); // Carnival screen var carnivalScreen = new Container(); carnivalScreen.visible = false; game.addChild(carnivalScreen); // Carnival background var carnivalBg = carnivalScreen.attachAsset('carnival_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); // Carnival title var carnivalTitle = new Text2('CARNIVAL GAMES', { size: 100, fill: 0xFFD700 }); carnivalTitle.anchor.set(0.5, 0.5); carnivalTitle.x = 1024; carnivalTitle.y = 200; carnivalScreen.addChild(carnivalTitle); // Carnival subtitle var carnivalSubtitle = new Text2('Entry Fee: 10 Coins per Game', { size: 50, fill: 0xFFFFFF }); carnivalSubtitle.anchor.set(0.5, 0.5); carnivalSubtitle.x = 1024; carnivalSubtitle.y = 300; carnivalScreen.addChild(carnivalSubtitle); // Carnival coins display var carnivalCoinsText = new Text2('Coins: 0', { size: 60, fill: 0xFFD700 }); carnivalCoinsText.anchor.set(1, 0); carnivalCoinsText.x = 1948; carnivalCoinsText.y = 100; carnivalScreen.addChild(carnivalCoinsText); // Back button for carnival var carnivalBackButton = carnivalScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 200, scaleX: 1.5, scaleY: 1.5 }); var carnivalBackText = new Text2('BACK', { size: 50, fill: 0xFFFFFF }); carnivalBackText.anchor.set(0.5, 0.5); carnivalBackText.x = 200; carnivalBackText.y = 200; carnivalScreen.addChild(carnivalBackText); // Tic Tac Toe button var ticTacToeButton = carnivalScreen.attachAsset('tictactoe_grid', { anchorX: 0.5, anchorY: 0.5, x: 512, y: 700, scaleX: 0.5, scaleY: 0.5 }); var ticTacToeText = new Text2('Itchy tac Scratchy', { size: 50, fill: 0xFFFFFF }); ticTacToeText.anchor.set(0.5, 0.5); ticTacToeText.x = 512; ticTacToeText.y = 900; carnivalScreen.addChild(ticTacToeText); var ticTacToeDesc = new Text2('Classic Tic Tac Toe\nWin: 25 coins', { size: 35, fill: 0xAAAAAA }); ticTacToeDesc.anchor.set(0.5, 0.5); ticTacToeDesc.x = 512; ticTacToeDesc.y = 980; carnivalScreen.addChild(ticTacToeDesc); // Hit the Mole button var hitMoleButton = carnivalScreen.attachAsset('mole_hole', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 700, scaleX: 2, scaleY: 2 }); var hitMoleText = new Text2('Hit the Mole', { size: 50, fill: 0xFFFFFF }); hitMoleText.anchor.set(0.5, 0.5); hitMoleText.x = 1024; hitMoleText.y = 900; carnivalScreen.addChild(hitMoleText); var hitMoleDesc = new Text2('Hit 5 Scratchys\nWin: 30 coins', { size: 35, fill: 0xAAAAAA }); hitMoleDesc.anchor.set(0.5, 0.5); hitMoleDesc.x = 1024; hitMoleDesc.y = 980; carnivalScreen.addChild(hitMoleDesc); // Horse Betting button var horseBettingButton = carnivalScreen.attachAsset('horse_track', { anchorX: 0.5, anchorY: 0.5, x: 1536, y: 700, scaleX: 0.3, scaleY: 0.5 }); var horseBettingText = new Text2('Horse Betting', { size: 50, fill: 0xFFFFFF }); horseBettingText.anchor.set(0.5, 0.5); horseBettingText.x = 1536; horseBettingText.y = 900; carnivalScreen.addChild(horseBettingText); var horseBettingDesc = new Text2('Bet on the winner\nWin: 40 coins', { size: 35, fill: 0xAAAAAA }); horseBettingDesc.anchor.set(0.5, 0.5); horseBettingDesc.x = 1536; horseBettingDesc.y = 980; carnivalScreen.addChild(horseBettingDesc); // Active mini-game var activeMiniGame = null; // GUI elements (hidden initially) var levelText = new Text2('Level 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); levelText.x = 150; levelText.visible = false; LK.gui.topLeft.addChild(levelText); var xpBarBg = LK.gui.top.attachAsset('xpbar_bg', { anchorX: 0.5, anchorY: 0, y: 10 }); xpBarBg.visible = false; var xpBarFill = LK.gui.top.attachAsset('xpbar_fill', { anchorX: 0, anchorY: 0, x: -150, y: 10, scaleX: 0 }); xpBarFill.visible = false; var coinText = new Text2('Coins: 0', { size: 50, fill: 0xFFD700 }); coinText.anchor.set(1, 0); coinText.visible = false; LK.gui.topRight.addChild(coinText); var healthBarBg = LK.gui.topLeft.attachAsset('healthbar_bg', { anchorX: 0, anchorY: 0, x: 120, y: 80 }); healthBarBg.visible = false; var healthBarFill = LK.gui.topLeft.attachAsset('healthbar_fill', { anchorX: 0, anchorY: 0, x: 120, y: 80, scaleX: 1 }); healthBarFill.visible = false; var waveText = new Text2('Wave 1', { size: 80, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0.5); waveText.visible = false; LK.gui.center.addChild(waveText); var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 1); scoreText.visible = false; LK.gui.bottom.addChild(scoreText); // Load saved data var savedCoins = 0; var savedWeapons = null; var savedSelected = null; var savedSubweapons = null; var savedSelectedSubweapon = null; try { savedCoins = storage.coins || 0; savedWeapons = storage.unlockedWeapons; savedSelected = storage.selectedWeapon; savedSubweapons = storage.unlockedSubweapons; savedSelectedSubweapon = storage.selectedSubweapon; } catch (e) { console.log('Storage not available:', e); } if (savedWeapons) { unlockedWeapons = savedWeapons; } if (savedSelected) { selectedWeapon = savedSelected; } if (savedSubweapons) { unlockedSubweapons = savedSubweapons; } if (savedSelectedSubweapon) { selectedSubweapon = savedSelectedSubweapon; } bart = game.addChild(new Bart()); bart.x = 1024; bart.y = 2000; bart.visible = false; bart.coins = savedCoins; // Set initial weapon visual bart.updateWeaponVisual(selectedWeapon); // Update coin display immediately coinText.setText('Coins: ' + bart.coins); // Update title screen coins display titleCoinsText.setText('Coins: ' + bart.coins); // Create shop screen shopScreen = new Container(); shopScreen.visible = false; game.addChild(shopScreen); // Create encyclopedia screen encyclopediaScreen = new Encyclopedia(); encyclopediaScreen.x = 1024; encyclopediaScreen.y = 1366; encyclopediaScreen.visible = false; game.addChild(encyclopediaScreen); // Shop tab system variables var currentTab = 'weapons'; // Shop title var shopTitle = new Text2('KRUSTY BURGER', { size: 100, fill: 0xFFFF00 }); shopTitle.anchor.set(0.5, 0.5); shopTitle.x = 1024; shopTitle.y = 150; shopScreen.addChild(shopTitle); // Weapons tab button var weaponsTabButton = shopScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 750, y: 250, scaleX: 2, scaleY: 1.5 }); weaponsTabButton.tint = 0x00FF00; // Active tab color var weaponsTabText = new Text2('WEAPONS', { size: 50, fill: 0xFFFFFF }); weaponsTabText.anchor.set(0.5, 0.5); weaponsTabText.x = 750; weaponsTabText.y = 250; shopScreen.addChild(weaponsTabText); // Subweapons tab button var subweaponsTabButton = shopScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1298, y: 250, scaleX: 2, scaleY: 1.5 }); var subweaponsTabText = new Text2('SUBWEAPONS', { size: 50, fill: 0xFFFFFF }); subweaponsTabText.anchor.set(0.5, 0.5); subweaponsTabText.x = 1298; subweaponsTabText.y = 250; shopScreen.addChild(subweaponsTabText); // Back button var backButton = shopScreen.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 200, scaleX: 1.5, scaleY: 1.5 }); var backText = new Text2('BACK', { size: 50, fill: 0xFFFFFF }); backText.anchor.set(0.5, 0.5); backText.x = 200; backText.y = 200; shopScreen.addChild(backText); // Coins display in shop var shopCoinsText = new Text2('Coins: 0', { size: 60, fill: 0xFFD700 }); shopCoinsText.anchor.set(1, 0.5); shopCoinsText.x = 1848; shopCoinsText.y = 200; shopScreen.addChild(shopCoinsText); // Containers for different tab content var weaponsContainer = new Container(); var subweaponsContainer = new Container(); shopScreen.addChild(weaponsContainer); shopScreen.addChild(subweaponsContainer); subweaponsContainer.visible = false; // Start with weapons tab active // Weapon buttons var weaponData = [{ id: 'slingshot', name: 'Slingshot', desc: 'The Default Weapon', y: 400 }, { id: 'dartgun', name: 'Dart Gun', desc: 'High damage, slow fire rate', y: 550 }, { id: 'scattershot', name: 'Scattershot', desc: 'Shoots peanuts that split into 3', y: 700 }, { id: 'ducky', name: 'Ducky Triple', desc: 'Shoots 3 projectiles', y: 850 }, { id: 'bow', name: 'Toy Bow', desc: 'Lower damage but 100% more XP!', y: 1000 }, { id: 'spraycan', name: 'Spraycan', desc: 'Medium damage, stuns for 1.2s', y: 1150 }, { id: 'pot', name: 'Pot-a-Bomb', desc: 'Area damage, chance to split into shards', y: 1300 }, { id: 'flower', name: "Krusty's Flower", desc: 'Water beam, rapid fire', y: 1450 }]; // Subweapon buttons var subweaponData = [{ id: 'santa_helper', name: "Santa's Little Helper", desc: 'Fast ally that bites enemies', y: 400 }, { id: 'krusty_shop', name: 'Krusty Burger Shop', desc: 'Spawns powerups every 15 seconds', y: 550 }, { id: 'snowball_cat', name: 'Snowball II', desc: 'Distracts enemies & reduces invincibility', y: 700 }]; subweaponData.forEach(function (subweapon) { // Subweapon button background var subweaponBg = subweaponsContainer.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: subweapon.y, scaleX: 8, scaleY: 2.4 }); subweaponBg.subweaponId = subweapon.id; // Subweapon name var subweaponName = new Text2(subweapon.name, { size: 50, fill: 0x00FFFF }); subweaponName.anchor.set(0.5, 0.5); subweaponName.x = 800; subweaponName.y = subweapon.y - 15; subweaponsContainer.addChild(subweaponName); // Subweapon description var subweaponDesc = new Text2(subweapon.desc, { size: 35, fill: 0xAAAAAA }); subweaponDesc.anchor.set(0.5, 0.5); subweaponDesc.x = 800; subweaponDesc.y = subweapon.y + 15; subweaponsContainer.addChild(subweaponDesc); // Price/status text var priceText = new Text2('Cost: ' + subweaponPrices[subweapon.id], { size: 45, fill: 0xFFD700 }); priceText.anchor.set(0.5, 0.5); priceText.x = 1400; priceText.y = subweapon.y; priceText.subweaponId = subweapon.id; subweaponsContainer.addChild(priceText); }); weaponData.forEach(function (weapon) { // Weapon button background var weaponBg = weaponsContainer.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: weapon.y, scaleX: 8, scaleY: 3 }); weaponBg.weaponId = weapon.id; // Weapon name var weaponName = new Text2(weapon.name, { size: 60, fill: 0xFFFFFF }); weaponName.anchor.set(0.5, 0.5); weaponName.x = 800; weaponName.y = weapon.y - 20; weaponsContainer.addChild(weaponName); // Weapon description var weaponDesc = new Text2(weapon.desc, { size: 40, fill: 0xAAAAAA }); weaponDesc.anchor.set(0.5, 0.5); weaponDesc.x = 800; weaponDesc.y = weapon.y + 20; weaponsContainer.addChild(weaponDesc); // Price/status text var priceText = new Text2(weapon.id === 'slingshot' ? 'OWNED' : 'Cost: ' + weaponPrices[weapon.id], { size: 50, fill: weapon.id === 'slingshot' ? 0x00FF00 : 0xFFD700 }); priceText.anchor.set(0.5, 0.5); priceText.x = 1400; priceText.y = weapon.y; priceText.weaponId = weapon.id; weaponsContainer.addChild(priceText); }); function switchShopTab(tabName) { currentTab = tabName; if (tabName === 'weapons') { weaponsContainer.visible = true; subweaponsContainer.visible = false; weaponsTabButton.tint = 0x00FF00; // Active tab color subweaponsTabButton.tint = 0xFFFFFF; // Inactive tab color } else if (tabName === 'subweapons') { weaponsContainer.visible = false; subweaponsContainer.visible = true; weaponsTabButton.tint = 0xFFFFFF; // Inactive tab color subweaponsTabButton.tint = 0x00FF00; // Active tab color } } function updateShopDisplay() { // Update coins in shop var shopCoinsText = shopScreen.children.find(function (child) { return child instanceof Text2 && child.text && child.text.startsWith('Coins:'); }); if (shopCoinsText) { shopCoinsText.setText('Coins: ' + bart.coins); } // Update title screen coins display titleCoinsText.setText('Coins: ' + bart.coins); // Update weapon status texts weaponsContainer.children.forEach(function (child) { if (child instanceof Text2 && child.weaponId) { if (unlockedWeapons.indexOf(child.weaponId) !== -1) { var newText = selectedWeapon === child.weaponId ? 'EQUIPPED' : 'OWNED'; var newColor = selectedWeapon === child.weaponId ? 0x00FFFF : 0x00FF00; child.setText(newText); // Remove old text and create new one with correct color var parent = child.parent; var x = child.x; var y = child.y; var weaponId = child.weaponId; parent.removeChild(child); var newTextObj = new Text2(newText, { size: 50, fill: newColor }); newTextObj.anchor.set(0.5, 0.5); newTextObj.x = x; newTextObj.y = y; newTextObj.weaponId = weaponId; parent.addChild(newTextObj); } } }); // Update subweapon status texts subweaponsContainer.children.forEach(function (child) { if (child instanceof Text2 && child.subweaponId) { if (unlockedSubweapons.indexOf(child.subweaponId) !== -1) { var newText = selectedSubweapon === child.subweaponId ? 'EQUIPPED' : 'OWNED'; var newColor = selectedSubweapon === child.subweaponId ? 0x00FFFF : 0x00FF00; child.setText(newText); // Remove old text and create new one with correct color var parent = child.parent; var x = child.x; var y = child.y; var subweaponId = child.subweaponId; parent.removeChild(child); var newTextObj = new Text2(newText, { size: 45, fill: newColor }); newTextObj.anchor.set(0.5, 0.5); newTextObj.x = x; newTextObj.y = y; newTextObj.subweaponId = subweaponId; parent.addChild(newTextObj); } } }); } function selectBossAfterAd() { // Show boss selection popup var bossChoiceOverlay = new Container(); game.addChild(bossChoiceOverlay); // Background var choiceBg = bossChoiceOverlay.attachAsset('info_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.8, scaleY: 0.6 }); // Title var choiceTitle = new Text2('Choose Your Boss!', { size: 80, fill: 0xFFD700 }); choiceTitle.anchor.set(0.5, 0.5); choiceTitle.x = 1024; choiceTitle.y = 900; bossChoiceOverlay.addChild(choiceTitle); // Mutant Leader button var mlButton = bossChoiceOverlay.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 700, y: 1200, scaleX: 2, scaleY: 1.5 }); mlButton.tint = 0x800080; var mlText = new Text2('Mutant Leader', { size: 40, fill: 0xFFFFFF }); mlText.anchor.set(0.5, 0.5); mlText.x = 700; mlText.y = 1200; bossChoiceOverlay.addChild(mlText); // Concert button var concertButton = bossChoiceOverlay.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1200, scaleX: 2, scaleY: 1.5 }); concertButton.tint = 0x2678d7; var concertText = new Text2('Concert', { size: 40, fill: 0xFFFFFF }); concertText.anchor.set(0.5, 0.5); concertText.x = 1024; concertText.y = 1200; bossChoiceOverlay.addChild(concertText); // UFO button var ufoButton = bossChoiceOverlay.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1348, y: 1200, scaleX: 2, scaleY: 1.5 }); ufoButton.tint = 0x4B0082; var ufoText = new Text2('UFO Striker', { size: 40, fill: 0xFFFFFF }); ufoText.anchor.set(0.5, 0.5); ufoText.x = 1348; ufoText.y = 1200; bossChoiceOverlay.addChild(ufoText); // Random button var randomButton = bossChoiceOverlay.attachAsset('healthbar_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1400, scaleX: 2, scaleY: 1.5 }); randomButton.tint = 0xFFD700; var randomText = new Text2('Random', { size: 40, fill: 0x000000 }); randomText.anchor.set(0.5, 0.5); randomText.x = 1024; randomText.y = 1400; bossChoiceOverlay.addChild(randomText); // Handle choice clicks bossChoiceOverlay.down = function (x, y, obj) { var localX = x; var localY = y; if (localX > 600 && localX < 800 && localY > 1150 && localY < 1250) { // Mutant Leader selectedGiantMutant = 'mutant_leader'; isGiantMutantRush = true; game.removeChild(bossChoiceOverlay); startGame(); } else if (localX > 924 && localX < 1124 && localY > 1150 && localY < 1250) { // Concert selectedGiantMutant = 'concert'; isGiantMutantRush = true; game.removeChild(bossChoiceOverlay); startGame(); } else if (localX > 1248 && localX < 1448 && localY > 1150 && localY < 1250) { // UFO Striker selectedGiantMutant = 'ufo_striker'; isGiantMutantRush = true; game.removeChild(bossChoiceOverlay); startGame(); } else if (localX > 924 && localX < 1124 && localY > 1350 && localY < 1450) { // Random selectedGiantMutant = 'random'; isGiantMutantRush = true; game.removeChild(bossChoiceOverlay); startGame(); } }; } function startGame() { gameStarted = true; // Hide title screen titleScreen.visible = false; // Show game elements bart.visible = true; levelText.visible = true; xpBarBg.visible = true; xpBarFill.visible = true; coinText.visible = true; waveText.visible = true; scoreText.visible = true; healthBarBg.visible = true; healthBarFill.visible = true; // Apply selected weapon stats var stats = weaponStats[selectedWeapon]; bart.damage = stats.damage; bart.fireRate = stats.fireRate; // Update Bart's visual appearance bart.updateWeaponVisual(selectedWeapon); // Giant Mutant Rush mode setup if (isGiantMutantRush) { // Set Bart to level 10 bart.level = 10; bart.xpToNext = 1000; bart.maxHealth = 100 + 9 * 20; // 9 level ups worth of health bart.health = bart.maxHealth; bart.damage = stats.damage + 9 * 5; // 9 level ups worth of damage bart.fireRate = Math.max(10, stats.fireRate - 9 * 2); // 9 level ups worth of fire rate // Update UI levelText.setText('Level ' + bart.level); healthBarFill.scaleX = 1; waveText.setText('GIANT MUTANT RUSH!'); waveText.tint = 0xFF0000; // Spawn the selected boss if (selectedGiantMutant === 'mutant_leader') { // Spawn the Mutant Leader var leader = new MutantLeader(); leader.x = 1024; leader.y = 400; enemies.push(leader); game.addChild(leader); } else if (selectedGiantMutant === 'concert') { // Spawn the Concert var concert = new Concert(); concert.x = 1024; concert.y = 400; // At top of screen enemies.push(concert); game.addChild(concert); } else if (selectedGiantMutant === 'ufo_striker') { // Spawn the UFO Striker var ufo = new UFOStriker(); ufo.x = 1024; ufo.y = 400; enemies.push(ufo); game.addChild(ufo); } else { // Random selection (fallback) var giantType = Math.random() * 3; if (giantType < 1) { // Spawn the Mutant Leader var leader = new MutantLeader(); leader.x = 1024; leader.y = 400; enemies.push(leader); game.addChild(leader); } else if (giantType < 2) { // Spawn the Concert var concert = new Concert(); concert.x = 1024; concert.y = 400; // At top of screen enemies.push(concert); game.addChild(concert); } else { // Spawn the UFO Striker var ufo = new UFOStriker(); ufo.x = 1024; ufo.y = 400; enemies.push(ufo); game.addChild(ufo); } } mutantLeaderSpawned = true; } // Spawn active subweapon if (selectedSubweapon) { if (selectedSubweapon === 'santa_helper') { activeSubweapon = new SantaHelper(); activeSubweapon.x = bart.x + 80; activeSubweapon.y = bart.y + 50; game.addChild(activeSubweapon); } else if (selectedSubweapon === 'krusty_shop') { activeSubweapon = new KrustyShop(); activeSubweapon.x = bart.x + 150; activeSubweapon.y = bart.y - 100; game.addChild(activeSubweapon); } else if (selectedSubweapon === 'snowball_cat') { activeSubweapon = new SnowballCat(); activeSubweapon.x = bart.x - 150; activeSubweapon.y = bart.y; game.addChild(activeSubweapon); } } // Create joystick joystick = LK.gui.bottomLeft.attachAsset('joystick_base', { anchorX: 0.5, anchorY: 0.5, x: joystickCenter.x, y: -150 }); joystick.alpha = 0.8; joystickKnob = LK.gui.bottomLeft.attachAsset('joystick_knob', { anchorX: 0.5, anchorY: 0.5, x: joystickCenter.x, y: -150 }); joystickKnob.alpha = 0.9; // Show initial wave text waveText.setText('Wave 1'); if (!isLowQualityMode) { tween(waveText, { scaleX: 2, scaleY: 2 }, { duration: 500, easing: tween.elasticOut }); tween(waveText, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.elasticIn }); } } function spawnEnemy() { var enemy; // Boss waves: 5, 10, 15, 20 if (wave % 5 === 0) { enemy = new Boss(); // Scale boss health and speed based on wave enemy.maxHealth = 500 + (wave - 5) * 200; enemy.health = enemy.maxHealth; enemy.speed = 1 + wave * 0.1; enemy.xpValue = 100 + wave * 20; } else { var mutantType = Math.random(); if (wave >= 8 && mutantType < 0.1) { enemy = new SamuraiMutant(); enemy.speed = 1.2 + wave * 0.2; enemy.maxHealth = 100 + wave * 15; enemy.health = enemy.maxHealth; enemy.xpValue = 50 + wave * 6; } else if (wave >= 13 && mutantType < 0.15) { enemy = new DrummerMutant(); enemy.speed = 0.8 + wave * 0.1; enemy.maxHealth = 150 + wave * 20; enemy.health = enemy.maxHealth; enemy.xpValue = 45 + wave * 5; } else if (wave >= 13 && mutantType < 0.25) { enemy = new VocalMutant(); enemy.speed = 5 + wave * 0.5; enemy.maxHealth = 40 + wave * 10; enemy.health = enemy.maxHealth; enemy.xpValue = 35 + wave * 4; } else if (wave >= 13 && mutantType < 0.35) { enemy = new RockerMutant(); enemy.speed = 2.5 + wave * 0.3; enemy.maxHealth = 70 + wave * 15; enemy.health = enemy.maxHealth; enemy.xpValue = 40 + wave * 5; } else if (wave >= 8 && mutantType < 0.45) { enemy = new PoetMutant(); enemy.speed = 1 + wave * 0.15; enemy.maxHealth = 80 + wave * 12; enemy.health = enemy.maxHealth; enemy.xpValue = 40 + wave * 5; } else if (wave >= 7 && mutantType < 0.55) { enemy = new ShooterMutant(); enemy.speed = 1.5 + wave * 0.2; enemy.maxHealth = 50 + wave * 10; enemy.health = enemy.maxHealth; enemy.xpValue = 25 + wave * 3; } else if (wave >= 6 && mutantType < 0.45) { enemy = new CookMutant(); enemy.speed = 1.5 + wave * 0.2; enemy.maxHealth = 60 + wave * 10; enemy.health = enemy.maxHealth; enemy.xpValue = 30 + wave * 4; } else if (wave >= 2 && mutantType < 0.65) { enemy = new FastMutant(); enemy.speed = 4 + wave * 0.4; enemy.maxHealth = 15 + wave * 8; enemy.health = enemy.maxHealth; enemy.xpValue = 15 + wave * 2; } else { enemy = new Mutant(); // Progressive scaling for mutants across all 20 waves enemy.speed = 2 + wave * 0.3; enemy.maxHealth = 30 + wave * 15; enemy.health = enemy.maxHealth; enemy.xpValue = 10 + wave * 2; } // Adjust invincibility based on wave if (wave >= 15) { // No invincibility at wave 15 onwards enemy.invincible = false; enemy.invincibilityTimer = 0; } else if (wave >= 10) { // Reduced invincibility (1.5 seconds) at wave 10 onwards enemy.invincibilityTimer = 90; // 1.5 seconds at 60fps } else { // Normal invincibility for waves 1-9 (3 seconds) enemy.invincibilityTimer = 180; // 3 seconds at 60fps } // Special mutant variants for higher waves if (wave >= 10) { enemy.speed += 1; enemy.maxHealth += 50; enemy.health = enemy.maxHealth; mutantGraphics = enemy.children[0]; if (mutantGraphics) { mutantGraphics.tint = 0xFF6666; // Red tint for stronger mutants } } if (wave >= 15) { enemy.speed += 1; enemy.maxHealth += 100; enemy.health = enemy.maxHealth; mutantGraphics = enemy.children[0]; if (mutantGraphics) { mutantGraphics.tint = 0xFF0000; // Dark red tint for elite mutants } } } enemy.x = Math.random() * 1848 + 100; enemy.y = -100; enemies.push(enemy); game.addChild(enemy); } function shootBullet() { if (bart.fireTimer > 0 || enemies.length === 0) return; var closestEnemy = null; var closestDist = Infinity; for (var i = 0; i < enemies.length; i++) { var dx = enemies[i].x - bart.x; var dy = enemies[i].y - bart.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < closestDist) { closestDist = dist; closestEnemy = enemies[i]; } } if (closestEnemy && closestDist < 800) { var stats = weaponStats[selectedWeapon]; if (selectedWeapon === 'flower') { // Continuous beam weapon var bullet = new FlowerBeam(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullet.speed = 25; bullets.push(bullet); game.addChild(bullet); } else if (selectedWeapon === 'dartgun') { // Dart gun projectile var bullet = new Dart(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } else if (selectedWeapon === 'scattershot') { // Scattershot peanut var bullet = new Peanut(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } else if (selectedWeapon === 'bow') { // Toy Bow rubber arrow var bullet = new RubberArrow(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } else if (selectedWeapon === 'pot') { // Pot-a-Bomb projectile var bullet = new PotBomb(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } else if (selectedWeapon === 'spraycan') { // Spraycan projectile var bullet = new Spray(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } else if (selectedWeapon === 'ducky') { // Triple shot with spread for (var i = -1; i <= 1; i++) { var bullet = new Bullet(); bullet.x = bart.x + i * 30; bullet.y = bart.y; // Create spread by offsetting target position var spreadAngle = i * 0.3; // 0.3 radians spread per bullet var targetDx = closestEnemy.x - bart.x; var targetDy = closestEnemy.y - bart.y; var targetDist = Math.sqrt(targetDx * targetDx + targetDy * targetDy); // Apply spread to target direction var currentAngle = Math.atan2(targetDy, targetDx); var newAngle = currentAngle + spreadAngle; // Create a virtual target with spread var virtualTarget = { x: bart.x + Math.cos(newAngle) * targetDist, y: bart.y + Math.sin(newAngle) * targetDist }; bullet.target = virtualTarget; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } } else { // Single shot (slingshot) var bullet = new Bullet(); bullet.x = bart.x; bullet.y = bart.y; bullet.target = closestEnemy; bullet.damage = bart.damage; bullets.push(bullet); game.addChild(bullet); } bart.fireTimer = bart.fireRate; LK.getSound('shoot').play(); } } function spawnItem(x, y, type) { var item; if (type === 'coin') { item = new Coin(); } else { item = new PowerUp(); } item.x = x; item.y = y; items.push(item); game.addChild(item); } game.down = function (x, y, obj) { if (!gameStarted) { if (bossSelectionScreen.visible) { // Boss selection screen interactions if (x > 100 && x < 300 && y > 100 && y < 300) { // Back button bossSelectionScreen.visible = false; titleScreen.visible = true; } else if (x > 724 && x < 1324 && y > 500 && y < 700) { // Mutant Leader button if (bart.coins >= 50) { bart.coins -= 50; try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins for Boss rush entry fee:', e); } coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); bossSelectionCoinsText.setText('Coins: ' + bart.coins); selectedGiantMutant = 'mutant_leader'; isGiantMutantRush = true; bossSelectionScreen.visible = false; startGame(); } } else if (x > 724 && x < 1324 && y > 750 && y < 950) { // Concert button if (bart.coins >= 50) { bart.coins -= 50; try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins for Boss rush entry fee:', e); } coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); bossSelectionCoinsText.setText('Coins: ' + bart.coins); selectedGiantMutant = 'concert'; isGiantMutantRush = true; bossSelectionScreen.visible = false; startGame(); } } else if (x > 724 && x < 1324 && y > 1000 && y < 1200) { // UFO Striker button if (bart.coins >= 50) { bart.coins -= 50; try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins for Boss rush entry fee:', e); } coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); bossSelectionCoinsText.setText('Coins: ' + bart.coins); selectedGiantMutant = 'ufo_striker'; isGiantMutantRush = true; bossSelectionScreen.visible = false; startGame(); } } else if (x > 724 && x < 1324 && y > 1250 && y < 1450) { // Random boss button if (bart.coins >= 50) { bart.coins -= 50; try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins for Boss rush entry fee:', e); } coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); bossSelectionCoinsText.setText('Coins: ' + bart.coins); selectedGiantMutant = 'random'; isGiantMutantRush = true; bossSelectionScreen.visible = false; startGame(); } } else if (x > 674 && x < 1374 && y > 400 && y < 500) { // Watch ad button if (!isWatchingAd) { isWatchingAd = true; adCountdown = 1800; // 30 seconds at 60fps bossSelectionScreen.visible = false; adOverlay.visible = true; } } } else if (carnivalScreen.visible) { // Carnival screen interactions if (activeMiniGame) { // Handle mini-game interactions if (activeMiniGame instanceof TicTacToe) { // Check cell clicks for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { var cell = activeMiniGame.cells[row][col]; var cellX = activeMiniGame.x + cell.x; var cellY = activeMiniGame.y + cell.y; if (x > cellX - 90 && x < cellX + 90 && y > cellY - 90 && y < cellY + 90) { activeMiniGame.makeMove(row, col); } } } } else if (activeMiniGame instanceof WhackAMole) { // Check mole clicks for (var i = 0; i < activeMiniGame.moles.length; i++) { var mole = activeMiniGame.moles[i]; var moleX = activeMiniGame.x + mole.x; var moleY = activeMiniGame.y + mole.y; if (x > moleX - 60 && x < moleX + 60 && y > moleY - 75 && y < moleY + 75) { activeMiniGame.hitMole(mole); } } } else if (activeMiniGame instanceof HorseBetting) { // Check horse selection if (x > 824 && x < 1024 && y > 1066 && y < 1266) { activeMiniGame.selectHorse('itchy'); } else if (x > 1224 && x < 1424 && y > 1066 && y < 1266) { activeMiniGame.selectHorse('scratchy'); } } } else { // Main carnival menu if (x > 100 && x < 300 && y > 100 && y < 300) { // Back button carnivalScreen.visible = false; titleScreen.visible = true; } else if (x > 312 && x < 712 && y > 500 && y < 1000) { // Tic Tac Toe if (bart.coins >= 10) { bart.coins -= 10; coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); carnivalCoinsText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } // Hide menu buttons ticTacToeButton.visible = false; ticTacToeText.visible = false; ticTacToeDesc.visible = false; hitMoleButton.visible = false; hitMoleText.visible = false; hitMoleDesc.visible = false; horseBettingButton.visible = false; horseBettingText.visible = false; horseBettingDesc.visible = false; carnivalTitle.visible = false; carnivalSubtitle.visible = false; // Start game activeMiniGame = new TicTacToe(); activeMiniGame.x = 1024; activeMiniGame.y = 1366; activeMiniGame.onComplete = function (won, coins) { if (won) { bart.coins += coins; coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); carnivalCoinsText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } } LK.setTimeout(function () { carnivalScreen.removeChild(activeMiniGame); activeMiniGame = null; // Show menu buttons again ticTacToeButton.visible = true; ticTacToeText.visible = true; ticTacToeDesc.visible = true; hitMoleButton.visible = true; hitMoleText.visible = true; hitMoleDesc.visible = true; horseBettingButton.visible = true; horseBettingText.visible = true; horseBettingDesc.visible = true; carnivalTitle.visible = true; carnivalSubtitle.visible = true; }, 2000); }; carnivalScreen.addChild(activeMiniGame); } else { LK.effects.flashObject(ticTacToeButton, 0xFF0000, 500); } } else if (x > 824 && x < 1224 && y > 500 && y < 1000) { // Hit the Mole if (bart.coins >= 10) { bart.coins -= 10; coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); carnivalCoinsText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } // Hide menu buttons ticTacToeButton.visible = false; ticTacToeText.visible = false; ticTacToeDesc.visible = false; hitMoleButton.visible = false; hitMoleText.visible = false; hitMoleDesc.visible = false; horseBettingButton.visible = false; horseBettingText.visible = false; horseBettingDesc.visible = false; carnivalTitle.visible = false; carnivalSubtitle.visible = false; // Start game activeMiniGame = new WhackAMole(); activeMiniGame.x = 1024; activeMiniGame.y = 1366; activeMiniGame.onComplete = function (won, coins) { if (won) { bart.coins += coins; coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); carnivalCoinsText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } } LK.setTimeout(function () { carnivalScreen.removeChild(activeMiniGame); activeMiniGame = null; // Show menu buttons again ticTacToeButton.visible = true; ticTacToeText.visible = true; ticTacToeDesc.visible = true; hitMoleButton.visible = true; hitMoleText.visible = true; hitMoleDesc.visible = true; horseBettingButton.visible = true; horseBettingText.visible = true; horseBettingDesc.visible = true; carnivalTitle.visible = true; carnivalSubtitle.visible = true; }, 2000); }; carnivalScreen.addChild(activeMiniGame); } else { LK.effects.flashObject(hitMoleButton, 0xFF0000, 500); } } else if (x > 1336 && x < 1736 && y > 500 && y < 1000) { // Horse Betting if (bart.coins >= 10) { bart.coins -= 10; coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); carnivalCoinsText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } // Hide menu buttons ticTacToeButton.visible = false; ticTacToeText.visible = false; ticTacToeDesc.visible = false; hitMoleButton.visible = false; hitMoleText.visible = false; hitMoleDesc.visible = false; horseBettingButton.visible = false; horseBettingText.visible = false; horseBettingDesc.visible = false; carnivalTitle.visible = false; carnivalSubtitle.visible = false; // Start game activeMiniGame = new HorseBetting(); activeMiniGame.x = 1024; activeMiniGame.y = 1366; activeMiniGame.onComplete = function (won, coins) { if (won) { bart.coins += coins; coinText.setText('Coins: ' + bart.coins); titleCoinsText.setText('Coins: ' + bart.coins); carnivalCoinsText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } } LK.setTimeout(function () { carnivalScreen.removeChild(activeMiniGame); activeMiniGame = null; // Show menu buttons again ticTacToeButton.visible = true; ticTacToeText.visible = true; ticTacToeDesc.visible = true; hitMoleButton.visible = true; hitMoleText.visible = true; hitMoleDesc.visible = true; horseBettingButton.visible = true; horseBettingText.visible = true; horseBettingDesc.visible = true; carnivalTitle.visible = true; carnivalSubtitle.visible = true; }, 2000); }; carnivalScreen.addChild(activeMiniGame); } else { LK.effects.flashObject(horseBettingButton, 0xFF0000, 500); } } } } else if (encyclopediaScreen.visible) { // Encyclopedia interactions var localX = x - encyclopediaScreen.x; var localY = y - encyclopediaScreen.y; if (localX > -75 && localX < 75 && localY > 325 && localY < 375) { // Close button encyclopediaScreen.visible = false; titleScreen.visible = true; } else if (localX > -275 && localX < -125 && localY > 255 && localY < 305) { // Previous button encyclopediaScreen.prevPage(); } else if (localX > 125 && localX < 275 && localY > 255 && localY < 305) { // Next button encyclopediaScreen.nextPage(); } } else if (shopScreen.visible) { // Shop interactions if (x > 100 && x < 300 && y > 100 && y < 300) { // Back button shopScreen.visible = false; titleScreen.visible = true; } // Tab buttons if (x > 650 && x < 850 && y > 200 && y < 300) { // Weapons tab switchShopTab('weapons'); } else if (x > 1198 && x < 1398 && y > 200 && y < 300) { // Subweapons tab switchShopTab('subweapons'); } // Subweapon buttons (only when subweapons tab is active) if (currentTab === 'subweapons') { var subweaponY = [400, 550, 700]; var subweaponIds = ['santa_helper', 'krusty_shop', 'snowball_cat']; for (var i = 0; i < subweaponY.length; i++) { if (x > 224 && x < 1824 && y > subweaponY[i] - 96 && y < subweaponY[i] + 96) { var subweaponId = subweaponIds[i]; if (unlockedSubweapons.indexOf(subweaponId) !== -1) { // Already owned - equip it selectedSubweapon = selectedSubweapon === subweaponId ? null : subweaponId; try { storage.selectedSubweapon = selectedSubweapon; } catch (e) { console.log('Could not save selected subweapon:', e); } updateShopDisplay(); } else if (bart.coins >= subweaponPrices[subweaponId]) { // Can afford - buy it bart.coins -= subweaponPrices[subweaponId]; unlockedSubweapons.push(subweaponId); selectedSubweapon = subweaponId; try { storage.coins = bart.coins; storage.unlockedSubweapons = unlockedSubweapons; storage.selectedSubweapon = selectedSubweapon; } catch (e) { console.log('Could not save subweapon purchase:', e); } updateShopDisplay(); } } } } // Weapon buttons (only when weapons tab is active) if (currentTab === 'weapons') { var weaponY = [400, 550, 700, 850, 1000, 1150, 1300, 1450]; var weaponIds = ['slingshot', 'dartgun', 'scattershot', 'ducky', 'bow', 'spraycan', 'pot', 'flower']; for (var i = 0; i < weaponY.length; i++) { if (x > 224 && x < 1824 && y > weaponY[i] - 120 && y < weaponY[i] + 120) { var weaponId = weaponIds[i]; if (unlockedWeapons.indexOf(weaponId) !== -1) { // Already owned - equip it selectedWeapon = weaponId; bart.updateWeaponVisual(selectedWeapon); try { storage.selectedWeapon = selectedWeapon; } catch (e) { console.log('Could not save selected weapon:', e); } updateShopDisplay(); } else if (bart.coins >= weaponPrices[weaponId]) { // Can afford - buy it bart.coins -= weaponPrices[weaponId]; unlockedWeapons.push(weaponId); selectedWeapon = weaponId; bart.updateWeaponVisual(selectedWeapon); try { storage.coins = bart.coins; storage.unlockedWeapons = unlockedWeapons; storage.selectedWeapon = selectedWeapon; } catch (e) { console.log('Could not save weapon purchase:', e); } updateShopDisplay(); } } } } } else { // Title screen if (x > 824 && x < 1224 && y > 1300 && y < 1500) { // Start button startGame(); } else if (x > 824 && x < 1224 && y > 1700 && y < 1900) { // Shop button titleScreen.visible = false; shopScreen.visible = true; updateShopDisplay(); } else if (x > 824 && x < 1224 && y > 2000 && y < 2200) { // Encyclopedia button titleScreen.visible = false; encyclopediaScreen.visible = true; } else if (x > 312 && x < 712 && y > 1900 && y < 2350) { // Carnival button titleScreen.visible = false; carnivalScreen.visible = true; carnivalCoinsText.setText('Coins: ' + bart.coins); } else if (x > 100 && x < 300 && y > 350 && y < 450) { // Quality toggle button toggleQualityMode(); } else if (x > 1286 && x < 1786 && y > 2000 && y < 2200) { // Giant Mutant Rush button - show boss selection if (bart.coins >= 50) { titleScreen.visible = false; bossSelectionScreen.visible = true; bossSelectionCoinsText.setText('Coins: ' + bart.coins); } else { // Flash button red to indicate insufficient funds LK.effects.flashObject(giantMutantRushButton, 0xFF0000, 500); } } } } else { // Check if touch is on joystick area var joystickScreenX = joystickCenter.x; var joystickScreenY = 2732 - 150; // Convert GUI coordinate to screen coordinate var distFromJoystick = Math.sqrt((x - joystickScreenX) * (x - joystickScreenX) + (y - joystickScreenY) * (y - joystickScreenY)); if (distFromJoystick <= joystickRadius * 2) { joystickPressed = true; updateJoystick(x, y); } } }; game.up = function (x, y, obj) { joystickPressed = false; joystickDirection.x = 0; joystickDirection.y = 0; if (joystickKnob) { joystickKnob.x = joystickCenter.x; joystickKnob.y = -150; } }; game.move = function (x, y, obj) { if (joystickPressed && !bart.stunned) { updateJoystick(x, y); } }; game.update = function () { if (!gameStarted) { // Animate title on title screen (reduce animation in low quality mode) if (!isLowQualityMode) { titleText.y = 800 + Math.sin(LK.ticks * 0.05) * 20; } // Update active mini-game if any if (activeMiniGame && activeMiniGame.update) { activeMiniGame.update(); } // Handle ad countdown if (isWatchingAd && adCountdown > 0) { adCountdown--; var secondsLeft = Math.ceil(adCountdown / 60); adCountdownText.setText(secondsLeft.toString()); // Animate countdown text if (adCountdown % 60 === 0) { tween(adCountdownText, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut }); tween(adCountdownText, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeIn }); } // Ad complete if (adCountdown <= 0) { isWatchingAd = false; adOverlay.visible = false; // Give free entry selectBossAfterAd(); } } return; } // Handle attack speed debuff if (bart.attackSpeedDebuffTimer && bart.attackSpeedDebuffTimer > 0) { bart.attackSpeedDebuffTimer--; if (bart.attackSpeedDebuffTimer <= 0) { bart.fireRate = bart.originalFireRate; // Restore Bart's normal weapon visual bart.updateWeaponVisual(selectedWeapon); } } // Update Bart position based on joystick if (gameStarted && joystickDirection.x !== 0 || joystickDirection.y !== 0) { if (!bart.stunned) { bart.x += joystickDirection.x * joystickSpeed; bart.y += joystickDirection.y * joystickSpeed; // Keep Bart within bounds bart.x = Math.max(60, Math.min(1988, bart.x)); bart.y = Math.max(80, Math.min(2652, bart.y)); } } shootBullet(); spawnTimer--; if (spawnTimer <= 0) { if (!isGiantMutantRush) { spawnEnemy(); // Dynamic spawn rate that gets faster but never too overwhelming var baseSpawnRate = 120 - wave * 4; if (wave >= 10) baseSpawnRate -= 20; // Faster spawning for waves 10+ if (wave >= 15) baseSpawnRate += 30; // Slower spawning for waves 15+ to reduce difficulty spawnTimer = Math.max(20, baseSpawnRate); } else { // Giant Mutant Rush mode - no regular spawning spawnTimer = 60; } } for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (bullet.shouldDestroy || bullet.y < -50 || bullet.y > 2782) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check for reflection by Samurai Mutant's katana var reflected = false; for (var s = 0; s < enemies.length; s++) { if (enemies[s] instanceof SamuraiMutant && !enemies[s].invincible) { var samurai = enemies[s]; var dx = bullet.x - samurai.x; var dy = bullet.y - samurai.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < samurai.reflectRadius) { // Reflect the bullet back towards Bart reflected = true; if (bart) { bullet.target = bart; // Reverse bullet direction var newDx = bart.x - bullet.x; var newDy = bart.y - bullet.y; var newDist = Math.sqrt(newDx * newDx + newDy * newDy); if (newDist > 0) { bullet.velocityX = newDx / newDist * bullet.speed; bullet.velocityY = newDy / newDist * bullet.speed; } } // Visual effect for reflection LK.effects.flashObject(samurai.katana, 0xFFFFFF, 200); LK.getSound('hit').play(); break; } } } if (reflected) continue; for (var j = enemies.length - 1; j >= 0; j--) { if (bullet.intersects(enemies[j])) { // Handle spray stun if (bullet instanceof Spray) { enemies[j].takeDamage(bullet.damage, bullet.stunDuration); } else { enemies[j].takeDamage(bullet.damage); } // Handle rubber arrow - no longer pierces if (bullet instanceof RubberArrow) { bullet.destroy(); bullets.splice(i, 1); break; } // Handle pot bomb explosion if (bullet instanceof PotBomb) { bullet.explode(); bullets.splice(i, 1); break; } // Handle peanut splitting if (bullet instanceof Peanut && !bullet.hasSplit) { bullet.hasSplit = true; // Create 3 small nuts for (var k = 0; k < 3; k++) { var nut = new SmallNut(); nut.x = bullet.x; nut.y = bullet.y; // Spread nuts in different directions var angle = (k - 1) * 0.8; // -0.8, 0, 0.8 radians nut.velocityX = Math.sin(angle) * 8; nut.velocityY = Math.cos(angle) * -8; bullets.push(nut); game.addChild(nut); } } bullet.destroy(); bullets.splice(i, 1); break; } } // Check if reflected bullet hits Bart if (bullet.target === bart && bullet.intersects(bart)) { bart.takeDamage(bullet.damage); bullet.destroy(); bullets.splice(i, 1); break; } // Check collision with alien meals for (var j = alienMeals.length - 1; j >= 0; j--) { if (bullet.intersects(alienMeals[j])) { alienMeals[j].destroy(); alienMeals.splice(j, 1); bullet.destroy(); bullets.splice(i, 1); LK.effects.flashObject(bullet, 0xFF0000, 200); break; } } } var bartTookDamage = false; for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.intersects(bart)) { if (enemy instanceof MutantLeader || enemy instanceof Concert || enemy instanceof UFOStriker) { // Instant kill for Giant Mutants (UFO Striker starts kidnapping instead) if (enemy instanceof UFOStriker) { // UFO Striker starts kidnapping on touch continue; // Skip normal damage, UFO handles it } bart.health = 0; bart.takeDamage(0); // Trigger game over } else { var damage = 10; if (enemy instanceof VocalMutant) { damage = enemy.getDamage(); } else if (enemy.damageMultiplier) { damage = Math.floor(10 * enemy.damageMultiplier); } bart.takeDamage(damage); enemy.shouldDestroy = true; } bartTookDamage = true; } if (enemy.y > 2832) { enemy.destroy(); enemies.splice(i, 1); } } // Handle speed boost timers for (var i = 0; i < enemies.length; i++) { if (enemies[i].speedBoosted && enemies[i].speedBoostTimer) { enemies[i].speedBoostTimer--; if (enemies[i].speedBoostTimer <= 0) { enemies[i].speed = enemies[i].originalSpeed; enemies[i].speedBoosted = false; } } } // Only process enemy destruction and XP gain if Bart didn't take damage this frame if (!bartTookDamage) { for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.shouldDestroy) { var xpToGain = enemy.xpValue; // Double XP for Toy Bow weapon if (selectedWeapon === 'bow') { xpToGain = enemy.xpValue * 2; } bart.gainXP(xpToGain); LK.setScore(LK.getScore() + enemy.xpValue); scoreText.setText('Score: ' + LK.getScore()); enemiesKilled++; // Automatic 350 coins for Giant Mutants in Giant Mutant Rush mode if (isGiantMutantRush && (enemy instanceof MutantLeader || enemy instanceof Concert || enemy instanceof UFOStriker)) { bart.coins += 350; coinText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins for Giant Mutant:', e); } } if (Math.random() < enemy.coinChance) { if (enemy instanceof MutantLeader) { // Drop tons of coins for Mutant Leader for (var c = 0; c < 20; c++) { spawnItem(enemy.x + (Math.random() - 0.5) * 200, enemy.y + (Math.random() - 0.5) * 200, 'coin'); } } else { spawnItem(enemy.x, enemy.y, 'coin'); } } if (Math.random() < enemy.powerupChance) { spawnItem(enemy.x, enemy.y, 'powerup'); } // Check if this was a Giant Mutant in Giant Mutant Rush mode if (isGiantMutantRush && (enemy instanceof MutantLeader || enemy instanceof Concert || enemy instanceof UFOStriker)) { // Victory! try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins on victory:', e); } LK.showYouWin(); } enemy.destroy(); enemies.splice(i, 1); // Dynamic enemy count per wave - starts at 10, increases every 5 waves var enemiesNeeded = 10 + Math.floor((wave - 1) / 5) * 5; if (enemiesKilled >= enemiesNeeded) { wave++; enemiesKilled = 0; // Infinite waves - no win condition waveText.setText('Wave ' + wave); // Special celebration for milestone waves if (wave % 5 === 0) { if (!isLowQualityMode) { LK.effects.flashScreen(0xFFD700, 1000); } waveText.tint = 0xFFD700; } else { waveText.tint = 0xFFFFFF; } if (!isLowQualityMode) { tween(waveText, { scaleX: 2, scaleY: 2 }, { duration: 500, easing: tween.elasticOut }); tween(waveText, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.elasticIn }); } } continue; } } } else { // If Bart took damage, still clean up destroyed enemies but don't give XP for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.shouldDestroy) { enemy.destroy(); enemies.splice(i, 1); } } } for (var i = items.length - 1; i >= 0; i--) { var item = items[i]; if (item.shouldDestroy) { item.destroy(); items.splice(i, 1); continue; } if (item.intersects(bart)) { if (item instanceof Coin) { bart.coins += item.value; coinText.setText('Coins: ' + bart.coins); try { storage.coins = bart.coins; } catch (e) { console.log('Could not save coins:', e); } LK.getSound('pickup').play(); } else if (item instanceof PowerUp) { if (item.type === 'damage') { bart.damage += 5; } else { bart.fireRate = Math.max(5, bart.fireRate - 5); } LK.getSound('powerup_pickup').play(); } item.destroy(); items.splice(i, 1); } } for (var i = enemyProjectiles.length - 1; i >= 0; i--) { var projectile = enemyProjectiles[i]; if (projectile.shouldDestroy || projectile.y < -50 || projectile.y > 2832 || projectile.x < -50 || projectile.x > 2098) { projectile.destroy(); enemyProjectiles.splice(i, 1); continue; } if (projectile.intersects(bart)) { // Handle StunRay stunning effect if (projectile instanceof StunRay) { bart.takeDamage(projectile.damage); if (!bart.stunned) { bart.stunned = true; bart.stunnedTimer = projectile.stunDuration; } } else { bart.takeDamage(projectile.damage); } projectile.destroy(); enemyProjectiles.splice(i, 1); } } for (var i = alienMeals.length - 1; i >= 0; i--) { var meal = alienMeals[i]; if (meal.shouldDestroy) { meal.destroy(); alienMeals.splice(i, 1); } } levelText.setText('Level ' + bart.level); xpBarFill.scaleX = bart.xp / bart.xpToNext; }; LK.playMusic('battle');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AlienMeal = Container.expand(function () {
var self = Container.call(this);
var mealGraphics = self.attachAsset('alien_meal', {
anchorX: 0.5,
anchorY: 0.5
});
self.invincibilityDuration = 600; // 10 seconds at 60fps
self.checkRadius = 80;
self.lifetime = 600; // 10 seconds
self.consumed = false;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
// Pulsing effect to show it's active
mealGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.2) * 0.3;
// Check for non-cook mutants touching the meal
if (!self.consumed) {
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
// Skip cook mutants - they can't consume their own meals
if (enemy instanceof CookMutant) continue;
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.checkRadius) {
// Give invincibility to this enemy
enemy.invincible = true;
enemy.invincibilityTimer = self.invincibilityDuration;
// Visual effect for invincibility gain
LK.effects.flashObject(enemy, 0x00FFFF, 500);
tween(enemy, {
tint: 0x00FFFF
}, {
duration: 200,
easing: tween.easeOut
});
tween(enemy, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeIn
});
// Mark meal as consumed
self.consumed = true;
self.shouldDestroy = true;
return;
}
}
}
};
return self;
});
var Bart = Container.expand(function () {
var self = Container.call(this);
var bartGraphics = self.attachAsset('bart_slingshot', {
anchorX: 0.5,
anchorY: 0.5
});
self.bartGraphics = bartGraphics;
self.currentWeapon = 'slingshot';
self.updateWeaponVisual = function (weaponId) {
if (self.currentWeapon === weaponId) return;
self.currentWeapon = weaponId;
var oldGraphics = self.bartGraphics;
var newGraphics = self.attachAsset('bart_' + weaponId, {
anchorX: 0.5,
anchorY: 0.5
});
newGraphics.x = oldGraphics.x;
newGraphics.y = oldGraphics.y;
newGraphics.rotation = oldGraphics.rotation;
newGraphics.alpha = oldGraphics.alpha;
newGraphics.scaleX = oldGraphics.scaleX;
newGraphics.scaleY = oldGraphics.scaleY;
self.removeChild(oldGraphics);
self.bartGraphics = newGraphics;
};
self.maxHealth = 100;
self.health = self.maxHealth;
self.level = 1;
self.xp = 0;
self.xpToNext = 100;
self.damage = 10;
self.fireRate = 30;
self.fireTimer = 0;
self.coins = 0;
self.stunned = false;
self.stunnedTimer = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('hut').play();
LK.effects.flashObject(self, 0xFF0000, 500);
if (healthBarFill) {
healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth);
}
if (self.health <= 0) {
try {
storage.coins = self.coins;
} catch (e) {
console.log('Could not save coins on game over:', e);
}
LK.showGameOver();
}
};
self.gainXP = function (amount) {
self.xp += amount;
while (self.xp >= self.xpToNext) {
self.xp -= self.xpToNext;
self.level++;
self.xpToNext = self.level * 100;
self.maxHealth += 20;
self.health = self.maxHealth;
if (healthBarFill) {
healthBarFill.scaleX = 1;
}
self.damage += 5;
self.fireRate = Math.max(10, self.fireRate - 2);
LK.getSound('levelup').play();
LK.effects.flashScreen(0xFFFF00, 300);
}
};
self.update = function () {
if (self.stunned) {
self.stunnedTimer--;
if (self.stunnedTimer <= 0) {
self.stunned = false;
}
}
self.fireTimer--;
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 500;
self.health = self.maxHealth;
self.speed = 1;
self.xpValue = 100;
self.coinChance = 1;
self.powerupChance = 0.5;
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
var healthBarBg = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
y: -100
});
self.healthBarFill = self.attachAsset('healthbar_fill', {
anchorX: 0,
anchorY: 0.5,
x: -100,
y: -100
});
self.takeDamage = function (damage) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
bossGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
bossGraphics.alpha = 1; // Reset to full opacity
}
}
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
}
};
return self;
});
var BowlingBall = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('bowling_ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 15;
self.targetX = 0;
self.targetY = 0;
self.directionSet = false;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 180;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (!self.directionSet) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.velocityX = dx / dist * self.speed;
self.velocityY = dy / dist * self.speed;
}
self.directionSet = true;
}
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += 0.2;
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 10;
self.speed = 15;
self.target = null;
self.lifetime = 60;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
} else {
self.y -= self.speed;
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 5;
self.lifetime = 300;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
}
self.rotation += 0.05;
};
return self;
});
var Concert = Container.expand(function () {
var self = Container.call(this);
var concertGraphics = self.attachAsset('concert', {
anchorX: 0.5,
anchorY: 0.5
});
// Band members
self.drummer = self.attachAsset('drummer', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: -100
});
self.vocal = self.attachAsset('vocal', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -120
});
self.rocker = self.attachAsset('rocker', {
anchorX: 0.5,
anchorY: 0.5,
x: 250,
y: -100
});
self.maxHealth = 25750;
self.health = self.maxHealth;
self.speed = 0; // Cannot move
self.xpValue = 2500;
self.coinChance = 1;
self.powerupChance = 1;
self.isInstantKillBoss = true; // Special flag to not destroy on contact
// Timers for abilities
self.drummerTimer = 225; // 3.75 seconds
self.swearTimer = 600; // 10 seconds
self.rockMusicTimer = 300; // 5 seconds
self.damageMultiplier = 1.0; // Starts at 100% damage
self.maxDamageMultiplier = 1.9; // Max 190% (90% increase)
// Regular mutant spawn timer
self.regularSpawnTimer = 120; // 2 seconds
// New attack timers
self.noisyDrummingTimer = 600; // 10 seconds
self.risingRockstarsTimer = 900; // 15 seconds
self.stereoSoundsTimer = 3600; // 60 seconds
// Health bar
var healthBarBg = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
y: -350,
scaleX: 2
});
self.healthBarFill = self.attachAsset('healthbar_fill', {
anchorX: 0,
anchorY: 0.5,
x: -200,
y: -350,
scaleX: 2
});
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth) * 2;
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
// Drop tons of coins
for (var i = 0; i < 30; i++) {
spawnItem(self.x + (Math.random() - 0.5) * 400, self.y + (Math.random() - 0.5) * 300, 'coin');
}
}
};
self.update = function () {
// Update timers
self.drummerTimer--;
self.swearTimer--;
self.rockMusicTimer--;
self.regularSpawnTimer--;
self.noisyDrummingTimer--;
self.risingRockstarsTimer--;
self.stereoSoundsTimer--;
// Excessive Drumming - shoot 3 soundwaves in spread
if (self.drummerTimer <= 0 && bart) {
for (var i = -1; i <= 1; i++) {
var soundWave = new SoundWave();
soundWave.x = self.x + self.drummer.x;
soundWave.y = self.y + self.drummer.y;
// Calculate spread angle
var angle = Math.atan2(bart.y - soundWave.y, bart.x - soundWave.x);
angle += i * 0.3; // 0.3 radians spread
soundWave.targetX = soundWave.x + Math.cos(angle) * 1000;
soundWave.targetY = soundWave.y + Math.sin(angle) * 1000;
soundWave.damage = 15 * self.damageMultiplier; // Slightly more damage than regular
enemyProjectiles.push(soundWave);
game.addChild(soundWave);
}
self.drummerTimer = 225; // Reset to 3.75 seconds
LK.effects.flashObject(self.drummer, 0xFF00FF, 500);
// Drummer animation
tween(self.drummer, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut
});
tween(self.drummer, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
// Noisy Drumming - shoot 10 sound waves really fast
if (self.noisyDrummingTimer <= 0 && bart) {
for (var i = 0; i < 10; i++) {
// Delay each sound wave slightly for rapid fire effect
LK.setTimeout(function (index) {
return function () {
if (bart && !self.destroyed) {
var soundWave = new SoundWave();
soundWave.x = self.x + self.drummer.x;
soundWave.y = self.y + self.drummer.y;
// Random spread pattern
var angle = Math.atan2(bart.y - soundWave.y, bart.x - soundWave.x);
angle += (Math.random() - 0.5) * 0.8; // Random spread
soundWave.targetX = soundWave.x + Math.cos(angle) * 1000;
soundWave.targetY = soundWave.y + Math.sin(angle) * 1000;
soundWave.damage = 20 * self.damageMultiplier; // More damage
soundWave.speed = 10; // Faster
enemyProjectiles.push(soundWave);
game.addChild(soundWave);
LK.effects.flashObject(self.drummer, 0xFFFF00, 100);
}
};
}(i), i * 100); // 100ms between each wave
}
self.noisyDrummingTimer = 600; // Reset to 10 seconds
}
// Swear-fest - increase damage multiplier
if (self.swearTimer <= 0) {
if (self.damageMultiplier < self.maxDamageMultiplier) {
self.damageMultiplier += 0.15; // 15% increase
self.damageMultiplier = Math.min(self.damageMultiplier, self.maxDamageMultiplier);
}
self.swearTimer = 600; // Reset to 10 seconds
LK.effects.flashScreen(0xFF0000, 300);
LK.effects.flashObject(self.vocal, 0xFF0000, 1000);
// Vocal animation
tween(self.vocal, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
tween(self.vocal, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Update all enemies' damage
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] !== self) {
enemies[i].damageMultiplier = self.damageMultiplier;
}
}
}
// Rock Music - make all mutants faster
if (self.rockMusicTimer <= 0) {
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] !== self && !enemies[i].rockerBoosted) {
enemies[i].originalSpeed = enemies[i].speed;
enemies[i].speed *= 1.3; // 30% speed boost
enemies[i].rockerBoosted = true;
enemies[i].rockerBoostTimer = 300; // 5 seconds
LK.effects.flashObject(enemies[i], 0x00FF00, 500);
}
}
self.rockMusicTimer = 300; // Reset to 5 seconds
LK.effects.flashObject(self.rocker, 0x00FF00, 1000);
// Rocker animation
tween(self.rocker, {
scaleX: 1.4,
scaleY: 1.4,
rotation: 0.3
}, {
duration: 250,
easing: tween.easeOut
});
tween(self.rocker, {
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 250,
easing: tween.easeIn
});
}
// Rising Rockstars - summon band member mutants
if (self.risingRockstarsTimer <= 0) {
// Spawn Drummer Mutant
var drummer = new DrummerMutant();
drummer.x = self.x - 300;
drummer.y = self.y + 300;
drummer.invincible = false;
drummer.invincibilityTimer = 0;
drummer.damageMultiplier = self.damageMultiplier;
enemies.push(drummer);
game.addChild(drummer);
// Spawn Vocal Mutant
var vocal = new VocalMutant();
vocal.x = self.x;
vocal.y = self.y + 350;
vocal.invincible = false;
vocal.invincibilityTimer = 0;
vocal.damageMultiplier = self.damageMultiplier;
enemies.push(vocal);
game.addChild(vocal);
// Spawn Rocker Mutant
var rocker = new RockerMutant();
rocker.x = self.x + 300;
rocker.y = self.y + 300;
rocker.invincible = false;
rocker.invincibilityTimer = 0;
rocker.damageMultiplier = self.damageMultiplier;
enemies.push(rocker);
game.addChild(rocker);
self.risingRockstarsTimer = 900; // Reset to 15 seconds
LK.effects.flashScreen(0xFF00FF, 500);
// Animation for summoning
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
// Rock fans - spawn regular mutants continuously
if (self.regularSpawnTimer <= 0) {
var mutant = new Mutant();
mutant.x = self.x + (Math.random() - 0.5) * 600;
mutant.y = self.y + 200;
// Apply current damage multiplier
mutant.damageMultiplier = self.damageMultiplier;
// Scale mutant stats based on wave
mutant.speed = 2 + wave * 0.3;
mutant.maxHealth = 30 + wave * 15;
mutant.health = mutant.maxHealth;
mutant.xpValue = 10 + wave * 2;
mutant.invincible = false;
mutant.invincibilityTimer = 0;
enemies.push(mutant);
game.addChild(mutant);
self.regularSpawnTimer = 120; // Reset to 2 seconds
}
// Handle rocker boost timers for all enemies
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].rockerBoosted && enemies[i].rockerBoostTimer) {
enemies[i].rockerBoostTimer--;
if (enemies[i].rockerBoostTimer <= 0) {
enemies[i].speed = enemies[i].originalSpeed;
enemies[i].rockerBoosted = false;
}
}
}
// Stereo Sounds - all band members shoot homing instakill soundwaves
if (self.stereoSoundsTimer <= 0 && bart) {
// Warning flash
LK.effects.flashScreen(0xFF0000, 1000);
// Drummer shoots homing soundwave
var drummerWave = new SoundWave();
drummerWave.x = self.x + self.drummer.x;
drummerWave.y = self.y + self.drummer.y;
drummerWave.damage = 9999; // Instakill
drummerWave.speed = 4; // Slower but homing
drummerWave.isHoming = true; // Mark as homing
drummerWave.target = bart;
enemyProjectiles.push(drummerWave);
game.addChild(drummerWave);
// Vocal shoots homing soundwave
var vocalWave = new SoundWave();
vocalWave.x = self.x + self.vocal.x;
vocalWave.y = self.y + self.vocal.y;
vocalWave.damage = 9999; // Instakill
vocalWave.speed = 4; // Slower but homing
vocalWave.isHoming = true; // Mark as homing
vocalWave.target = bart;
enemyProjectiles.push(vocalWave);
game.addChild(vocalWave);
// Rocker shoots homing soundwave
var rockerWave = new SoundWave();
rockerWave.x = self.x + self.rocker.x;
rockerWave.y = self.y + self.rocker.y;
rockerWave.damage = 9999; // Instakill
rockerWave.speed = 4; // Slower but homing
rockerWave.isHoming = true; // Mark as homing
rockerWave.target = bart;
enemyProjectiles.push(rockerWave);
game.addChild(rockerWave);
self.stereoSoundsTimer = 3600; // Reset to 60 seconds
// Epic animation for all band members
tween(self.drummer, {
scaleX: 2,
scaleY: 2,
tint: 0xFF0000
}, {
duration: 500,
easing: tween.easeOut
});
tween(self.vocal, {
scaleX: 2,
scaleY: 2,
tint: 0xFF0000
}, {
duration: 500,
easing: tween.easeOut
});
tween(self.rocker, {
scaleX: 2,
scaleY: 2,
tint: 0xFF0000
}, {
duration: 500,
easing: tween.easeOut
});
// Reset after animation
tween(self.drummer, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
tween(self.vocal, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
tween(self.rocker, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeIn
});
}
// Pulsing effect for band members
self.drummer.y = -100 + Math.sin(LK.ticks * 0.1) * 10;
self.vocal.y = -120 + Math.sin(LK.ticks * 0.15) * 8;
self.rocker.y = -100 + Math.sin(LK.ticks * 0.12) * 12;
};
return self;
});
var CookMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('cook_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 60;
self.health = self.maxHealth;
self.speed = 1.5;
self.xpValue = 30;
self.coinChance = 0.5;
self.powerupChance = 0.2;
self.cookTimer = 0;
self.cookInterval = 240; // 4 seconds
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1; // Reset to full opacity
}
}
self.cookTimer--;
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Cook alien meals when close to other enemies
if (self.cookTimer <= 0) {
var nearbyEnemies = [];
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] !== self) {
var eDx = enemies[i].x - self.x;
var eDy = enemies[i].y - self.y;
var eDist = Math.sqrt(eDx * eDx + eDy * eDy);
if (eDist < 300) {
nearbyEnemies.push(enemies[i]);
}
}
}
if (nearbyEnemies.length > 0) {
// Create an alien meal
var meal = new AlienMeal();
meal.x = self.x + (Math.random() - 0.5) * 100;
meal.y = self.y + (Math.random() - 0.5) * 100;
alienMeals.push(meal);
game.addChild(meal);
self.cookTimer = self.cookInterval;
LK.effects.flashObject(self, 0x00FF00, 300);
}
}
}
};
return self;
});
var Dart = Container.expand(function () {
var self = Container.call(this);
var dartGraphics = self.attachAsset('dart', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 10;
self.speed = 20;
self.target = null;
self.lifetime = 60;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
self.rotation = Math.atan2(dy, dx) + Math.PI / 2; // Point towards target
}
} else {
self.y -= self.speed;
}
};
return self;
});
var DrummerMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('drummer_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 150;
self.health = self.maxHealth;
self.speed = 0.8;
self.xpValue = 45;
self.coinChance = 0.6;
self.powerupChance = 0.3;
self.shootTimer = 0;
self.shootInterval = 90; // 1.5 seconds base
self.invincible = true;
self.invincibilityTimer = 180;
self.takeDamage = function (damage) {
if (self.invincible) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3;
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1;
}
}
self.shootTimer--;
// Check if Vocal is on screen to double attack speed
var vocalOnScreen = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] instanceof VocalMutant && enemies[i] !== self) {
vocalOnScreen = true;
break;
}
}
var currentInterval = vocalOnScreen ? self.shootInterval / 2 : self.shootInterval;
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Shoot sound waves at Bart (infinite range)
if (self.shootTimer <= 0) {
var soundWave = new SoundWave();
soundWave.x = self.x;
soundWave.y = self.y;
soundWave.targetX = bart.x;
soundWave.targetY = bart.y;
enemyProjectiles.push(soundWave);
game.addChild(soundWave);
self.shootTimer = currentInterval;
// Visual effect when shooting
LK.effects.flashObject(self, 0xFF00FF, 300);
}
}
};
return self;
});
var Encyclopedia = Container.expand(function () {
var self = Container.call(this);
// Background
var bg = self.attachAsset('encyclopedia', {
anchorX: 0.5,
anchorY: 0.5
});
// Title
self.titleText = new Text2('ENCYCLOPEDIA', {
size: 80,
fill: 0xFFFF00
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -300;
self.addChild(self.titleText);
// Page content container
self.pageContainer = new Container();
self.addChild(self.pageContainer);
// Close button
var closeButton = self.attachAsset('info_button', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 350
});
var closeText = new Text2('CLOSE', {
size: 40,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeText.y = 350;
self.addChild(closeText);
// Navigation buttons
var prevButton = self.attachAsset('info_button', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 280,
scaleX: 0.8
});
var prevText = new Text2('< PREV', {
size: 35,
fill: 0xFFFFFF
});
prevText.anchor.set(0.5, 0.5);
prevText.x = -200;
prevText.y = 280;
self.addChild(prevText);
var nextButton = self.attachAsset('info_button', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 280,
scaleX: 0.8
});
var nextText = new Text2('NEXT >', {
size: 35,
fill: 0xFFFFFF
});
nextText.anchor.set(0.5, 0.5);
nextText.x = 200;
nextText.y = 280;
self.addChild(nextText);
// Page indicator
self.pageIndicator = new Text2('Page 1/1', {
size: 30,
fill: 0xAAAAAA
});
self.pageIndicator.anchor.set(0.5, 0.5);
self.pageIndicator.y = 320;
self.addChild(self.pageIndicator);
self.currentPage = 0;
self.pages = [];
// Initialize encyclopedia content
self.initializePages = function () {
self.pages = [
// Enemies
{
title: "MUTANT",
content: "Basic enemy that moves towards Bart.\nHealth: 30 + (wave × 15)\nSpeed: 2 + (wave × 0.3)\nXP Value: 10 + (wave × 2)\nAppears from: Wave 1"
}, {
title: "FAST MUTANT",
content: "Quick enemy that rushes at Bart.\nHealth: 15 + (wave × 8)\nSpeed: 4 + (wave × 0.4)\nXP Value: 15 + (wave × 2)\nAppears from: Wave 2"
}, {
title: "SHOOTER MUTANT",
content: "Fires bowling balls at Bart.\nHealth: 50 + (wave × 10)\nSpeed: 1.5 + (wave × 0.2)\nXP Value: 25 + (wave × 3)\nAppears from: Wave 7"
}, {
title: "COOK MUTANT",
content: "Creates alien meals that grant invincibility.\nHealth: 60 + (wave × 10)\nSpeed: 1.5 + (wave × 0.2)\nXP Value: 30 + (wave × 4)\nAppears from: Wave 6"
}, {
title: "POET MUTANT",
content: "Summons other mutants to help!\nHealth: 80 + (wave × 12)\nSpeed: 1 + (wave × 0.15)\nXP Value: 40 + (wave × 5)\nAppears from: Wave 8"
}, {
title: "SAMURAI MUTANT",
content: "Has a spinning katana that reflects projectiles.\nHealth: 100 + (wave × 15)\nSpeed: 1.2 + (wave × 0.2)\nXP Value: 50 + (wave × 6)\nAppears from: Wave 8"
}, {
title: "DRUMMER MUTANT",
content: "High HP, shoots sound waves. Attack speed doubles if Vocal is present.\nHealth: 150 + (wave × 20)\nSpeed: 0.8 + (wave × 0.1)\nXP Value: 45 + (wave × 5)\nAppears from: Wave 13"
}, {
title: "VOCAL MUTANT",
content: "Fast with low HP. Damage doubles if Rocker is present.\nHealth: 40 + (wave × 10)\nSpeed: 5 + (wave × 0.5)\nXP Value: 35 + (wave × 4)\nAppears from: Wave 13"
}, {
title: "ROCKER MUTANT",
content: "Boosts ally speed for 5 seconds. Enhanced boost if Drummer is present.\nHealth: 70 + (wave × 15)\nSpeed: 2.5 + (wave × 0.3)\nXP Value: 40 + (wave × 5)\nAppears from: Wave 13"
}, {
title: "BOSS",
content: "Powerful enemy that appears every 5 waves.\nHealth: 500 + ((wave-5) × 200)\nSpeed: 1 + (wave × 0.1)\nXP Value: 100 + (wave × 20)\nAppears: Waves 5, 10, 15, 20..."
},
// Weapons
{
title: "SLINGSHOT",
content: "The default weapon.\nDamage: 10\nFire Rate: Medium\nProjectiles: 1\nCost: FREE (Starting weapon)"
}, {
title: "DART GUN",
content: "High damage, slow fire rate.\nDamage: 50\nFire Rate: Slow\nProjectiles: 1\nCost: 100 coins"
}, {
title: "SCATTERSHOT",
content: "Shoots peanuts that split.\nDamage: 15 (5 per split)\nFire Rate: Medium-Slow\nProjectiles: 1→3\nCost: 250 coins"
}, {
title: "DUCKY TRIPLE",
content: "Shoots 3 projectiles in a spread.\nDamage: 25\nFire Rate: Medium\nProjectiles: 3\nCost: 500 coins"
}, {
title: "SPRAYCAN",
content: "Stuns enemies on hit.\nDamage: 8\nFire Rate: Slow\nStun: 1.2 seconds\nCost: 750 coins"
}, {
title: "KRUSTY'S FLOWER",
content: "Water beam with rapid fire.\nDamage: 3\nFire Rate: Very Fast\nProjectiles: 1 (continuous)\nCost: 1000 coins"
}, {
title: "TOY BOW",
content: "Bart is now armed with a bow! Lower damage but 100% more XP.\nDamage: 12\nFire Rate: Medium-Fast\nSpecial: Double XP from all enemies\nCost: 600 coins"
}, {
title: "POT-A-BOMB",
content: "Bart holds a pot! Area damage with explosive potential.\nDamage: 35 (area effect)\nFire Rate: Slow\nSpecial: 30% chance to split into 4 diagonal shards\nCost: 800 coins"
},
// Subweapons
{
title: "SANTA'S LITTLE HELPER",
content: "Fast ally that bites enemies.\nDamage: 15 per bite\nSpeed: 12\nSight Range: 800 pixels\nCost: 750 coins"
}, {
title: "KRUSTY BURGER SHOP",
content: "Spawns powerups periodically.\nSpawn Rate: Every 15 seconds\nPowerup Types: Damage/Fire Rate\nCost: 1200 coins"
}, {
title: "SNOWBALL II",
content: "Sneaky cat that distracts enemies.\nDistraction Range: 600 pixels\nReduces invincibility by 50%\nSpeed: 8\nCost: 900 coins"
},
// Game Features
{
title: "POWER-UPS",
content: "Dropped by enemies randomly.\n• Damage Boost: +5 damage\n• Fire Rate: -5 fire rate delay\nDrop chance varies by enemy type."
}, {
title: "COINS",
content: "Currency for buying weapons.\nValue: 5 coins each\nDropped by defeated enemies.\nCoins are saved between games!"
}, {
title: "ALIEN MEALS",
content: "Created by Cook Mutants.\nGrants 10 seconds invincibility.\nCan be destroyed by shooting.\nOnly non-cook mutants can consume."
}, {
title: "INVINCIBILITY",
content: "Enemy spawn protection:\n• Waves 1-9: 3 seconds\n• Waves 10-14: 1.5 seconds\n• Wave 15+: No invincibility"
}, {
title: "LEVELING SYSTEM",
content: "Gain XP from defeating enemies.\nEach level grants:\n• +20 max health\n• +5 damage\n• -2 fire rate delay\nFull heal on level up!"
}, {
title: "WAVE PROGRESSION",
content: "Infinite waves with scaling difficulty.\nBosses appear every 5 waves.\nEnemies get stronger each wave.\nNew enemy types unlock at higher waves."
}];
};
self.showPage = function (pageIndex) {
// Clear previous content
self.pageContainer.removeChildren();
if (pageIndex >= 0 && pageIndex < self.pages.length) {
var page = self.pages[pageIndex];
// Page title
var pageTitle = new Text2(page.title, {
size: 60,
fill: 0x00FFFF
});
pageTitle.anchor.set(0.5, 0.5);
pageTitle.y = -200;
self.pageContainer.addChild(pageTitle);
// Page content
var lines = page.content.split('\n');
var yOffset = -100;
for (var i = 0; i < lines.length; i++) {
var contentLine = new Text2(lines[i], {
size: 35,
fill: 0xFFFFFF
});
contentLine.anchor.set(0.5, 0.5);
contentLine.y = yOffset;
self.pageContainer.addChild(contentLine);
yOffset += 45;
}
self.currentPage = pageIndex;
self.pageIndicator.setText('Page ' + (pageIndex + 1) + '/' + self.pages.length);
}
};
self.nextPage = function () {
if (self.currentPage < self.pages.length - 1) {
self.showPage(self.currentPage + 1);
}
};
self.prevPage = function () {
if (self.currentPage > 0) {
self.showPage(self.currentPage - 1);
}
};
self.initializePages();
self.showPage(0);
return self;
});
var FastMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('fast_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 15;
self.health = self.maxHealth;
self.speed = 4;
self.xpValue = 15;
self.coinChance = 0.2;
self.powerupChance = 0.05;
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
// Handle sleep effect
if (self.sleeping) {
self.sleepTimer--;
if (self.sleepTimer <= 0) {
self.sleeping = false;
self.speed = self.originalSpeed;
tween(self, {
alpha: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
return; // Don't move when sleeping
}
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1; // Reset to full opacity
}
}
var target = self.distractedBy || bart;
if (target) {
var dx = target.x - self.x;
var dy = target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
if (self.distractedBy && dist < 100) {
self.distractedBy = null;
}
}
};
return self;
});
var FlowerBeam = Container.expand(function () {
var self = Container.call(this);
var beamGraphics = self.attachAsset('flower_beam', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 10;
self.speed = 25;
self.target = null;
self.lifetime = 60;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
self.rotation = Math.atan2(dy, dx) + Math.PI / 2; // Point towards target
}
} else {
self.y -= self.speed;
}
};
return self;
});
var HorseBetting = Container.expand(function () {
var self = Container.call(this);
// Game state
self.selectedHorse = null;
self.raceStarted = false;
self.gameOver = false;
self.onComplete = null;
self.horsePositions = {
itchy: 0,
scratchy: 0
};
// Title
self.titleText = new Text2('HORSE BETTING', {
size: 60,
fill: 0xFFFFFF
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -400;
self.addChild(self.titleText);
// Instructions
self.instructionText = new Text2('Pick a horse to bet on!', {
size: 40,
fill: 0xAAAAAA
});
self.instructionText.anchor.set(0.5, 0.5);
self.instructionText.y = -340;
self.addChild(self.instructionText);
// Betting buttons
var itchyButton = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: -200,
scaleX: 2,
scaleY: 2
});
itchyButton.tint = 0xFF6666;
var itchyText = new Text2('Bet on Itchy', {
size: 40,
fill: 0xFFFFFF
});
itchyText.anchor.set(0.5, 0.5);
itchyText.x = -200;
itchyText.y = -200;
self.addChild(itchyText);
var scratchyButton = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: -200,
scaleX: 2,
scaleY: 2
});
scratchyButton.tint = 0x6666FF;
var scratchyText = new Text2('Bet on Scratchy', {
size: 40,
fill: 0xFFFFFF
});
scratchyText.anchor.set(0.5, 0.5);
scratchyText.x = 200;
scratchyText.y = -200;
self.addChild(scratchyText);
// Track
var track = self.attachAsset('horse_track', {
anchorX: 0.5,
anchorY: 0.5,
y: 100
});
// Finish line
var finishLine = self.attachAsset('finish_line', {
anchorX: 0.5,
anchorY: 0.5,
x: 600,
y: 100
});
// Horses
self.itchyHorse = self.attachAsset('horse_itchy', {
anchorX: 0.5,
anchorY: 0.5,
x: -600,
y: 50
});
self.scratchyHorse = self.attachAsset('horse_scratchy', {
anchorX: 0.5,
anchorY: 0.5,
x: -600,
y: 150
});
// Result text
self.resultText = new Text2('', {
size: 60,
fill: 0xFFD700
});
self.resultText.anchor.set(0.5, 0.5);
self.resultText.y = 350;
self.addChild(self.resultText);
self.selectHorse = function (horse) {
if (self.raceStarted || self.gameOver) return;
self.selectedHorse = horse;
self.instructionText.setText('You bet on ' + (horse === 'itchy' ? 'Itchy' : 'Scratchy') + '!');
// Start race after delay
LK.setTimeout(function () {
self.startRace();
}, 1000);
};
self.startRace = function () {
self.raceStarted = true;
self.instructionText.setText('They\'re off!');
// Hide betting buttons
itchyButton.visible = false;
itchyText.visible = false;
scratchyButton.visible = false;
scratchyText.visible = false;
};
self.update = function () {
if (!self.raceStarted || self.gameOver) return;
// Move horses with random speeds
var itchySpeed = 3 + Math.random() * 4;
var scratchySpeed = 3 + Math.random() * 4;
self.horsePositions.itchy += itchySpeed;
self.horsePositions.scratchy += scratchySpeed;
self.itchyHorse.x = -600 + self.horsePositions.itchy;
self.scratchyHorse.x = -600 + self.horsePositions.scratchy;
// Galloping animation
self.itchyHorse.y = 50 + Math.sin(LK.ticks * 0.3) * 10;
self.scratchyHorse.y = 150 + Math.sin(LK.ticks * 0.3 + 1) * 10;
// Check for winner
if (self.horsePositions.itchy >= 1200 || self.horsePositions.scratchy >= 1200) {
self.gameOver = true;
var winner = self.horsePositions.itchy >= 1200 ? 'itchy' : 'scratchy';
if (winner === self.selectedHorse) {
self.resultText.setText('You Win! +40 Coins!');
LK.getSound('carnival_win').play();
if (self.onComplete) self.onComplete(true, 40);
} else {
self.resultText.setText((winner === 'itchy' ? 'Itchy' : 'Scratchy') + ' Wins!');
LK.getSound('carnival_lose').play();
if (self.onComplete) self.onComplete(false, 0);
}
}
};
return self;
});
var KrustyShop = Container.expand(function () {
var self = Container.call(this);
var shopGraphics = self.attachAsset('krusty_shop', {
anchorX: 0.5,
anchorY: 0.5
});
self.powerupTimer = 900; // 15 seconds at 60fps
self.update = function () {
self.powerupTimer--;
// Pulse effect when close to spawning powerup
if (self.powerupTimer < 60) {
shopGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.5) * 0.5;
} else {
shopGraphics.alpha = 1;
}
if (self.powerupTimer <= 0) {
// Spawn powerup
spawnItem(self.x, self.y, 'powerup');
self.powerupTimer = 900; // Reset timer
LK.effects.flashObject(self, 0xFFFF00, 500);
}
// Gentle floating animation
self.y += Math.sin(LK.ticks * 0.03) * 0.3;
};
return self;
});
var LeaderBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('leader_bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 90;
self.targetX = 0;
self.targetY = 0;
self.directionSet = false;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 180;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (!self.directionSet) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.velocityX = dx / dist * self.speed;
self.velocityY = dy / dist * self.speed;
}
self.directionSet = true;
}
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += 0.15;
};
return self;
});
var Mutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 30;
self.health = self.maxHealth;
self.speed = 2;
self.xpValue = 10;
self.coinChance = 0.3;
self.powerupChance = 0.1;
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
self.stunned = false;
self.stunnedTimer = 0;
self.takeDamage = function (damage, stunDuration) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
if (!isLowQualityMode) {
LK.effects.flashObject(self, 0xFFFFFF, 200);
}
if (stunDuration && stunDuration > 0) {
self.stunned = true;
self.stunnedTimer = stunDuration;
}
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
// Handle sleep effect
if (self.sleeping) {
self.sleepTimer--;
if (self.sleepTimer <= 0) {
self.sleeping = false;
self.speed = self.originalSpeed;
tween(self, {
alpha: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
return; // Don't move when sleeping
}
if (self.stunned) {
self.stunnedTimer--;
mutantGraphics.tint = 0x00FF00; // Green tint when stunned
if (self.stunnedTimer <= 0) {
self.stunned = false;
mutantGraphics.tint = 0xFFFFFF;
}
return; // Don't move when stunned
}
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1; // Reset to full opacity
}
}
// Check if distracted by Snowball II
var target = self.distractedBy || bart;
if (target) {
var dx = target.x - self.x;
var dy = target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Reset distraction after getting close
if (self.distractedBy && dist < 100) {
self.distractedBy = null;
}
}
};
return self;
});
var MutantLeader = Container.expand(function () {
var self = Container.call(this);
var leaderGraphics = self.attachAsset('mutant_leader', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.maxHealth = 20000;
self.health = self.maxHealth;
self.speed = 3;
self.xpValue = 1000;
self.coinChance = 1;
self.coinValue = 100; // Drops 100 coins
self.powerupChance = 1;
self.isInstantKillBoss = true; // Special flag to not destroy on contact
self.rageMode = false;
self.originalSpeed = self.speed;
// Timers for abilities
self.callForHelpTimer = 600; // 10 seconds
self.gunAttackTimer = 300; // 5 seconds
self.whistleTimer = 1200; // 20 seconds
// Health bar
var healthBarBg = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
y: -150,
scaleX: 1.5
});
self.healthBarFill = self.attachAsset('healthbar_fill', {
anchorX: 0,
anchorY: 0.5,
x: -150,
y: -150,
scaleX: 1.5
});
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth) * 1.5;
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
// Drop tons of coins
for (var i = 0; i < 20; i++) {
spawnItem(self.x + (Math.random() - 0.5) * 200, self.y + (Math.random() - 0.5) * 200, 'coin');
}
}
};
self.update = function () {
// Update timers
self.callForHelpTimer--;
self.gunAttackTimer--;
self.whistleTimer--;
// Check for rage mode activation at 50% health
if (!self.rageMode && self.health <= self.maxHealth / 2) {
self.rageMode = true;
self.speed = self.originalSpeed * 1.5; // 50% faster
LK.effects.flashObject(self, 0xFF0000, 1000);
LK.effects.flashScreen(0xFF0000, 500);
// Visual effect for rage activation
tween(leaderGraphics, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 500,
easing: tween.easeOut
});
tween(leaderGraphics, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeIn
});
}
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Move towards Bart
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Call for help ability - faster in rage mode
var helpInterval = self.rageMode ? 270 : 600; // 4.5 seconds in rage, 10 seconds normal
if (self.callForHelpTimer <= 0) {
// Summon 3 random enemies
for (var i = 0; i < 3; i++) {
var enemyType = Math.random();
var enemy;
if (enemyType < 0.33) {
enemy = new Mutant();
} else if (enemyType < 0.66) {
enemy = new FastMutant();
} else {
enemy = new ShooterMutant();
}
// Spawn on opposite side of screen from Bart
enemy.x = bart.x < 1024 ? 1800 : 200;
enemy.y = Math.random() * 1800 + 400;
enemy.invincible = false;
enemy.invincibilityTimer = 0;
enemies.push(enemy);
game.addChild(enemy);
}
self.callForHelpTimer = helpInterval;
LK.effects.flashObject(self, 0x00FF00, 500);
// Play call help sound
LK.getSound('Callhelp').play();
}
// Gun attack ability
if (self.gunAttackTimer <= 0) {
var bullet = new LeaderBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.targetX = bart.x;
bullet.targetY = bart.y;
bullet.damage = 90; // Insane damage but not instant kill
bullet.speed = 12;
enemyProjectiles.push(bullet);
game.addChild(bullet);
self.gunAttackTimer = 300;
LK.effects.flashObject(self, 0xFF0000, 300);
}
// Whistle ability - reduce Bart's attack speed
if (self.whistleTimer <= 0) {
bart.originalFireRate = bart.fireRate;
bart.fireRate = bart.fireRate * 2; // Double fire rate delay (slower)
bart.attackSpeedDebuffTimer = 285; // 4.75 seconds
self.whistleTimer = 1200;
LK.effects.flashScreen(0x0000FF, 500);
LK.effects.flashObject(self, 0x0000FF, 1000);
// Change Bart to debuffed visual
bart.updateWeaponVisual('debuffed');
// Play whistle sound
LK.getSound('Whistleblow').play();
// Visual effect on Bart
tween(leaderGraphics, {
scaleX: 2,
scaleY: 2
}, {
duration: 300,
easing: tween.easeOut
});
tween(leaderGraphics, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeIn
});
}
}
};
return self;
});
var Peanut = Container.expand(function () {
var self = Container.call(this);
var peanutGraphics = self.attachAsset('peanut', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 15;
self.speed = 12;
self.target = null;
self.lifetime = 60;
self.hasSplit = false;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
} else {
self.y -= self.speed;
}
self.rotation += 0.1;
};
return self;
});
var PoetMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('poet_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 80;
self.health = self.maxHealth;
self.speed = 1;
self.xpValue = 40;
self.coinChance = 0.6;
self.powerupChance = 0.25;
self.summonTimer = 0;
self.summonInterval = 180; // 3 seconds
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1; // Reset to full opacity
}
}
self.summonTimer--;
// Apply damage multiplier if it exists
var actualDamage = 10;
if (self.damageMultiplier) {
actualDamage = Math.floor(10 * self.damageMultiplier);
}
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Summon mutants when close to player
if (self.summonTimer <= 0 && dist < 800) {
// Summon a basic mutant
var summonedMutant = new Mutant();
summonedMutant.x = self.x + (Math.random() - 0.5) * 200;
summonedMutant.y = self.y + (Math.random() - 0.5) * 200;
summonedMutant.maxHealth = 20 + wave * 8;
summonedMutant.health = summonedMutant.maxHealth;
summonedMutant.speed = 2 + wave * 0.2;
enemies.push(summonedMutant);
game.addChild(summonedMutant);
self.summonTimer = self.summonInterval;
LK.effects.flashObject(self, 0xFF00FF, 300);
}
}
};
return self;
});
var PotBomb = Container.expand(function () {
var self = Container.call(this);
var potGraphics = self.attachAsset('pot_bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 35;
self.speed = 12;
self.target = null;
self.lifetime = 240; // 4 seconds at 60fps - auto-explode to reduce lag
self.exploded = false;
self.explosionRadius = 120;
self.splitChance = 0.3; // 30% chance to split into shards
self.update = function () {
self.lifetime--;
// Auto-explode after 4 seconds (240 frames at 60fps) to reduce lag
if (self.lifetime <= 0) {
self.explode();
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
self.rotation += 0.15; // Spinning pot effect
}
} else {
self.y -= self.speed;
}
};
self.explode = function () {
if (self.exploded) return;
self.exploded = true;
// Hide the pot immediately
potGraphics.visible = false;
// Visual explosion effect
LK.effects.flashScreen(0xFF8C00, 300);
// Area damage to all enemies within radius
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.explosionRadius) {
enemy.takeDamage(self.damage);
LK.effects.flashObject(enemy, 0xFF8C00, 300);
}
}
// Always split into pottery shards
for (var i = 0; i < 4; i++) {
var shard = new PotteryShard();
shard.x = self.x;
shard.y = self.y;
// Set diagonal directions: NE, NW, SE, SW
var angle = i * Math.PI / 2 + Math.PI / 4; // 45, 135, 225, 315 degrees
shard.velocityX = Math.cos(angle) * shard.speed;
shard.velocityY = Math.sin(angle) * shard.speed;
bullets.push(shard);
game.addChild(shard);
}
self.shouldDestroy = true;
};
return self;
});
var PotteryShard = Container.expand(function () {
var self = Container.call(this);
var shardGraphics = self.attachAsset('pottery_shard', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 15;
self.speed = 10;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 60;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += 0.2; // Spinning shard effect
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.random() < 0.5 ? 'damage' : 'firerate';
self.lifetime = 300;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
}
self.rotation += 0.03;
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var RockerMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('rocker_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 70;
self.health = self.maxHealth;
self.speed = 2.5;
self.xpValue = 40;
self.coinChance = 0.5;
self.powerupChance = 0.2;
self.boostTimer = 0;
self.boostInterval = 300; // 5 seconds
self.invincible = true;
self.invincibilityTimer = 180;
self.takeDamage = function (damage) {
if (self.invincible) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3;
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1;
}
}
self.boostTimer--;
// Check if Drummer is on screen for enhanced boost
var drummerOnScreen = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] instanceof DrummerMutant && enemies[i] !== self) {
drummerOnScreen = true;
break;
}
}
// Apply speed boost to all allies
if (self.boostTimer <= 0) {
var boostAmount = drummerOnScreen ? 1.5 : 1; // Extra boost if drummer present
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] !== self && !enemies[i].speedBoosted) {
enemies[i].originalSpeed = enemies[i].speed;
enemies[i].speed += boostAmount;
enemies[i].speedBoosted = true;
enemies[i].speedBoostTimer = 300; // 5 seconds
// Visual effect for boosted enemies
LK.effects.flashObject(enemies[i], 0x00FF00, 500);
}
}
self.boostTimer = self.boostInterval;
// Visual effect when boosting
LK.effects.flashObject(self, 0x00FF00, 1000);
mutantGraphics.tint = 0x00FF00;
tween(mutantGraphics, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
}
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
}
};
return self;
});
var RubberArrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('rubber_arrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 20;
self.speed = 18;
self.target = null;
self.lifetime = 80;
self.pierceCount = 0;
self.maxPierce = 3;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
self.rotation = Math.atan2(dy, dx);
}
} else {
self.y -= self.speed;
}
};
return self;
});
var SamuraiMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('samurai_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
// Create katana - much bigger
self.katana = self.attachAsset('katana', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: 0,
scaleX: 2.5,
scaleY: 2.5
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.speed = 1.2;
self.xpValue = 50;
self.coinChance = 0.7;
self.powerupChance = 0.3;
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
self.katanaAngle = 0;
self.katanaRadius = 300; // Much farther from mutant
self.reflectRadius = 350; // Increased to match farther katana
self.takeDamage = function (damage) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1; // Reset to full opacity
}
}
// Rotate katana around the mutant - much faster
self.katanaAngle += 0.3; // Much faster rotation speed
self.katana.x = Math.cos(self.katanaAngle) * self.katanaRadius;
self.katana.y = Math.sin(self.katanaAngle) * self.katanaRadius;
self.katana.rotation = self.katanaAngle + Math.PI / 2; // Orient katana tangentially
// Move towards Bart
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
}
};
return self;
});
var SantaHelper = Container.expand(function () {
var self = Container.call(this);
var helperGraphics = self.attachAsset('santa_helper', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 15;
self.target = null;
self.attackCooldown = 0;
self.findTarget = function () {
var closestEnemy = null;
var closestDist = Infinity;
for (var i = 0; i < enemies.length; i++) {
var dx = enemies[i].x - self.x;
var dy = enemies[i].y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < closestDist && dist < 800) {
closestDist = dist;
closestEnemy = enemies[i];
}
}
return closestEnemy;
};
self.update = function () {
self.attackCooldown--;
// Find new target if current target is destroyed
if (!self.target || self.target.shouldDestroy || self.target.destroyed) {
self.target = self.findTarget();
}
if (self.target) {
// Move towards target aggressively
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Attack if close enough
if (dist < 60 && self.attackCooldown <= 0) {
self.target.takeDamage(self.damage);
self.attackCooldown = 20; // Attack every 0.33 seconds
LK.effects.flashObject(self, 0xFF0000, 200);
// Bite animation effect
tween(helperGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
tween(helperGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
} else {
// Follow Bart if no enemies
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 80) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
}
}
};
return self;
});
var ShooterMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('shooter_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 50;
self.health = self.maxHealth;
self.speed = 1.5;
self.xpValue = 25;
self.coinChance = 0.4;
self.powerupChance = 0.15;
self.shootTimer = 0;
self.shootInterval = 120;
self.invincible = true;
self.invincibilityTimer = 180; // 3 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invincible) return; // No damage during invincibility
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3; // Flashing effect
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1; // Reset to full opacity
}
}
self.shootTimer--;
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
if (self.shootTimer <= 0 && dist < 2567) {
var bowlingBall = new BowlingBall();
bowlingBall.x = self.x;
bowlingBall.y = self.y;
bowlingBall.targetX = bart.x;
bowlingBall.targetY = bart.y;
enemyProjectiles.push(bowlingBall);
game.addChild(bowlingBall);
self.shootTimer = self.shootInterval;
}
}
};
return self;
});
var SmallNut = Container.expand(function () {
var self = Container.call(this);
var nutGraphics = self.attachAsset('small_nut', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 5;
self.speed = 10;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 40;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += 0.2;
};
return self;
});
var SnowballCat = Container.expand(function () {
var self = Container.call(this);
var catGraphics = self.attachAsset('snowball_cat', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.distractionRadius = 600;
self.runDirection = 1;
self.runTimer = 0;
self.invincibilityReduction = 0.5; // Reduces invincibility time by 50%
self.velocityX = (Math.random() - 0.5) * self.speed * 2; // Random X velocity
self.velocityY = (Math.random() - 0.5) * self.speed * 2; // Random Y velocity
self.directionChangeTimer = 0;
self.update = function () {
// Change direction randomly every 1-3 seconds
self.directionChangeTimer++;
if (self.directionChangeTimer > 60 + Math.random() * 120) {
self.velocityX = (Math.random() - 0.5) * self.speed * 2;
self.velocityY = (Math.random() - 0.5) * self.speed * 2;
self.directionChangeTimer = 0;
}
// Move in current direction
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off edges with some randomness
if (self.x < 50) {
self.x = 50;
self.velocityX = Math.abs(self.velocityX) * (0.8 + Math.random() * 0.4);
self.velocityY = (Math.random() - 0.5) * self.speed;
} else if (self.x > 1998) {
self.x = 1998;
self.velocityX = -Math.abs(self.velocityX) * (0.8 + Math.random() * 0.4);
self.velocityY = (Math.random() - 0.5) * self.speed;
}
if (self.y < 50) {
self.y = 50;
self.velocityY = Math.abs(self.velocityY) * (0.8 + Math.random() * 0.4);
self.velocityX = (Math.random() - 0.5) * self.speed;
} else if (self.y > 2682) {
self.y = 2682;
self.velocityY = -Math.abs(self.velocityY) * (0.8 + Math.random() * 0.4);
self.velocityX = (Math.random() - 0.5) * self.speed;
}
// Check for nearby enemies to distract
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = self.x - enemy.x;
var dy = self.y - enemy.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.distractionRadius) {
// Make enemy follow the cat instead of Bart
enemy.distractedBy = self;
// Reduce invincibility time if enemy is invincible
if (enemy.invincible && enemy.invincibilityTimer > 0) {
enemy.invincibilityTimer = Math.floor(enemy.invincibilityTimer * self.invincibilityReduction);
}
}
}
// Animated running effect with rotation based on movement direction
var catGraphics = self.children[0];
catGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.1;
catGraphics.rotation = Math.atan2(self.velocityY, self.velocityX) * 0.2; // Face movement direction
};
return self;
});
var SoundBarrier = Container.expand(function () {
var self = Container.call(this);
// Create a wide barrier using multiple sound waves
self.waves = [];
for (var i = 0; i < 5; i++) {
var wave = self.attachAsset('sound_wave', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - 2) * 80,
y: 0,
scaleX: 1.2,
scaleY: 0.8,
tint: 0xFFD700,
alpha: 0.6
});
self.waves.push(wave);
}
self.health = 150;
self.lifetime = 600; // 10 seconds
self.width = 400;
self.height = 80;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
}
};
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
// Pulsing effect
for (var i = 0; i < self.waves.length; i++) {
self.waves[i].alpha = 0.4 + Math.sin(LK.ticks * 0.1 + i * 0.5) * 0.2;
self.waves[i].scaleY = 0.8 + Math.sin(LK.ticks * 0.15 + i * 0.3) * 0.1;
}
// Block enemy projectiles
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
var projectile = enemyProjectiles[i];
var dx = Math.abs(projectile.x - self.x);
var dy = Math.abs(projectile.y - self.y);
if (dx < self.width / 2 && dy < self.height / 2) {
self.takeDamage(projectile.damage || 10);
projectile.destroy();
enemyProjectiles.splice(i, 1);
}
}
// Slow down enemies passing through
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = Math.abs(enemy.x - self.x);
var dy = Math.abs(enemy.y - self.y);
if (dx < self.width / 2 && dy < self.height / 2) {
if (!enemy.barrierSlowed) {
enemy.barrierSlowed = true;
enemy.originalBarrierSpeed = enemy.speed;
enemy.speed *= 0.3; // 70% speed reduction
}
} else if (enemy.barrierSlowed) {
enemy.speed = enemy.originalBarrierSpeed;
enemy.barrierSlowed = false;
}
}
};
return self;
});
var SoundWave = Container.expand(function () {
var self = Container.call(this);
var waveGraphics = self.attachAsset('sound_wave', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 20; // Much faster than before
self.damage = 12;
self.targetX = 0;
self.targetY = 0;
self.directionSet = false;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 300; // Much longer lifespan
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
// Homing behavior for instakill soundwaves
if (self.isHoming && self.target && !self.target.destroyed) {
// Make homing sound waves smaller and faster with longer lifespan
if (self.lifetime === 300) {
// Initialize on first frame
waveGraphics.scaleX = 0.7; // Smaller than regular sound waves
waveGraphics.scaleY = 0.7;
self.lifetime = 350; // Slightly bigger lifespan than regular
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * (self.speed * 1.2); // Faster than regular speed
self.y += dy / dist * (self.speed * 1.2);
}
// Make it glow red for instakill waves
if (self.damage >= 9999) {
waveGraphics.tint = 0xFF0000;
}
} else {
// Standard projectile movement like bowling balls
if (!self.directionSet) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.velocityX = dx / dist * self.speed;
self.velocityY = dy / dist * self.speed;
}
self.directionSet = true;
}
self.x += self.velocityX;
self.y += self.velocityY;
}
// Enhanced glowing effect using tween
waveGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.3) * 0.2;
// Continuous scaling glow effect
tween(waveGraphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.9
}, {
duration: 500,
easing: tween.easeInOut
});
tween(waveGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut
});
};
return self;
});
var Spray = Container.expand(function () {
var self = Container.call(this);
var sprayGraphics = self.attachAsset('spray', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 8;
self.speed = 15;
self.target = null;
self.lifetime = 45;
self.stunDuration = 72; // 1.2 seconds at 60fps
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (self.target && !self.target.destroyed) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
self.rotation = Math.atan2(dy, dx);
}
} else {
self.y -= self.speed;
}
sprayGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.3) * 0.3;
};
return self;
});
var StunRay = Container.expand(function () {
var self = Container.call(this);
var rayGraphics = self.attachAsset('sound_wave', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x9400D3 // Purple color for stun ray
});
self.speed = 12;
self.damage = 30;
self.stunDuration = 45; // 0.75 seconds at 60fps
self.targetX = 0;
self.targetY = 0;
self.directionSet = false;
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 240;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.shouldDestroy = true;
return;
}
if (!self.directionSet) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.velocityX = dx / dist * self.speed;
self.velocityY = dy / dist * self.speed;
}
self.directionSet = true;
}
self.x += self.velocityX;
self.y += self.velocityY;
// Pulsing effect
rayGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.4) * 0.4;
rayGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
rayGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
};
return self;
});
var TicTacToe = Container.expand(function () {
var self = Container.call(this);
// Game state
self.board = [[null, null, null], [null, null, null], [null, null, null]];
self.currentPlayer = 'X'; // Player is X, AI is O
self.gameOver = false;
self.onComplete = null;
// Background
var bg = self.attachAsset('tictactoe_grid', {
anchorX: 0.5,
anchorY: 0.5
});
// Draw grid lines
var vLine1 = self.attachAsset('grid_line', {
anchorX: 0.5,
anchorY: 0.5,
x: -100,
scaleX: 0.017,
scaleY: 40
});
var vLine2 = self.attachAsset('grid_line', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
scaleX: 0.017,
scaleY: 40
});
var hLine1 = self.attachAsset('grid_line', {
anchorX: 0.5,
anchorY: 0.5,
y: -100,
scaleY: 0.67
});
var hLine2 = self.attachAsset('grid_line', {
anchorX: 0.5,
anchorY: 0.5,
y: 100,
scaleY: 0.67
});
// Title
self.titleText = new Text2('TIC TAC TOE', {
size: 60,
fill: 0xFFFFFF
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -380;
self.addChild(self.titleText);
// Instruction
self.instructionText = new Text2('You are Itchy (X), beat Scratchy (O)!', {
size: 40,
fill: 0xAAAAAA
});
self.instructionText.anchor.set(0.5, 0.5);
self.instructionText.y = -320;
self.addChild(self.instructionText);
// Result text
self.resultText = new Text2('', {
size: 60,
fill: 0xFFD700
});
self.resultText.anchor.set(0.5, 0.5);
self.resultText.y = 380;
self.addChild(self.resultText);
// Grid cells for interaction
self.cells = [];
for (var row = 0; row < 3; row++) {
self.cells[row] = [];
for (var col = 0; col < 3; col++) {
var cellBg = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: (col - 1) * 200,
y: (row - 1) * 200,
scaleX: 0.9,
scaleY: 4.5,
alpha: 0.01
});
cellBg.row = row;
cellBg.col = col;
self.cells[row][col] = cellBg;
}
}
self.makeMove = function (row, col) {
if (self.gameOver || self.board[row][col] !== null) return false;
self.board[row][col] = self.currentPlayer;
// Add visual mark
if (self.currentPlayer === 'X') {
var itchy = self.attachAsset('itchy', {
anchorX: 0.5,
anchorY: 0.5,
x: (col - 1) * 200,
y: (row - 1) * 200
});
} else {
var scratchy = self.attachAsset('scratchy', {
anchorX: 0.5,
anchorY: 0.5,
x: (col - 1) * 200,
y: (row - 1) * 200
});
}
// Check for winner
var winner = self.checkWinner();
if (winner) {
self.gameOver = true;
if (winner === 'X') {
self.resultText.setText('You Win! +25 Coins!');
LK.getSound('carnival_win').play();
if (self.onComplete) self.onComplete(true, 25);
} else {
self.resultText.setText('Scratchy Wins!');
LK.getSound('carnival_lose').play();
if (self.onComplete) self.onComplete(false, 0);
}
return true;
}
// Check for tie
if (self.isBoardFull()) {
self.gameOver = true;
self.resultText.setText('It\'s a Tie!');
LK.getSound('carnival_lose').play();
if (self.onComplete) self.onComplete(false, 0);
return true;
}
// Switch player
self.currentPlayer = self.currentPlayer === 'X' ? 'O' : 'X';
// AI move
if (self.currentPlayer === 'O' && !self.gameOver) {
LK.setTimeout(function () {
self.makeAIMove();
}, 500);
}
return true;
};
self.makeAIMove = function () {
// Simple AI - tries to win, block, or take center/corners
var bestMove = self.findBestMove();
if (bestMove) {
self.makeMove(bestMove.row, bestMove.col);
}
};
self.findBestMove = function () {
// Try to win
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (self.board[row][col] === null) {
self.board[row][col] = 'O';
if (self.checkWinner() === 'O') {
self.board[row][col] = null;
return {
row: row,
col: col
};
}
self.board[row][col] = null;
}
}
}
// Try to block
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (self.board[row][col] === null) {
self.board[row][col] = 'X';
if (self.checkWinner() === 'X') {
self.board[row][col] = null;
return {
row: row,
col: col
};
}
self.board[row][col] = null;
}
}
}
// Take center
if (self.board[1][1] === null) {
return {
row: 1,
col: 1
};
}
// Take corners
var corners = [[0, 0], [0, 2], [2, 0], [2, 2]];
for (var i = 0; i < corners.length; i++) {
if (self.board[corners[i][0]][corners[i][1]] === null) {
return {
row: corners[i][0],
col: corners[i][1]
};
}
}
// Take any available
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (self.board[row][col] === null) {
return {
row: row,
col: col
};
}
}
}
return null;
};
self.checkWinner = function () {
// Check rows
for (var row = 0; row < 3; row++) {
if (self.board[row][0] && self.board[row][0] === self.board[row][1] && self.board[row][1] === self.board[row][2]) {
return self.board[row][0];
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (self.board[0][col] && self.board[0][col] === self.board[1][col] && self.board[1][col] === self.board[2][col]) {
return self.board[0][col];
}
}
// Check diagonals
if (self.board[1][1]) {
if (self.board[0][0] === self.board[1][1] && self.board[1][1] === self.board[2][2]) {
return self.board[1][1];
}
if (self.board[0][2] === self.board[1][1] && self.board[1][1] === self.board[2][0]) {
return self.board[1][1];
}
}
return null;
};
self.isBoardFull = function () {
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (self.board[row][col] === null) {
return false;
}
}
}
return true;
};
return self;
});
var UFOStriker = Container.expand(function () {
var self = Container.call(this);
// Create UFO body using proper UFO asset
var ufoBody = self.attachAsset('ufo_striker', {
anchorX: 0.5,
anchorY: 0.5
});
// Add a dome on top
var ufoDome = self.attachAsset('ufo_dome', {
anchorX: 0.5,
anchorY: 0.5,
y: -60,
alpha: 0.8
});
self.maxHealth = 30550;
self.health = self.maxHealth;
self.speed = 2; // Faster speed (was 0.5)
self.xpValue = 3000;
self.coinChance = 1;
self.coinValue = 200;
self.powerupChance = 1;
self.isInstantKillBoss = true;
// Timers for abilities
self.stunRayTimer = 180; // 3 seconds
self.replicaTimer = 450; // 7.5 seconds
self.cloneTimer = 6000; // 100 seconds
self.kidnappingTarget = null;
self.kidnappingProgress = 0;
self.clones = [];
// Health bar
var healthBarBg = self.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
y: -180,
scaleX: 2
});
self.healthBarFill = self.attachAsset('healthbar_fill', {
anchorX: 0,
anchorY: 0.5,
x: -200,
y: -180,
scaleX: 2
});
self.takeDamage = function (damage) {
// Can't take damage while kidnapping
if (self.kidnappingTarget) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
self.healthBarFill.scaleX = Math.max(0, self.health / self.maxHealth) * 2;
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
// Drop many coins
for (var i = 0; i < 40; i++) {
spawnItem(self.x + (Math.random() - 0.5) * 300, self.y + (Math.random() - 0.5) * 300, 'coin');
}
}
};
self.startKidnapping = function (target) {
self.kidnappingTarget = target;
self.kidnappingProgress = 0;
// Freeze Bart
target.stunned = true;
target.stunnedTimer = 300; // 5 seconds
// Create tractor beam effect
var tractorBeam = self.attachAsset('tractor_beam', {
anchorX: 0.5,
anchorY: 0,
y: 50,
scaleY: 1,
tint: 0x00FF00,
alpha: 0.6
});
self.tractorBeam = tractorBeam;
// Start pulling animation
tween(target, {
y: self.y + 100
}, {
duration: 5000,
easing: tween.linear,
onFinish: function onFinish() {
// Kidnapping complete - game over
target.health = 0;
target.takeDamage(0);
}
});
};
self.executeRandomBossMove = function () {
// List of possible boss moves to replicate
var moves = ['summonEnemies', 'shootProjectiles', 'areaAttack', 'speedBoost'];
var selectedMove = moves[Math.floor(Math.random() * moves.length)];
switch (selectedMove) {
case 'summonEnemies':
// Summon 2 random enemies (like Mutant Leader)
for (var i = 0; i < 2; i++) {
var enemyType = Math.random();
var enemy;
if (enemyType < 0.5) {
enemy = new Mutant();
} else {
enemy = new FastMutant();
}
enemy.x = self.x + (Math.random() - 0.5) * 400;
enemy.y = self.y + 200;
enemy.invincible = false;
enemy.invincibilityTimer = 0;
enemies.push(enemy);
game.addChild(enemy);
}
LK.effects.flashObject(self, 0x00FF00, 500);
break;
case 'shootProjectiles':
// Shoot multiple sound waves (like Concert)
if (bart) {
for (var i = -2; i <= 2; i++) {
var soundWave = new SoundWave();
soundWave.x = self.x;
soundWave.y = self.y;
var angle = Math.atan2(bart.y - soundWave.y, bart.x - soundWave.x);
angle += i * 0.3;
soundWave.targetX = soundWave.x + Math.cos(angle) * 1000;
soundWave.targetY = soundWave.y + Math.sin(angle) * 1000;
soundWave.damage = 25;
enemyProjectiles.push(soundWave);
game.addChild(soundWave);
}
}
LK.effects.flashObject(self, 0xFF00FF, 500);
break;
case 'areaAttack':
// Flash area damage (like pot explosion)
LK.effects.flashScreen(0xFF0000, 300);
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 400) {
bart.takeDamage(40);
}
}
break;
case 'speedBoost':
// Boost all enemy speeds (like Concert's Rock Music)
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] !== self && !enemies[i].ufoSpeedBoosted) {
enemies[i].originalSpeed = enemies[i].speed;
enemies[i].speed *= 1.5;
enemies[i].ufoSpeedBoosted = true;
enemies[i].ufoSpeedBoostTimer = 300;
LK.effects.flashObject(enemies[i], 0x00FF00, 500);
}
}
break;
}
};
self.createClone = function () {
var clone = new UFOStrikerClone();
clone.x = self.x + (Math.random() - 0.5) * 300;
clone.y = self.y + (Math.random() - 0.5) * 300;
self.clones.push(clone);
enemies.push(clone);
game.addChild(clone);
LK.effects.flashScreen(0x0000FF, 500);
// Animation for cloning
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
};
self.update = function () {
// Update timers
self.stunRayTimer--;
self.replicaTimer--;
self.cloneTimer--;
// Clean up destroyed clones
self.clones = self.clones.filter(function (clone) {
return !clone.destroyed && !clone.shouldDestroy;
});
// Handle UFO speed boost timers
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].ufoSpeedBoosted && enemies[i].ufoSpeedBoostTimer) {
enemies[i].ufoSpeedBoostTimer--;
if (enemies[i].ufoSpeedBoostTimer <= 0) {
enemies[i].speed = enemies[i].originalSpeed;
enemies[i].ufoSpeedBoosted = false;
}
}
}
// Kidnapping logic
if (self.kidnappingTarget) {
self.kidnappingProgress++;
// Update tractor beam
if (self.tractorBeam) {
var dx = self.kidnappingTarget.x - self.x;
var dy = self.kidnappingTarget.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
self.tractorBeam.rotation = Math.atan2(dy, dx) + Math.PI / 2;
self.tractorBeam.scaleY = dist / 600; // Adjust beam length based on tractor beam height
}
if (self.kidnappingProgress >= 300) {
// Kidnapping complete
self.kidnappingTarget = null;
if (self.tractorBeam) {
self.removeChild(self.tractorBeam);
self.tractorBeam = null;
}
}
return; // Don't do other actions while kidnapping
}
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Try to kidnap if touching Bart
if (dist < 100 && !bart.stunned) {
self.startKidnapping(bart);
return;
}
// Move towards Bart slowly
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Stun-Ray ability
if (self.stunRayTimer <= 0) {
var stunRay = new StunRay();
stunRay.x = self.x;
stunRay.y = self.y;
stunRay.targetX = bart.x;
stunRay.targetY = bart.y;
enemyProjectiles.push(stunRay);
game.addChild(stunRay);
self.stunRayTimer = 180;
LK.effects.flashObject(self, 0x9400D3, 300);
}
// Replica ability
if (self.replicaTimer <= 0) {
self.executeRandomBossMove();
self.replicaTimer = 450;
}
// Clone ability
if (self.cloneTimer <= 0 && self.clones.length < 3) {
self.createClone();
self.cloneTimer = 6000;
}
}
// UFO hovering animation
ufoBody.y = Math.sin(LK.ticks * 0.05) * 10;
ufoDome.y = -60 + Math.sin(LK.ticks * 0.05) * 10;
// Add pulsing glow effect to dome
ufoDome.alpha = 0.6 + Math.sin(LK.ticks * 0.1) * 0.2;
};
return self;
});
var UFOStrikerClone = Container.expand(function () {
var self = Container.call(this);
// Create UFO shape with blue tint
var ufoBody = self.attachAsset('ufo_striker', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x0000FF // Blue tint for clone
});
var ufoDome = self.attachAsset('ufo_dome', {
anchorX: 0.5,
anchorY: 0.5,
y: -50,
scaleX: 0.8,
scaleY: 0.8,
tint: 0x00BFFF,
alpha: 0.7
});
self.maxHealth = 10000;
self.health = self.maxHealth;
self.speed = 0.8;
self.xpValue = 500;
self.coinChance = 0.8;
self.powerupChance = 0.5;
// Simple AI - just move and shoot
self.shootTimer = 120;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.update = function () {
self.shootTimer--;
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Shoot stun rays
if (self.shootTimer <= 0) {
var stunRay = new StunRay();
stunRay.x = self.x;
stunRay.y = self.y;
stunRay.targetX = bart.x;
stunRay.targetY = bart.y;
stunRay.damage = 15; // Less damage than original
stunRay.stunDuration = 30; // 0.5 seconds
enemyProjectiles.push(stunRay);
game.addChild(stunRay);
self.shootTimer = 120;
}
}
// UFO hovering animation
ufoBody.y = Math.sin(LK.ticks * 0.05 + self.x) * 8;
ufoDome.y = -50 + Math.sin(LK.ticks * 0.05 + self.x) * 8;
// Pulsing glow effect for clone dome
ufoDome.alpha = 0.5 + Math.sin(LK.ticks * 0.12) * 0.2;
};
return self;
});
var VocalMutant = Container.expand(function () {
var self = Container.call(this);
var mutantGraphics = self.attachAsset('vocal_mutant', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 40;
self.health = self.maxHealth;
self.speed = 5;
self.xpValue = 35;
self.coinChance = 0.4;
self.powerupChance = 0.15;
self.baseDamage = 15; // Base damage when swearing at Bart
self.invincible = true;
self.invincibilityTimer = 180;
self.takeDamage = function (damage) {
if (self.invincible) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.shouldDestroy = true;
LK.getSound('hit').play();
}
};
self.getDamage = function () {
// Check if Rocker is on screen to double damage
var rockerOnScreen = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] instanceof RockerMutant && enemies[i] !== self) {
rockerOnScreen = true;
break;
}
}
return rockerOnScreen ? self.baseDamage * 2 : self.baseDamage;
};
self.update = function () {
if (self.invincible) {
self.invincibilityTimer--;
mutantGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.3;
if (self.invincibilityTimer <= 0) {
self.invincible = false;
mutantGraphics.alpha = 1;
}
}
if (bart) {
var dx = bart.x - self.x;
var dy = bart.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
}
};
return self;
});
var WhackAMole = Container.expand(function () {
var self = Container.call(this);
// Game state
self.score = 0;
self.timeLeft = 30; // 30 seconds
self.gameOver = false;
self.onComplete = null;
self.moles = [];
// Title
self.titleText = new Text2('HIT THE MOLE', {
size: 60,
fill: 0xFFFFFF
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -400;
self.addChild(self.titleText);
// Instructions
self.instructionText = new Text2('Hit 5 Scratchys to win! Avoid Itchys!', {
size: 40,
fill: 0xAAAAAA
});
self.instructionText.anchor.set(0.5, 0.5);
self.instructionText.y = -340;
self.addChild(self.instructionText);
// Score text
self.scoreText = new Text2('Score: 0/5', {
size: 50,
fill: 0xFFD700
});
self.scoreText.anchor.set(0.5, 0.5);
self.scoreText.y = -280;
self.addChild(self.scoreText);
// Timer text
self.timerText = new Text2('Time: 30', {
size: 50,
fill: 0xFFFFFF
});
self.timerText.anchor.set(0.5, 0.5);
self.timerText.y = 350;
self.addChild(self.timerText);
// Create mole holes
self.holes = [];
var positions = [{
x: -300,
y: -150
}, {
x: 0,
y: -150
}, {
x: 300,
y: -150
}, {
x: -300,
y: 50
}, {
x: 0,
y: 50
}, {
x: 300,
y: 50
}, {
x: -300,
y: 250
}, {
x: 0,
y: 250
}, {
x: 300,
y: 250
}];
for (var i = 0; i < positions.length; i++) {
var hole = self.attachAsset('mole_hole', {
anchorX: 0.5,
anchorY: 0.5,
x: positions[i].x,
y: positions[i].y
});
self.holes.push(hole);
}
// Result text
self.resultText = new Text2('', {
size: 60,
fill: 0xFFD700
});
self.resultText.anchor.set(0.5, 0.5);
self.resultText.y = 420;
self.addChild(self.resultText);
self.spawnMole = function () {
if (self.gameOver) return;
var holeIndex = Math.floor(Math.random() * self.holes.length);
var isItchy = Math.random() < 0.3; // 30% chance for Itchy
var mole = self.attachAsset(isItchy ? 'itchy' : 'scratchy', {
anchorX: 0.5,
anchorY: 0.5,
x: self.holes[holeIndex].x,
y: self.holes[holeIndex].y
});
mole.isItchy = isItchy;
mole.lifetime = 120; // 2 seconds
mole.clicked = false;
// Pop up animation
mole.scaleY = 0;
tween(mole, {
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
self.moles.push(mole);
};
self.hitMole = function (mole) {
if (mole.clicked || self.gameOver) return;
mole.clicked = true;
LK.getSound('whack').play();
if (mole.isItchy) {
// Hit Itchy - lose!
self.gameOver = true;
self.resultText.setText('You hit Itchy! Game Over!');
LK.getSound('carnival_lose').play();
if (self.onComplete) self.onComplete(false, 0);
} else {
// Hit Scratchy - score!
self.score++;
self.scoreText.setText('Score: ' + self.score + '/5');
if (self.score >= 5) {
self.gameOver = true;
self.resultText.setText('You Win! +30 Coins!');
LK.getSound('carnival_win').play();
if (self.onComplete) self.onComplete(true, 30);
}
}
// Hide mole
tween(mole, {
scaleY: 0
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
self.removeChild(mole);
}
});
};
self.update = function () {
if (self.gameOver) return;
// Update timer
if (LK.ticks % 60 === 0) {
self.timeLeft--;
self.timerText.setText('Time: ' + self.timeLeft);
if (self.timeLeft <= 0) {
self.gameOver = true;
self.resultText.setText('Time\'s Up!');
LK.getSound('carnival_lose').play();
if (self.onComplete) self.onComplete(false, 0);
}
}
// Spawn moles
if (LK.ticks % 45 === 0) {
self.spawnMole();
}
// Update moles
for (var i = self.moles.length - 1; i >= 0; i--) {
var mole = self.moles[i];
mole.lifetime--;
if (mole.lifetime <= 0) {
tween(mole, {
scaleY: 0
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
self.removeChild(mole);
}
});
self.moles.splice(i, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000080,
width: isLowQualityMode ? 1080 : 2048,
height: isLowQualityMode ? 1920 : 2732
});
/****
* Game Code
****/
var bart;
var enemies = [];
var bullets = [];
var items = [];
var enemyProjectiles = [];
var alienMeals = [];
var wave = 1;
var enemiesKilled = 0;
var spawnTimer = 0;
var dragTarget = null;
var gameStarted = false;
var titleScreen;
var startButton;
var titleText;
var shopScreen;
var shopButton;
var selectedWeapon = 'slingshot';
var unlockedWeapons = ['slingshot'];
var weaponPrices = {
dartgun: 100,
scattershot: 250,
ducky: 500,
spraycan: 750,
flower: 1000,
bow: 600,
pot: 800
};
var isGiantMutantRush = false;
var giantMutantRushButton;
var mutantLeaderSpawned = false;
var isLowQualityMode = false;
var savedQualityMode = false;
// Load saved quality mode
try {
savedQualityMode = storage.qualityMode === 'low';
isLowQualityMode = savedQualityMode;
} catch (e) {
console.log('Could not load quality mode:', e);
}
// Joystick variables
var joystick = null;
var joystickKnob = null;
var joystickPressed = false;
var joystickCenter = {
x: 200,
y: 2400
};
var joystickRadius = 80;
var joystickDirection = {
x: 0,
y: 0
};
var joystickSpeed = 8;
function updateJoystick(touchX, touchY) {
if (!joystickKnob) return;
var joystickScreenX = joystickCenter.x;
var joystickScreenY = 2732 - 150; // Convert GUI coordinate to screen coordinate
var deltaX = touchX - joystickScreenX;
var deltaY = touchY - joystickScreenY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Limit knob movement to joystick radius
if (distance > joystickRadius) {
deltaX = deltaX / distance * joystickRadius;
deltaY = deltaY / distance * joystickRadius;
distance = joystickRadius;
}
// Update knob position
joystickKnob.x = joystickCenter.x + deltaX;
joystickKnob.y = -150 + deltaY;
// Calculate movement direction (normalized)
if (distance > 10) {
// Dead zone
joystickDirection.x = deltaX / joystickRadius;
joystickDirection.y = deltaY / joystickRadius;
} else {
joystickDirection.x = 0;
joystickDirection.y = 0;
}
}
function toggleQualityMode() {
isLowQualityMode = !isLowQualityMode;
// Update button appearance
var qualityButton = titleScreen.children.find(function (child) {
return child.tint === 0x00FF00 || child.tint === 0xFF0000;
});
var qualityText = titleScreen.children.find(function (child) {
return child instanceof Text2 && (child.text === 'HD' || child.text === 'FHD');
});
if (isLowQualityMode) {
if (qualityButton) qualityButton.tint = 0xFF0000; // Red for low quality
if (qualityText) qualityText.setText('FHD');
// Low quality mode is now handled through conditional checks in game logic
} else {
if (qualityButton) qualityButton.tint = 0x00FF00; // Green for high quality
if (qualityText) qualityText.setText('HD');
// High quality mode is the default
}
// Save preference
try {
storage.qualityMode = isLowQualityMode ? 'low' : 'high';
} catch (e) {
console.log('Could not save quality mode:', e);
}
}
// Apply saved quality mode on startup
if (isLowQualityMode) {
LK.setTimeout(function () {
toggleQualityMode();
toggleQualityMode(); // Toggle twice to properly set initial state
}, 100);
}
var weaponStats = {
slingshot: {
damage: 10,
fireRate: 30,
projectileCount: 1
},
dartgun: {
damage: 50,
fireRate: 60,
projectileCount: 1
},
scattershot: {
damage: 15,
fireRate: 40,
projectileCount: 1
},
ducky: {
damage: 25,
fireRate: 45,
projectileCount: 3
},
spraycan: {
damage: 8,
fireRate: 50,
projectileCount: 1
},
flower: {
damage: 3,
fireRate: 6,
projectileCount: 1
},
bow: {
damage: 12,
fireRate: 35,
projectileCount: 1
},
pot: {
damage: 35,
fireRate: 55,
projectileCount: 1
}
};
var selectedSubweapon = null;
var unlockedSubweapons = [];
var subweaponPrices = {
santa_helper: 750,
krusty_shop: 1200,
snowball_cat: 900
};
var activeSubweapon = null;
var encyclopediaScreen;
// Create title screen
titleScreen = new Container();
game.addChild(titleScreen);
// Title text
titleText = new Text2('BART vs MUTANTS', {
size: 120,
fill: 0xFFFF00
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
titleScreen.addChild(titleText);
// Start button background
startButton = titleScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1400,
scaleX: 2,
scaleY: 3
});
// Start button text
var startText = new Text2('START', {
size: 80,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startText.x = 1024;
startText.y = 1400;
titleScreen.addChild(startText);
// Instructions text
var instructionsText = new Text2('Drag to move • Auto-shoot enemies', {
size: 50,
fill: 0xAAAAAA
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1600;
titleScreen.addChild(instructionsText);
// Title screen coins display
var titleCoinsText = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700
});
titleCoinsText.anchor.set(1, 0);
titleCoinsText.x = 1948;
titleCoinsText.y = 100;
titleScreen.addChild(titleCoinsText);
// Shop button background
shopButton = titleScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1800,
scaleX: 2,
scaleY: 2
});
// Shop button text
var shopButtonText = new Text2('KRUSTY BURGER', {
size: 60,
fill: 0xFFFF00
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 1024;
shopButtonText.y = 1800;
titleScreen.addChild(shopButtonText);
// Encyclopedia button background
var encyclopediaButton = titleScreen.attachAsset('info_button', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2100,
scaleX: 2,
scaleY: 2
});
// Encyclopedia button text
var encyclopediaButtonText = new Text2('ENCYCLOPEDIA', {
size: 60,
fill: 0x00FFFF
});
encyclopediaButtonText.anchor.set(0.5, 0.5);
encyclopediaButtonText.x = 1024;
encyclopediaButtonText.y = 2100;
titleScreen.addChild(encyclopediaButtonText);
// Carnival button background
var carnivalButton = titleScreen.attachAsset('carnival_tent', {
anchorX: 0.5,
anchorY: 0.5,
x: 512,
y: 2100,
scaleX: 0.8,
scaleY: 0.8
});
// Carnival button text
var carnivalText = new Text2('CARNIVAL', {
size: 50,
fill: 0xFFD700
});
carnivalText.anchor.set(0.5, 0.5);
carnivalText.x = 512;
carnivalText.y = 2250;
titleScreen.addChild(carnivalText);
// Carnival entry fee text
var carnivalFeeText = new Text2('10 coins per game', {
size: 30,
fill: 0xAAAAAA
});
carnivalFeeText.anchor.set(0.5, 0.5);
carnivalFeeText.x = 512;
carnivalFeeText.y = 2300;
titleScreen.addChild(carnivalFeeText);
// Quality mode toggle button
var qualityButton = titleScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 400,
scaleX: 2,
scaleY: 1.5
});
qualityButton.tint = isLowQualityMode ? 0xFF0000 : 0x00FF00; // Red for low quality, green for high quality
var qualityText = new Text2(isLowQualityMode ? 'FHD' : 'HD', {
size: 50,
fill: 0xFFFFFF
});
qualityText.anchor.set(0.5, 0.5);
qualityText.x = 200;
qualityText.y = 400;
titleScreen.addChild(qualityText);
var qualityLabel = new Text2('Quality', {
size: 30,
fill: 0xAAAAAA
});
qualityLabel.anchor.set(0.5, 0.5);
qualityLabel.x = 200;
qualityLabel.y = 450;
titleScreen.addChild(qualityLabel);
// Giant Mutant Rush button background
giantMutantRushButton = titleScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1536,
y: 2100,
scaleX: 2.5,
scaleY: 2
});
giantMutantRushButton.tint = 0xFF0000;
// Giant Mutant Rush button text
var giantRushText = new Text2('GIANT MUTANT RUSH!', {
size: 50,
fill: 0xFFFF00
});
giantRushText.anchor.set(0.5, 0.5);
giantRushText.x = 1536;
giantRushText.y = 2100;
titleScreen.addChild(giantRushText);
// Boss selection screen
var bossSelectionScreen = new Container();
bossSelectionScreen.visible = false;
game.addChild(bossSelectionScreen);
// Boss selection title
var bossSelectionTitle = new Text2('SELECT YOUR OPPONENT', {
size: 100,
fill: 0xFF0000
});
bossSelectionTitle.anchor.set(0.5, 0.5);
bossSelectionTitle.x = 1024;
bossSelectionTitle.y = 200;
bossSelectionScreen.addChild(bossSelectionTitle);
// Boss selection coins display
var bossSelectionCoinsText = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700
});
bossSelectionCoinsText.anchor.set(1, 0);
bossSelectionCoinsText.x = 1948;
bossSelectionCoinsText.y = 100;
bossSelectionScreen.addChild(bossSelectionCoinsText);
// Entry fee text
var entryFeeText = new Text2('Entry Fee: 50 Coins', {
size: 50,
fill: 0xFFD700
});
entryFeeText.anchor.set(0.5, 0.5);
entryFeeText.x = 1024;
entryFeeText.y = 350;
bossSelectionScreen.addChild(entryFeeText);
// Watch ad button
var watchAdButton = bossSelectionScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 450,
scaleX: 3.5,
scaleY: 1.5
});
watchAdButton.tint = 0x00FF00;
var watchAdText = new Text2('Watch Itchy & Scratchy Ad', {
size: 45,
fill: 0xFFFFFF
});
watchAdText.anchor.set(0.5, 0.5);
watchAdText.x = 1024;
watchAdText.y = 430;
bossSelectionScreen.addChild(watchAdText);
var watchAdSubtext = new Text2('30 seconds to skip fee', {
size: 30,
fill: 0xAAAAAA
});
watchAdSubtext.anchor.set(0.5, 0.5);
watchAdSubtext.x = 1024;
watchAdSubtext.y = 470;
bossSelectionScreen.addChild(watchAdSubtext);
// Mutant Leader selection button
var mutantLeaderButton = bossSelectionScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 600,
scaleX: 3,
scaleY: 2
});
mutantLeaderButton.tint = 0x800080;
var mutantLeaderText = new Text2('MUTANT LEADER', {
size: 60,
fill: 0xFFFFFF
});
mutantLeaderText.anchor.set(0.5, 0.5);
mutantLeaderText.x = 1024;
mutantLeaderText.y = 570;
bossSelectionScreen.addChild(mutantLeaderText);
var mutantLeaderDesc = new Text2('HP: 20000 | Summons allies & debuffs', {
size: 35,
fill: 0xAAAAAA
});
mutantLeaderDesc.anchor.set(0.5, 0.5);
mutantLeaderDesc.x = 1024;
mutantLeaderDesc.y = 630;
bossSelectionScreen.addChild(mutantLeaderDesc);
// Concert selection button
var concertButton = bossSelectionScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 850,
scaleX: 3,
scaleY: 2
});
concertButton.tint = 0x2678d7;
var concertText = new Text2('CONCERT', {
size: 60,
fill: 0xFFFFFF
});
concertText.anchor.set(0.5, 0.5);
concertText.x = 1024;
concertText.y = 820;
bossSelectionScreen.addChild(concertText);
var concertDesc = new Text2('HP: 25750 | Band attacks & buffs', {
size: 35,
fill: 0xAAAAAA
});
concertDesc.anchor.set(0.5, 0.5);
concertDesc.x = 1024;
concertDesc.y = 880;
bossSelectionScreen.addChild(concertDesc);
// UFO Striker selection button
var ufoButton = bossSelectionScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1100,
scaleX: 3,
scaleY: 2
});
ufoButton.tint = 0x4B0082;
var ufoText = new Text2('UFO STRIKER', {
size: 60,
fill: 0xFFFFFF
});
ufoText.anchor.set(0.5, 0.5);
ufoText.x = 1024;
ufoText.y = 1070;
bossSelectionScreen.addChild(ufoText);
var ufoDesc = new Text2('HP: 30550 | Kidnapping & cloning', {
size: 35,
fill: 0xAAAAAA
});
ufoDesc.anchor.set(0.5, 0.5);
ufoDesc.x = 1024;
ufoDesc.y = 1130;
bossSelectionScreen.addChild(ufoDesc);
// Random boss selection button
var randomBossButton = bossSelectionScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1350,
scaleX: 3,
scaleY: 2
});
randomBossButton.tint = 0xFFD700;
var randomBossText = new Text2('RANDOM BOSS', {
size: 60,
fill: 0x000000
});
randomBossText.anchor.set(0.5, 0.5);
randomBossText.x = 1024;
randomBossText.y = 1320;
bossSelectionScreen.addChild(randomBossText);
var randomBossDesc = new Text2('Let fate decide your opponent!', {
size: 35,
fill: 0x666666
});
randomBossDesc.anchor.set(0.5, 0.5);
randomBossDesc.x = 1024;
randomBossDesc.y = 1380;
bossSelectionScreen.addChild(randomBossDesc);
// Back button for boss selection
var bossBackButton = bossSelectionScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 200,
scaleX: 1.5,
scaleY: 1.5
});
var bossBackText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
bossBackText.anchor.set(0.5, 0.5);
bossBackText.x = 200;
bossBackText.y = 200;
bossSelectionScreen.addChild(bossBackText);
// Variable to store selected boss
var selectedGiantMutant = null;
// Ad watching state
var isWatchingAd = false;
var adCountdown = 0;
var adCountdownText = null;
var adOverlay = null;
// Ad overlay screen
var adOverlay = new Container();
adOverlay.visible = false;
game.addChild(adOverlay);
// Ad background
var adBg = adOverlay.attachAsset('info_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
// Ad title
var adTitle = new Text2('ITCHY & SCRATCHY SHOW', {
size: 100,
fill: 0xFF0000
});
adTitle.anchor.set(0.5, 0.5);
adTitle.x = 1024;
adTitle.y = 400;
adOverlay.addChild(adTitle);
// Ad content area
var adContent = new Text2('Advertisement Playing...', {
size: 60,
fill: 0xFFFFFF
});
adContent.anchor.set(0.5, 0.5);
adContent.x = 1024;
adContent.y = 800;
adOverlay.addChild(adContent);
// Ad countdown text
adCountdownText = new Text2('30', {
size: 120,
fill: 0xFFFF00
});
adCountdownText.anchor.set(0.5, 0.5);
adCountdownText.x = 1024;
adCountdownText.y = 1200;
adOverlay.addChild(adCountdownText);
// Ad skip notice
var adSkipNotice = new Text2('Please wait for ad to complete', {
size: 40,
fill: 0xAAAAAA
});
adSkipNotice.anchor.set(0.5, 0.5);
adSkipNotice.x = 1024;
adSkipNotice.y = 1600;
adOverlay.addChild(adSkipNotice);
// Carnival screen
var carnivalScreen = new Container();
carnivalScreen.visible = false;
game.addChild(carnivalScreen);
// Carnival background
var carnivalBg = carnivalScreen.attachAsset('carnival_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
// Carnival title
var carnivalTitle = new Text2('CARNIVAL GAMES', {
size: 100,
fill: 0xFFD700
});
carnivalTitle.anchor.set(0.5, 0.5);
carnivalTitle.x = 1024;
carnivalTitle.y = 200;
carnivalScreen.addChild(carnivalTitle);
// Carnival subtitle
var carnivalSubtitle = new Text2('Entry Fee: 10 Coins per Game', {
size: 50,
fill: 0xFFFFFF
});
carnivalSubtitle.anchor.set(0.5, 0.5);
carnivalSubtitle.x = 1024;
carnivalSubtitle.y = 300;
carnivalScreen.addChild(carnivalSubtitle);
// Carnival coins display
var carnivalCoinsText = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700
});
carnivalCoinsText.anchor.set(1, 0);
carnivalCoinsText.x = 1948;
carnivalCoinsText.y = 100;
carnivalScreen.addChild(carnivalCoinsText);
// Back button for carnival
var carnivalBackButton = carnivalScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 200,
scaleX: 1.5,
scaleY: 1.5
});
var carnivalBackText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
carnivalBackText.anchor.set(0.5, 0.5);
carnivalBackText.x = 200;
carnivalBackText.y = 200;
carnivalScreen.addChild(carnivalBackText);
// Tic Tac Toe button
var ticTacToeButton = carnivalScreen.attachAsset('tictactoe_grid', {
anchorX: 0.5,
anchorY: 0.5,
x: 512,
y: 700,
scaleX: 0.5,
scaleY: 0.5
});
var ticTacToeText = new Text2('Itchy tac Scratchy', {
size: 50,
fill: 0xFFFFFF
});
ticTacToeText.anchor.set(0.5, 0.5);
ticTacToeText.x = 512;
ticTacToeText.y = 900;
carnivalScreen.addChild(ticTacToeText);
var ticTacToeDesc = new Text2('Classic Tic Tac Toe\nWin: 25 coins', {
size: 35,
fill: 0xAAAAAA
});
ticTacToeDesc.anchor.set(0.5, 0.5);
ticTacToeDesc.x = 512;
ticTacToeDesc.y = 980;
carnivalScreen.addChild(ticTacToeDesc);
// Hit the Mole button
var hitMoleButton = carnivalScreen.attachAsset('mole_hole', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 700,
scaleX: 2,
scaleY: 2
});
var hitMoleText = new Text2('Hit the Mole', {
size: 50,
fill: 0xFFFFFF
});
hitMoleText.anchor.set(0.5, 0.5);
hitMoleText.x = 1024;
hitMoleText.y = 900;
carnivalScreen.addChild(hitMoleText);
var hitMoleDesc = new Text2('Hit 5 Scratchys\nWin: 30 coins', {
size: 35,
fill: 0xAAAAAA
});
hitMoleDesc.anchor.set(0.5, 0.5);
hitMoleDesc.x = 1024;
hitMoleDesc.y = 980;
carnivalScreen.addChild(hitMoleDesc);
// Horse Betting button
var horseBettingButton = carnivalScreen.attachAsset('horse_track', {
anchorX: 0.5,
anchorY: 0.5,
x: 1536,
y: 700,
scaleX: 0.3,
scaleY: 0.5
});
var horseBettingText = new Text2('Horse Betting', {
size: 50,
fill: 0xFFFFFF
});
horseBettingText.anchor.set(0.5, 0.5);
horseBettingText.x = 1536;
horseBettingText.y = 900;
carnivalScreen.addChild(horseBettingText);
var horseBettingDesc = new Text2('Bet on the winner\nWin: 40 coins', {
size: 35,
fill: 0xAAAAAA
});
horseBettingDesc.anchor.set(0.5, 0.5);
horseBettingDesc.x = 1536;
horseBettingDesc.y = 980;
carnivalScreen.addChild(horseBettingDesc);
// Active mini-game
var activeMiniGame = null;
// GUI elements (hidden initially)
var levelText = new Text2('Level 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 150;
levelText.visible = false;
LK.gui.topLeft.addChild(levelText);
var xpBarBg = LK.gui.top.attachAsset('xpbar_bg', {
anchorX: 0.5,
anchorY: 0,
y: 10
});
xpBarBg.visible = false;
var xpBarFill = LK.gui.top.attachAsset('xpbar_fill', {
anchorX: 0,
anchorY: 0,
x: -150,
y: 10,
scaleX: 0
});
xpBarFill.visible = false;
var coinText = new Text2('Coins: 0', {
size: 50,
fill: 0xFFD700
});
coinText.anchor.set(1, 0);
coinText.visible = false;
LK.gui.topRight.addChild(coinText);
var healthBarBg = LK.gui.topLeft.attachAsset('healthbar_bg', {
anchorX: 0,
anchorY: 0,
x: 120,
y: 80
});
healthBarBg.visible = false;
var healthBarFill = LK.gui.topLeft.attachAsset('healthbar_fill', {
anchorX: 0,
anchorY: 0,
x: 120,
y: 80,
scaleX: 1
});
healthBarFill.visible = false;
var waveText = new Text2('Wave 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0.5);
waveText.visible = false;
LK.gui.center.addChild(waveText);
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 1);
scoreText.visible = false;
LK.gui.bottom.addChild(scoreText);
// Load saved data
var savedCoins = 0;
var savedWeapons = null;
var savedSelected = null;
var savedSubweapons = null;
var savedSelectedSubweapon = null;
try {
savedCoins = storage.coins || 0;
savedWeapons = storage.unlockedWeapons;
savedSelected = storage.selectedWeapon;
savedSubweapons = storage.unlockedSubweapons;
savedSelectedSubweapon = storage.selectedSubweapon;
} catch (e) {
console.log('Storage not available:', e);
}
if (savedWeapons) {
unlockedWeapons = savedWeapons;
}
if (savedSelected) {
selectedWeapon = savedSelected;
}
if (savedSubweapons) {
unlockedSubweapons = savedSubweapons;
}
if (savedSelectedSubweapon) {
selectedSubweapon = savedSelectedSubweapon;
}
bart = game.addChild(new Bart());
bart.x = 1024;
bart.y = 2000;
bart.visible = false;
bart.coins = savedCoins;
// Set initial weapon visual
bart.updateWeaponVisual(selectedWeapon);
// Update coin display immediately
coinText.setText('Coins: ' + bart.coins);
// Update title screen coins display
titleCoinsText.setText('Coins: ' + bart.coins);
// Create shop screen
shopScreen = new Container();
shopScreen.visible = false;
game.addChild(shopScreen);
// Create encyclopedia screen
encyclopediaScreen = new Encyclopedia();
encyclopediaScreen.x = 1024;
encyclopediaScreen.y = 1366;
encyclopediaScreen.visible = false;
game.addChild(encyclopediaScreen);
// Shop tab system variables
var currentTab = 'weapons';
// Shop title
var shopTitle = new Text2('KRUSTY BURGER', {
size: 100,
fill: 0xFFFF00
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 1024;
shopTitle.y = 150;
shopScreen.addChild(shopTitle);
// Weapons tab button
var weaponsTabButton = shopScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 750,
y: 250,
scaleX: 2,
scaleY: 1.5
});
weaponsTabButton.tint = 0x00FF00; // Active tab color
var weaponsTabText = new Text2('WEAPONS', {
size: 50,
fill: 0xFFFFFF
});
weaponsTabText.anchor.set(0.5, 0.5);
weaponsTabText.x = 750;
weaponsTabText.y = 250;
shopScreen.addChild(weaponsTabText);
// Subweapons tab button
var subweaponsTabButton = shopScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1298,
y: 250,
scaleX: 2,
scaleY: 1.5
});
var subweaponsTabText = new Text2('SUBWEAPONS', {
size: 50,
fill: 0xFFFFFF
});
subweaponsTabText.anchor.set(0.5, 0.5);
subweaponsTabText.x = 1298;
subweaponsTabText.y = 250;
shopScreen.addChild(subweaponsTabText);
// Back button
var backButton = shopScreen.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 200,
scaleX: 1.5,
scaleY: 1.5
});
var backText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 200;
backText.y = 200;
shopScreen.addChild(backText);
// Coins display in shop
var shopCoinsText = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700
});
shopCoinsText.anchor.set(1, 0.5);
shopCoinsText.x = 1848;
shopCoinsText.y = 200;
shopScreen.addChild(shopCoinsText);
// Containers for different tab content
var weaponsContainer = new Container();
var subweaponsContainer = new Container();
shopScreen.addChild(weaponsContainer);
shopScreen.addChild(subweaponsContainer);
subweaponsContainer.visible = false; // Start with weapons tab active
// Weapon buttons
var weaponData = [{
id: 'slingshot',
name: 'Slingshot',
desc: 'The Default Weapon',
y: 400
}, {
id: 'dartgun',
name: 'Dart Gun',
desc: 'High damage, slow fire rate',
y: 550
}, {
id: 'scattershot',
name: 'Scattershot',
desc: 'Shoots peanuts that split into 3',
y: 700
}, {
id: 'ducky',
name: 'Ducky Triple',
desc: 'Shoots 3 projectiles',
y: 850
}, {
id: 'bow',
name: 'Toy Bow',
desc: 'Lower damage but 100% more XP!',
y: 1000
}, {
id: 'spraycan',
name: 'Spraycan',
desc: 'Medium damage, stuns for 1.2s',
y: 1150
}, {
id: 'pot',
name: 'Pot-a-Bomb',
desc: 'Area damage, chance to split into shards',
y: 1300
}, {
id: 'flower',
name: "Krusty's Flower",
desc: 'Water beam, rapid fire',
y: 1450
}];
// Subweapon buttons
var subweaponData = [{
id: 'santa_helper',
name: "Santa's Little Helper",
desc: 'Fast ally that bites enemies',
y: 400
}, {
id: 'krusty_shop',
name: 'Krusty Burger Shop',
desc: 'Spawns powerups every 15 seconds',
y: 550
}, {
id: 'snowball_cat',
name: 'Snowball II',
desc: 'Distracts enemies & reduces invincibility',
y: 700
}];
subweaponData.forEach(function (subweapon) {
// Subweapon button background
var subweaponBg = subweaponsContainer.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: subweapon.y,
scaleX: 8,
scaleY: 2.4
});
subweaponBg.subweaponId = subweapon.id;
// Subweapon name
var subweaponName = new Text2(subweapon.name, {
size: 50,
fill: 0x00FFFF
});
subweaponName.anchor.set(0.5, 0.5);
subweaponName.x = 800;
subweaponName.y = subweapon.y - 15;
subweaponsContainer.addChild(subweaponName);
// Subweapon description
var subweaponDesc = new Text2(subweapon.desc, {
size: 35,
fill: 0xAAAAAA
});
subweaponDesc.anchor.set(0.5, 0.5);
subweaponDesc.x = 800;
subweaponDesc.y = subweapon.y + 15;
subweaponsContainer.addChild(subweaponDesc);
// Price/status text
var priceText = new Text2('Cost: ' + subweaponPrices[subweapon.id], {
size: 45,
fill: 0xFFD700
});
priceText.anchor.set(0.5, 0.5);
priceText.x = 1400;
priceText.y = subweapon.y;
priceText.subweaponId = subweapon.id;
subweaponsContainer.addChild(priceText);
});
weaponData.forEach(function (weapon) {
// Weapon button background
var weaponBg = weaponsContainer.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: weapon.y,
scaleX: 8,
scaleY: 3
});
weaponBg.weaponId = weapon.id;
// Weapon name
var weaponName = new Text2(weapon.name, {
size: 60,
fill: 0xFFFFFF
});
weaponName.anchor.set(0.5, 0.5);
weaponName.x = 800;
weaponName.y = weapon.y - 20;
weaponsContainer.addChild(weaponName);
// Weapon description
var weaponDesc = new Text2(weapon.desc, {
size: 40,
fill: 0xAAAAAA
});
weaponDesc.anchor.set(0.5, 0.5);
weaponDesc.x = 800;
weaponDesc.y = weapon.y + 20;
weaponsContainer.addChild(weaponDesc);
// Price/status text
var priceText = new Text2(weapon.id === 'slingshot' ? 'OWNED' : 'Cost: ' + weaponPrices[weapon.id], {
size: 50,
fill: weapon.id === 'slingshot' ? 0x00FF00 : 0xFFD700
});
priceText.anchor.set(0.5, 0.5);
priceText.x = 1400;
priceText.y = weapon.y;
priceText.weaponId = weapon.id;
weaponsContainer.addChild(priceText);
});
function switchShopTab(tabName) {
currentTab = tabName;
if (tabName === 'weapons') {
weaponsContainer.visible = true;
subweaponsContainer.visible = false;
weaponsTabButton.tint = 0x00FF00; // Active tab color
subweaponsTabButton.tint = 0xFFFFFF; // Inactive tab color
} else if (tabName === 'subweapons') {
weaponsContainer.visible = false;
subweaponsContainer.visible = true;
weaponsTabButton.tint = 0xFFFFFF; // Inactive tab color
subweaponsTabButton.tint = 0x00FF00; // Active tab color
}
}
function updateShopDisplay() {
// Update coins in shop
var shopCoinsText = shopScreen.children.find(function (child) {
return child instanceof Text2 && child.text && child.text.startsWith('Coins:');
});
if (shopCoinsText) {
shopCoinsText.setText('Coins: ' + bart.coins);
}
// Update title screen coins display
titleCoinsText.setText('Coins: ' + bart.coins);
// Update weapon status texts
weaponsContainer.children.forEach(function (child) {
if (child instanceof Text2 && child.weaponId) {
if (unlockedWeapons.indexOf(child.weaponId) !== -1) {
var newText = selectedWeapon === child.weaponId ? 'EQUIPPED' : 'OWNED';
var newColor = selectedWeapon === child.weaponId ? 0x00FFFF : 0x00FF00;
child.setText(newText);
// Remove old text and create new one with correct color
var parent = child.parent;
var x = child.x;
var y = child.y;
var weaponId = child.weaponId;
parent.removeChild(child);
var newTextObj = new Text2(newText, {
size: 50,
fill: newColor
});
newTextObj.anchor.set(0.5, 0.5);
newTextObj.x = x;
newTextObj.y = y;
newTextObj.weaponId = weaponId;
parent.addChild(newTextObj);
}
}
});
// Update subweapon status texts
subweaponsContainer.children.forEach(function (child) {
if (child instanceof Text2 && child.subweaponId) {
if (unlockedSubweapons.indexOf(child.subweaponId) !== -1) {
var newText = selectedSubweapon === child.subweaponId ? 'EQUIPPED' : 'OWNED';
var newColor = selectedSubweapon === child.subweaponId ? 0x00FFFF : 0x00FF00;
child.setText(newText);
// Remove old text and create new one with correct color
var parent = child.parent;
var x = child.x;
var y = child.y;
var subweaponId = child.subweaponId;
parent.removeChild(child);
var newTextObj = new Text2(newText, {
size: 45,
fill: newColor
});
newTextObj.anchor.set(0.5, 0.5);
newTextObj.x = x;
newTextObj.y = y;
newTextObj.subweaponId = subweaponId;
parent.addChild(newTextObj);
}
}
});
}
function selectBossAfterAd() {
// Show boss selection popup
var bossChoiceOverlay = new Container();
game.addChild(bossChoiceOverlay);
// Background
var choiceBg = bossChoiceOverlay.attachAsset('info_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.8,
scaleY: 0.6
});
// Title
var choiceTitle = new Text2('Choose Your Boss!', {
size: 80,
fill: 0xFFD700
});
choiceTitle.anchor.set(0.5, 0.5);
choiceTitle.x = 1024;
choiceTitle.y = 900;
bossChoiceOverlay.addChild(choiceTitle);
// Mutant Leader button
var mlButton = bossChoiceOverlay.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 700,
y: 1200,
scaleX: 2,
scaleY: 1.5
});
mlButton.tint = 0x800080;
var mlText = new Text2('Mutant Leader', {
size: 40,
fill: 0xFFFFFF
});
mlText.anchor.set(0.5, 0.5);
mlText.x = 700;
mlText.y = 1200;
bossChoiceOverlay.addChild(mlText);
// Concert button
var concertButton = bossChoiceOverlay.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1200,
scaleX: 2,
scaleY: 1.5
});
concertButton.tint = 0x2678d7;
var concertText = new Text2('Concert', {
size: 40,
fill: 0xFFFFFF
});
concertText.anchor.set(0.5, 0.5);
concertText.x = 1024;
concertText.y = 1200;
bossChoiceOverlay.addChild(concertText);
// UFO button
var ufoButton = bossChoiceOverlay.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1348,
y: 1200,
scaleX: 2,
scaleY: 1.5
});
ufoButton.tint = 0x4B0082;
var ufoText = new Text2('UFO Striker', {
size: 40,
fill: 0xFFFFFF
});
ufoText.anchor.set(0.5, 0.5);
ufoText.x = 1348;
ufoText.y = 1200;
bossChoiceOverlay.addChild(ufoText);
// Random button
var randomButton = bossChoiceOverlay.attachAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1400,
scaleX: 2,
scaleY: 1.5
});
randomButton.tint = 0xFFD700;
var randomText = new Text2('Random', {
size: 40,
fill: 0x000000
});
randomText.anchor.set(0.5, 0.5);
randomText.x = 1024;
randomText.y = 1400;
bossChoiceOverlay.addChild(randomText);
// Handle choice clicks
bossChoiceOverlay.down = function (x, y, obj) {
var localX = x;
var localY = y;
if (localX > 600 && localX < 800 && localY > 1150 && localY < 1250) {
// Mutant Leader
selectedGiantMutant = 'mutant_leader';
isGiantMutantRush = true;
game.removeChild(bossChoiceOverlay);
startGame();
} else if (localX > 924 && localX < 1124 && localY > 1150 && localY < 1250) {
// Concert
selectedGiantMutant = 'concert';
isGiantMutantRush = true;
game.removeChild(bossChoiceOverlay);
startGame();
} else if (localX > 1248 && localX < 1448 && localY > 1150 && localY < 1250) {
// UFO Striker
selectedGiantMutant = 'ufo_striker';
isGiantMutantRush = true;
game.removeChild(bossChoiceOverlay);
startGame();
} else if (localX > 924 && localX < 1124 && localY > 1350 && localY < 1450) {
// Random
selectedGiantMutant = 'random';
isGiantMutantRush = true;
game.removeChild(bossChoiceOverlay);
startGame();
}
};
}
function startGame() {
gameStarted = true;
// Hide title screen
titleScreen.visible = false;
// Show game elements
bart.visible = true;
levelText.visible = true;
xpBarBg.visible = true;
xpBarFill.visible = true;
coinText.visible = true;
waveText.visible = true;
scoreText.visible = true;
healthBarBg.visible = true;
healthBarFill.visible = true;
// Apply selected weapon stats
var stats = weaponStats[selectedWeapon];
bart.damage = stats.damage;
bart.fireRate = stats.fireRate;
// Update Bart's visual appearance
bart.updateWeaponVisual(selectedWeapon);
// Giant Mutant Rush mode setup
if (isGiantMutantRush) {
// Set Bart to level 10
bart.level = 10;
bart.xpToNext = 1000;
bart.maxHealth = 100 + 9 * 20; // 9 level ups worth of health
bart.health = bart.maxHealth;
bart.damage = stats.damage + 9 * 5; // 9 level ups worth of damage
bart.fireRate = Math.max(10, stats.fireRate - 9 * 2); // 9 level ups worth of fire rate
// Update UI
levelText.setText('Level ' + bart.level);
healthBarFill.scaleX = 1;
waveText.setText('GIANT MUTANT RUSH!');
waveText.tint = 0xFF0000;
// Spawn the selected boss
if (selectedGiantMutant === 'mutant_leader') {
// Spawn the Mutant Leader
var leader = new MutantLeader();
leader.x = 1024;
leader.y = 400;
enemies.push(leader);
game.addChild(leader);
} else if (selectedGiantMutant === 'concert') {
// Spawn the Concert
var concert = new Concert();
concert.x = 1024;
concert.y = 400; // At top of screen
enemies.push(concert);
game.addChild(concert);
} else if (selectedGiantMutant === 'ufo_striker') {
// Spawn the UFO Striker
var ufo = new UFOStriker();
ufo.x = 1024;
ufo.y = 400;
enemies.push(ufo);
game.addChild(ufo);
} else {
// Random selection (fallback)
var giantType = Math.random() * 3;
if (giantType < 1) {
// Spawn the Mutant Leader
var leader = new MutantLeader();
leader.x = 1024;
leader.y = 400;
enemies.push(leader);
game.addChild(leader);
} else if (giantType < 2) {
// Spawn the Concert
var concert = new Concert();
concert.x = 1024;
concert.y = 400; // At top of screen
enemies.push(concert);
game.addChild(concert);
} else {
// Spawn the UFO Striker
var ufo = new UFOStriker();
ufo.x = 1024;
ufo.y = 400;
enemies.push(ufo);
game.addChild(ufo);
}
}
mutantLeaderSpawned = true;
}
// Spawn active subweapon
if (selectedSubweapon) {
if (selectedSubweapon === 'santa_helper') {
activeSubweapon = new SantaHelper();
activeSubweapon.x = bart.x + 80;
activeSubweapon.y = bart.y + 50;
game.addChild(activeSubweapon);
} else if (selectedSubweapon === 'krusty_shop') {
activeSubweapon = new KrustyShop();
activeSubweapon.x = bart.x + 150;
activeSubweapon.y = bart.y - 100;
game.addChild(activeSubweapon);
} else if (selectedSubweapon === 'snowball_cat') {
activeSubweapon = new SnowballCat();
activeSubweapon.x = bart.x - 150;
activeSubweapon.y = bart.y;
game.addChild(activeSubweapon);
}
}
// Create joystick
joystick = LK.gui.bottomLeft.attachAsset('joystick_base', {
anchorX: 0.5,
anchorY: 0.5,
x: joystickCenter.x,
y: -150
});
joystick.alpha = 0.8;
joystickKnob = LK.gui.bottomLeft.attachAsset('joystick_knob', {
anchorX: 0.5,
anchorY: 0.5,
x: joystickCenter.x,
y: -150
});
joystickKnob.alpha = 0.9;
// Show initial wave text
waveText.setText('Wave 1');
if (!isLowQualityMode) {
tween(waveText, {
scaleX: 2,
scaleY: 2
}, {
duration: 500,
easing: tween.elasticOut
});
tween(waveText, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.elasticIn
});
}
}
function spawnEnemy() {
var enemy;
// Boss waves: 5, 10, 15, 20
if (wave % 5 === 0) {
enemy = new Boss();
// Scale boss health and speed based on wave
enemy.maxHealth = 500 + (wave - 5) * 200;
enemy.health = enemy.maxHealth;
enemy.speed = 1 + wave * 0.1;
enemy.xpValue = 100 + wave * 20;
} else {
var mutantType = Math.random();
if (wave >= 8 && mutantType < 0.1) {
enemy = new SamuraiMutant();
enemy.speed = 1.2 + wave * 0.2;
enemy.maxHealth = 100 + wave * 15;
enemy.health = enemy.maxHealth;
enemy.xpValue = 50 + wave * 6;
} else if (wave >= 13 && mutantType < 0.15) {
enemy = new DrummerMutant();
enemy.speed = 0.8 + wave * 0.1;
enemy.maxHealth = 150 + wave * 20;
enemy.health = enemy.maxHealth;
enemy.xpValue = 45 + wave * 5;
} else if (wave >= 13 && mutantType < 0.25) {
enemy = new VocalMutant();
enemy.speed = 5 + wave * 0.5;
enemy.maxHealth = 40 + wave * 10;
enemy.health = enemy.maxHealth;
enemy.xpValue = 35 + wave * 4;
} else if (wave >= 13 && mutantType < 0.35) {
enemy = new RockerMutant();
enemy.speed = 2.5 + wave * 0.3;
enemy.maxHealth = 70 + wave * 15;
enemy.health = enemy.maxHealth;
enemy.xpValue = 40 + wave * 5;
} else if (wave >= 8 && mutantType < 0.45) {
enemy = new PoetMutant();
enemy.speed = 1 + wave * 0.15;
enemy.maxHealth = 80 + wave * 12;
enemy.health = enemy.maxHealth;
enemy.xpValue = 40 + wave * 5;
} else if (wave >= 7 && mutantType < 0.55) {
enemy = new ShooterMutant();
enemy.speed = 1.5 + wave * 0.2;
enemy.maxHealth = 50 + wave * 10;
enemy.health = enemy.maxHealth;
enemy.xpValue = 25 + wave * 3;
} else if (wave >= 6 && mutantType < 0.45) {
enemy = new CookMutant();
enemy.speed = 1.5 + wave * 0.2;
enemy.maxHealth = 60 + wave * 10;
enemy.health = enemy.maxHealth;
enemy.xpValue = 30 + wave * 4;
} else if (wave >= 2 && mutantType < 0.65) {
enemy = new FastMutant();
enemy.speed = 4 + wave * 0.4;
enemy.maxHealth = 15 + wave * 8;
enemy.health = enemy.maxHealth;
enemy.xpValue = 15 + wave * 2;
} else {
enemy = new Mutant();
// Progressive scaling for mutants across all 20 waves
enemy.speed = 2 + wave * 0.3;
enemy.maxHealth = 30 + wave * 15;
enemy.health = enemy.maxHealth;
enemy.xpValue = 10 + wave * 2;
}
// Adjust invincibility based on wave
if (wave >= 15) {
// No invincibility at wave 15 onwards
enemy.invincible = false;
enemy.invincibilityTimer = 0;
} else if (wave >= 10) {
// Reduced invincibility (1.5 seconds) at wave 10 onwards
enemy.invincibilityTimer = 90; // 1.5 seconds at 60fps
} else {
// Normal invincibility for waves 1-9 (3 seconds)
enemy.invincibilityTimer = 180; // 3 seconds at 60fps
}
// Special mutant variants for higher waves
if (wave >= 10) {
enemy.speed += 1;
enemy.maxHealth += 50;
enemy.health = enemy.maxHealth;
mutantGraphics = enemy.children[0];
if (mutantGraphics) {
mutantGraphics.tint = 0xFF6666; // Red tint for stronger mutants
}
}
if (wave >= 15) {
enemy.speed += 1;
enemy.maxHealth += 100;
enemy.health = enemy.maxHealth;
mutantGraphics = enemy.children[0];
if (mutantGraphics) {
mutantGraphics.tint = 0xFF0000; // Dark red tint for elite mutants
}
}
}
enemy.x = Math.random() * 1848 + 100;
enemy.y = -100;
enemies.push(enemy);
game.addChild(enemy);
}
function shootBullet() {
if (bart.fireTimer > 0 || enemies.length === 0) return;
var closestEnemy = null;
var closestDist = Infinity;
for (var i = 0; i < enemies.length; i++) {
var dx = enemies[i].x - bart.x;
var dy = enemies[i].y - bart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < closestDist) {
closestDist = dist;
closestEnemy = enemies[i];
}
}
if (closestEnemy && closestDist < 800) {
var stats = weaponStats[selectedWeapon];
if (selectedWeapon === 'flower') {
// Continuous beam weapon
var bullet = new FlowerBeam();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullet.speed = 25;
bullets.push(bullet);
game.addChild(bullet);
} else if (selectedWeapon === 'dartgun') {
// Dart gun projectile
var bullet = new Dart();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
} else if (selectedWeapon === 'scattershot') {
// Scattershot peanut
var bullet = new Peanut();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
} else if (selectedWeapon === 'bow') {
// Toy Bow rubber arrow
var bullet = new RubberArrow();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
} else if (selectedWeapon === 'pot') {
// Pot-a-Bomb projectile
var bullet = new PotBomb();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
} else if (selectedWeapon === 'spraycan') {
// Spraycan projectile
var bullet = new Spray();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
} else if (selectedWeapon === 'ducky') {
// Triple shot with spread
for (var i = -1; i <= 1; i++) {
var bullet = new Bullet();
bullet.x = bart.x + i * 30;
bullet.y = bart.y;
// Create spread by offsetting target position
var spreadAngle = i * 0.3; // 0.3 radians spread per bullet
var targetDx = closestEnemy.x - bart.x;
var targetDy = closestEnemy.y - bart.y;
var targetDist = Math.sqrt(targetDx * targetDx + targetDy * targetDy);
// Apply spread to target direction
var currentAngle = Math.atan2(targetDy, targetDx);
var newAngle = currentAngle + spreadAngle;
// Create a virtual target with spread
var virtualTarget = {
x: bart.x + Math.cos(newAngle) * targetDist,
y: bart.y + Math.sin(newAngle) * targetDist
};
bullet.target = virtualTarget;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
}
} else {
// Single shot (slingshot)
var bullet = new Bullet();
bullet.x = bart.x;
bullet.y = bart.y;
bullet.target = closestEnemy;
bullet.damage = bart.damage;
bullets.push(bullet);
game.addChild(bullet);
}
bart.fireTimer = bart.fireRate;
LK.getSound('shoot').play();
}
}
function spawnItem(x, y, type) {
var item;
if (type === 'coin') {
item = new Coin();
} else {
item = new PowerUp();
}
item.x = x;
item.y = y;
items.push(item);
game.addChild(item);
}
game.down = function (x, y, obj) {
if (!gameStarted) {
if (bossSelectionScreen.visible) {
// Boss selection screen interactions
if (x > 100 && x < 300 && y > 100 && y < 300) {
// Back button
bossSelectionScreen.visible = false;
titleScreen.visible = true;
} else if (x > 724 && x < 1324 && y > 500 && y < 700) {
// Mutant Leader button
if (bart.coins >= 50) {
bart.coins -= 50;
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins for Boss rush entry fee:', e);
}
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
bossSelectionCoinsText.setText('Coins: ' + bart.coins);
selectedGiantMutant = 'mutant_leader';
isGiantMutantRush = true;
bossSelectionScreen.visible = false;
startGame();
}
} else if (x > 724 && x < 1324 && y > 750 && y < 950) {
// Concert button
if (bart.coins >= 50) {
bart.coins -= 50;
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins for Boss rush entry fee:', e);
}
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
bossSelectionCoinsText.setText('Coins: ' + bart.coins);
selectedGiantMutant = 'concert';
isGiantMutantRush = true;
bossSelectionScreen.visible = false;
startGame();
}
} else if (x > 724 && x < 1324 && y > 1000 && y < 1200) {
// UFO Striker button
if (bart.coins >= 50) {
bart.coins -= 50;
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins for Boss rush entry fee:', e);
}
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
bossSelectionCoinsText.setText('Coins: ' + bart.coins);
selectedGiantMutant = 'ufo_striker';
isGiantMutantRush = true;
bossSelectionScreen.visible = false;
startGame();
}
} else if (x > 724 && x < 1324 && y > 1250 && y < 1450) {
// Random boss button
if (bart.coins >= 50) {
bart.coins -= 50;
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins for Boss rush entry fee:', e);
}
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
bossSelectionCoinsText.setText('Coins: ' + bart.coins);
selectedGiantMutant = 'random';
isGiantMutantRush = true;
bossSelectionScreen.visible = false;
startGame();
}
} else if (x > 674 && x < 1374 && y > 400 && y < 500) {
// Watch ad button
if (!isWatchingAd) {
isWatchingAd = true;
adCountdown = 1800; // 30 seconds at 60fps
bossSelectionScreen.visible = false;
adOverlay.visible = true;
}
}
} else if (carnivalScreen.visible) {
// Carnival screen interactions
if (activeMiniGame) {
// Handle mini-game interactions
if (activeMiniGame instanceof TicTacToe) {
// Check cell clicks
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = activeMiniGame.cells[row][col];
var cellX = activeMiniGame.x + cell.x;
var cellY = activeMiniGame.y + cell.y;
if (x > cellX - 90 && x < cellX + 90 && y > cellY - 90 && y < cellY + 90) {
activeMiniGame.makeMove(row, col);
}
}
}
} else if (activeMiniGame instanceof WhackAMole) {
// Check mole clicks
for (var i = 0; i < activeMiniGame.moles.length; i++) {
var mole = activeMiniGame.moles[i];
var moleX = activeMiniGame.x + mole.x;
var moleY = activeMiniGame.y + mole.y;
if (x > moleX - 60 && x < moleX + 60 && y > moleY - 75 && y < moleY + 75) {
activeMiniGame.hitMole(mole);
}
}
} else if (activeMiniGame instanceof HorseBetting) {
// Check horse selection
if (x > 824 && x < 1024 && y > 1066 && y < 1266) {
activeMiniGame.selectHorse('itchy');
} else if (x > 1224 && x < 1424 && y > 1066 && y < 1266) {
activeMiniGame.selectHorse('scratchy');
}
}
} else {
// Main carnival menu
if (x > 100 && x < 300 && y > 100 && y < 300) {
// Back button
carnivalScreen.visible = false;
titleScreen.visible = true;
} else if (x > 312 && x < 712 && y > 500 && y < 1000) {
// Tic Tac Toe
if (bart.coins >= 10) {
bart.coins -= 10;
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
carnivalCoinsText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
// Hide menu buttons
ticTacToeButton.visible = false;
ticTacToeText.visible = false;
ticTacToeDesc.visible = false;
hitMoleButton.visible = false;
hitMoleText.visible = false;
hitMoleDesc.visible = false;
horseBettingButton.visible = false;
horseBettingText.visible = false;
horseBettingDesc.visible = false;
carnivalTitle.visible = false;
carnivalSubtitle.visible = false;
// Start game
activeMiniGame = new TicTacToe();
activeMiniGame.x = 1024;
activeMiniGame.y = 1366;
activeMiniGame.onComplete = function (won, coins) {
if (won) {
bart.coins += coins;
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
carnivalCoinsText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
}
LK.setTimeout(function () {
carnivalScreen.removeChild(activeMiniGame);
activeMiniGame = null;
// Show menu buttons again
ticTacToeButton.visible = true;
ticTacToeText.visible = true;
ticTacToeDesc.visible = true;
hitMoleButton.visible = true;
hitMoleText.visible = true;
hitMoleDesc.visible = true;
horseBettingButton.visible = true;
horseBettingText.visible = true;
horseBettingDesc.visible = true;
carnivalTitle.visible = true;
carnivalSubtitle.visible = true;
}, 2000);
};
carnivalScreen.addChild(activeMiniGame);
} else {
LK.effects.flashObject(ticTacToeButton, 0xFF0000, 500);
}
} else if (x > 824 && x < 1224 && y > 500 && y < 1000) {
// Hit the Mole
if (bart.coins >= 10) {
bart.coins -= 10;
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
carnivalCoinsText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
// Hide menu buttons
ticTacToeButton.visible = false;
ticTacToeText.visible = false;
ticTacToeDesc.visible = false;
hitMoleButton.visible = false;
hitMoleText.visible = false;
hitMoleDesc.visible = false;
horseBettingButton.visible = false;
horseBettingText.visible = false;
horseBettingDesc.visible = false;
carnivalTitle.visible = false;
carnivalSubtitle.visible = false;
// Start game
activeMiniGame = new WhackAMole();
activeMiniGame.x = 1024;
activeMiniGame.y = 1366;
activeMiniGame.onComplete = function (won, coins) {
if (won) {
bart.coins += coins;
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
carnivalCoinsText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
}
LK.setTimeout(function () {
carnivalScreen.removeChild(activeMiniGame);
activeMiniGame = null;
// Show menu buttons again
ticTacToeButton.visible = true;
ticTacToeText.visible = true;
ticTacToeDesc.visible = true;
hitMoleButton.visible = true;
hitMoleText.visible = true;
hitMoleDesc.visible = true;
horseBettingButton.visible = true;
horseBettingText.visible = true;
horseBettingDesc.visible = true;
carnivalTitle.visible = true;
carnivalSubtitle.visible = true;
}, 2000);
};
carnivalScreen.addChild(activeMiniGame);
} else {
LK.effects.flashObject(hitMoleButton, 0xFF0000, 500);
}
} else if (x > 1336 && x < 1736 && y > 500 && y < 1000) {
// Horse Betting
if (bart.coins >= 10) {
bart.coins -= 10;
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
carnivalCoinsText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
// Hide menu buttons
ticTacToeButton.visible = false;
ticTacToeText.visible = false;
ticTacToeDesc.visible = false;
hitMoleButton.visible = false;
hitMoleText.visible = false;
hitMoleDesc.visible = false;
horseBettingButton.visible = false;
horseBettingText.visible = false;
horseBettingDesc.visible = false;
carnivalTitle.visible = false;
carnivalSubtitle.visible = false;
// Start game
activeMiniGame = new HorseBetting();
activeMiniGame.x = 1024;
activeMiniGame.y = 1366;
activeMiniGame.onComplete = function (won, coins) {
if (won) {
bart.coins += coins;
coinText.setText('Coins: ' + bart.coins);
titleCoinsText.setText('Coins: ' + bart.coins);
carnivalCoinsText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
}
LK.setTimeout(function () {
carnivalScreen.removeChild(activeMiniGame);
activeMiniGame = null;
// Show menu buttons again
ticTacToeButton.visible = true;
ticTacToeText.visible = true;
ticTacToeDesc.visible = true;
hitMoleButton.visible = true;
hitMoleText.visible = true;
hitMoleDesc.visible = true;
horseBettingButton.visible = true;
horseBettingText.visible = true;
horseBettingDesc.visible = true;
carnivalTitle.visible = true;
carnivalSubtitle.visible = true;
}, 2000);
};
carnivalScreen.addChild(activeMiniGame);
} else {
LK.effects.flashObject(horseBettingButton, 0xFF0000, 500);
}
}
}
} else if (encyclopediaScreen.visible) {
// Encyclopedia interactions
var localX = x - encyclopediaScreen.x;
var localY = y - encyclopediaScreen.y;
if (localX > -75 && localX < 75 && localY > 325 && localY < 375) {
// Close button
encyclopediaScreen.visible = false;
titleScreen.visible = true;
} else if (localX > -275 && localX < -125 && localY > 255 && localY < 305) {
// Previous button
encyclopediaScreen.prevPage();
} else if (localX > 125 && localX < 275 && localY > 255 && localY < 305) {
// Next button
encyclopediaScreen.nextPage();
}
} else if (shopScreen.visible) {
// Shop interactions
if (x > 100 && x < 300 && y > 100 && y < 300) {
// Back button
shopScreen.visible = false;
titleScreen.visible = true;
}
// Tab buttons
if (x > 650 && x < 850 && y > 200 && y < 300) {
// Weapons tab
switchShopTab('weapons');
} else if (x > 1198 && x < 1398 && y > 200 && y < 300) {
// Subweapons tab
switchShopTab('subweapons');
}
// Subweapon buttons (only when subweapons tab is active)
if (currentTab === 'subweapons') {
var subweaponY = [400, 550, 700];
var subweaponIds = ['santa_helper', 'krusty_shop', 'snowball_cat'];
for (var i = 0; i < subweaponY.length; i++) {
if (x > 224 && x < 1824 && y > subweaponY[i] - 96 && y < subweaponY[i] + 96) {
var subweaponId = subweaponIds[i];
if (unlockedSubweapons.indexOf(subweaponId) !== -1) {
// Already owned - equip it
selectedSubweapon = selectedSubweapon === subweaponId ? null : subweaponId;
try {
storage.selectedSubweapon = selectedSubweapon;
} catch (e) {
console.log('Could not save selected subweapon:', e);
}
updateShopDisplay();
} else if (bart.coins >= subweaponPrices[subweaponId]) {
// Can afford - buy it
bart.coins -= subweaponPrices[subweaponId];
unlockedSubweapons.push(subweaponId);
selectedSubweapon = subweaponId;
try {
storage.coins = bart.coins;
storage.unlockedSubweapons = unlockedSubweapons;
storage.selectedSubweapon = selectedSubweapon;
} catch (e) {
console.log('Could not save subweapon purchase:', e);
}
updateShopDisplay();
}
}
}
}
// Weapon buttons (only when weapons tab is active)
if (currentTab === 'weapons') {
var weaponY = [400, 550, 700, 850, 1000, 1150, 1300, 1450];
var weaponIds = ['slingshot', 'dartgun', 'scattershot', 'ducky', 'bow', 'spraycan', 'pot', 'flower'];
for (var i = 0; i < weaponY.length; i++) {
if (x > 224 && x < 1824 && y > weaponY[i] - 120 && y < weaponY[i] + 120) {
var weaponId = weaponIds[i];
if (unlockedWeapons.indexOf(weaponId) !== -1) {
// Already owned - equip it
selectedWeapon = weaponId;
bart.updateWeaponVisual(selectedWeapon);
try {
storage.selectedWeapon = selectedWeapon;
} catch (e) {
console.log('Could not save selected weapon:', e);
}
updateShopDisplay();
} else if (bart.coins >= weaponPrices[weaponId]) {
// Can afford - buy it
bart.coins -= weaponPrices[weaponId];
unlockedWeapons.push(weaponId);
selectedWeapon = weaponId;
bart.updateWeaponVisual(selectedWeapon);
try {
storage.coins = bart.coins;
storage.unlockedWeapons = unlockedWeapons;
storage.selectedWeapon = selectedWeapon;
} catch (e) {
console.log('Could not save weapon purchase:', e);
}
updateShopDisplay();
}
}
}
}
} else {
// Title screen
if (x > 824 && x < 1224 && y > 1300 && y < 1500) {
// Start button
startGame();
} else if (x > 824 && x < 1224 && y > 1700 && y < 1900) {
// Shop button
titleScreen.visible = false;
shopScreen.visible = true;
updateShopDisplay();
} else if (x > 824 && x < 1224 && y > 2000 && y < 2200) {
// Encyclopedia button
titleScreen.visible = false;
encyclopediaScreen.visible = true;
} else if (x > 312 && x < 712 && y > 1900 && y < 2350) {
// Carnival button
titleScreen.visible = false;
carnivalScreen.visible = true;
carnivalCoinsText.setText('Coins: ' + bart.coins);
} else if (x > 100 && x < 300 && y > 350 && y < 450) {
// Quality toggle button
toggleQualityMode();
} else if (x > 1286 && x < 1786 && y > 2000 && y < 2200) {
// Giant Mutant Rush button - show boss selection
if (bart.coins >= 50) {
titleScreen.visible = false;
bossSelectionScreen.visible = true;
bossSelectionCoinsText.setText('Coins: ' + bart.coins);
} else {
// Flash button red to indicate insufficient funds
LK.effects.flashObject(giantMutantRushButton, 0xFF0000, 500);
}
}
}
} else {
// Check if touch is on joystick area
var joystickScreenX = joystickCenter.x;
var joystickScreenY = 2732 - 150; // Convert GUI coordinate to screen coordinate
var distFromJoystick = Math.sqrt((x - joystickScreenX) * (x - joystickScreenX) + (y - joystickScreenY) * (y - joystickScreenY));
if (distFromJoystick <= joystickRadius * 2) {
joystickPressed = true;
updateJoystick(x, y);
}
}
};
game.up = function (x, y, obj) {
joystickPressed = false;
joystickDirection.x = 0;
joystickDirection.y = 0;
if (joystickKnob) {
joystickKnob.x = joystickCenter.x;
joystickKnob.y = -150;
}
};
game.move = function (x, y, obj) {
if (joystickPressed && !bart.stunned) {
updateJoystick(x, y);
}
};
game.update = function () {
if (!gameStarted) {
// Animate title on title screen (reduce animation in low quality mode)
if (!isLowQualityMode) {
titleText.y = 800 + Math.sin(LK.ticks * 0.05) * 20;
}
// Update active mini-game if any
if (activeMiniGame && activeMiniGame.update) {
activeMiniGame.update();
}
// Handle ad countdown
if (isWatchingAd && adCountdown > 0) {
adCountdown--;
var secondsLeft = Math.ceil(adCountdown / 60);
adCountdownText.setText(secondsLeft.toString());
// Animate countdown text
if (adCountdown % 60 === 0) {
tween(adCountdownText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
tween(adCountdownText, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
// Ad complete
if (adCountdown <= 0) {
isWatchingAd = false;
adOverlay.visible = false;
// Give free entry
selectBossAfterAd();
}
}
return;
}
// Handle attack speed debuff
if (bart.attackSpeedDebuffTimer && bart.attackSpeedDebuffTimer > 0) {
bart.attackSpeedDebuffTimer--;
if (bart.attackSpeedDebuffTimer <= 0) {
bart.fireRate = bart.originalFireRate;
// Restore Bart's normal weapon visual
bart.updateWeaponVisual(selectedWeapon);
}
}
// Update Bart position based on joystick
if (gameStarted && joystickDirection.x !== 0 || joystickDirection.y !== 0) {
if (!bart.stunned) {
bart.x += joystickDirection.x * joystickSpeed;
bart.y += joystickDirection.y * joystickSpeed;
// Keep Bart within bounds
bart.x = Math.max(60, Math.min(1988, bart.x));
bart.y = Math.max(80, Math.min(2652, bart.y));
}
}
shootBullet();
spawnTimer--;
if (spawnTimer <= 0) {
if (!isGiantMutantRush) {
spawnEnemy();
// Dynamic spawn rate that gets faster but never too overwhelming
var baseSpawnRate = 120 - wave * 4;
if (wave >= 10) baseSpawnRate -= 20; // Faster spawning for waves 10+
if (wave >= 15) baseSpawnRate += 30; // Slower spawning for waves 15+ to reduce difficulty
spawnTimer = Math.max(20, baseSpawnRate);
} else {
// Giant Mutant Rush mode - no regular spawning
spawnTimer = 60;
}
}
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.shouldDestroy || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check for reflection by Samurai Mutant's katana
var reflected = false;
for (var s = 0; s < enemies.length; s++) {
if (enemies[s] instanceof SamuraiMutant && !enemies[s].invincible) {
var samurai = enemies[s];
var dx = bullet.x - samurai.x;
var dy = bullet.y - samurai.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < samurai.reflectRadius) {
// Reflect the bullet back towards Bart
reflected = true;
if (bart) {
bullet.target = bart;
// Reverse bullet direction
var newDx = bart.x - bullet.x;
var newDy = bart.y - bullet.y;
var newDist = Math.sqrt(newDx * newDx + newDy * newDy);
if (newDist > 0) {
bullet.velocityX = newDx / newDist * bullet.speed;
bullet.velocityY = newDy / newDist * bullet.speed;
}
}
// Visual effect for reflection
LK.effects.flashObject(samurai.katana, 0xFFFFFF, 200);
LK.getSound('hit').play();
break;
}
}
}
if (reflected) continue;
for (var j = enemies.length - 1; j >= 0; j--) {
if (bullet.intersects(enemies[j])) {
// Handle spray stun
if (bullet instanceof Spray) {
enemies[j].takeDamage(bullet.damage, bullet.stunDuration);
} else {
enemies[j].takeDamage(bullet.damage);
}
// Handle rubber arrow - no longer pierces
if (bullet instanceof RubberArrow) {
bullet.destroy();
bullets.splice(i, 1);
break;
}
// Handle pot bomb explosion
if (bullet instanceof PotBomb) {
bullet.explode();
bullets.splice(i, 1);
break;
}
// Handle peanut splitting
if (bullet instanceof Peanut && !bullet.hasSplit) {
bullet.hasSplit = true;
// Create 3 small nuts
for (var k = 0; k < 3; k++) {
var nut = new SmallNut();
nut.x = bullet.x;
nut.y = bullet.y;
// Spread nuts in different directions
var angle = (k - 1) * 0.8; // -0.8, 0, 0.8 radians
nut.velocityX = Math.sin(angle) * 8;
nut.velocityY = Math.cos(angle) * -8;
bullets.push(nut);
game.addChild(nut);
}
}
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
// Check if reflected bullet hits Bart
if (bullet.target === bart && bullet.intersects(bart)) {
bart.takeDamage(bullet.damage);
bullet.destroy();
bullets.splice(i, 1);
break;
}
// Check collision with alien meals
for (var j = alienMeals.length - 1; j >= 0; j--) {
if (bullet.intersects(alienMeals[j])) {
alienMeals[j].destroy();
alienMeals.splice(j, 1);
bullet.destroy();
bullets.splice(i, 1);
LK.effects.flashObject(bullet, 0xFF0000, 200);
break;
}
}
}
var bartTookDamage = false;
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(bart)) {
if (enemy instanceof MutantLeader || enemy instanceof Concert || enemy instanceof UFOStriker) {
// Instant kill for Giant Mutants (UFO Striker starts kidnapping instead)
if (enemy instanceof UFOStriker) {
// UFO Striker starts kidnapping on touch
continue; // Skip normal damage, UFO handles it
}
bart.health = 0;
bart.takeDamage(0); // Trigger game over
} else {
var damage = 10;
if (enemy instanceof VocalMutant) {
damage = enemy.getDamage();
} else if (enemy.damageMultiplier) {
damage = Math.floor(10 * enemy.damageMultiplier);
}
bart.takeDamage(damage);
enemy.shouldDestroy = true;
}
bartTookDamage = true;
}
if (enemy.y > 2832) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Handle speed boost timers
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].speedBoosted && enemies[i].speedBoostTimer) {
enemies[i].speedBoostTimer--;
if (enemies[i].speedBoostTimer <= 0) {
enemies[i].speed = enemies[i].originalSpeed;
enemies[i].speedBoosted = false;
}
}
}
// Only process enemy destruction and XP gain if Bart didn't take damage this frame
if (!bartTookDamage) {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.shouldDestroy) {
var xpToGain = enemy.xpValue;
// Double XP for Toy Bow weapon
if (selectedWeapon === 'bow') {
xpToGain = enemy.xpValue * 2;
}
bart.gainXP(xpToGain);
LK.setScore(LK.getScore() + enemy.xpValue);
scoreText.setText('Score: ' + LK.getScore());
enemiesKilled++;
// Automatic 350 coins for Giant Mutants in Giant Mutant Rush mode
if (isGiantMutantRush && (enemy instanceof MutantLeader || enemy instanceof Concert || enemy instanceof UFOStriker)) {
bart.coins += 350;
coinText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins for Giant Mutant:', e);
}
}
if (Math.random() < enemy.coinChance) {
if (enemy instanceof MutantLeader) {
// Drop tons of coins for Mutant Leader
for (var c = 0; c < 20; c++) {
spawnItem(enemy.x + (Math.random() - 0.5) * 200, enemy.y + (Math.random() - 0.5) * 200, 'coin');
}
} else {
spawnItem(enemy.x, enemy.y, 'coin');
}
}
if (Math.random() < enemy.powerupChance) {
spawnItem(enemy.x, enemy.y, 'powerup');
}
// Check if this was a Giant Mutant in Giant Mutant Rush mode
if (isGiantMutantRush && (enemy instanceof MutantLeader || enemy instanceof Concert || enemy instanceof UFOStriker)) {
// Victory!
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins on victory:', e);
}
LK.showYouWin();
}
enemy.destroy();
enemies.splice(i, 1);
// Dynamic enemy count per wave - starts at 10, increases every 5 waves
var enemiesNeeded = 10 + Math.floor((wave - 1) / 5) * 5;
if (enemiesKilled >= enemiesNeeded) {
wave++;
enemiesKilled = 0;
// Infinite waves - no win condition
waveText.setText('Wave ' + wave);
// Special celebration for milestone waves
if (wave % 5 === 0) {
if (!isLowQualityMode) {
LK.effects.flashScreen(0xFFD700, 1000);
}
waveText.tint = 0xFFD700;
} else {
waveText.tint = 0xFFFFFF;
}
if (!isLowQualityMode) {
tween(waveText, {
scaleX: 2,
scaleY: 2
}, {
duration: 500,
easing: tween.elasticOut
});
tween(waveText, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.elasticIn
});
}
}
continue;
}
}
} else {
// If Bart took damage, still clean up destroyed enemies but don't give XP
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.shouldDestroy) {
enemy.destroy();
enemies.splice(i, 1);
}
}
}
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
if (item.shouldDestroy) {
item.destroy();
items.splice(i, 1);
continue;
}
if (item.intersects(bart)) {
if (item instanceof Coin) {
bart.coins += item.value;
coinText.setText('Coins: ' + bart.coins);
try {
storage.coins = bart.coins;
} catch (e) {
console.log('Could not save coins:', e);
}
LK.getSound('pickup').play();
} else if (item instanceof PowerUp) {
if (item.type === 'damage') {
bart.damage += 5;
} else {
bart.fireRate = Math.max(5, bart.fireRate - 5);
}
LK.getSound('powerup_pickup').play();
}
item.destroy();
items.splice(i, 1);
}
}
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
var projectile = enemyProjectiles[i];
if (projectile.shouldDestroy || projectile.y < -50 || projectile.y > 2832 || projectile.x < -50 || projectile.x > 2098) {
projectile.destroy();
enemyProjectiles.splice(i, 1);
continue;
}
if (projectile.intersects(bart)) {
// Handle StunRay stunning effect
if (projectile instanceof StunRay) {
bart.takeDamage(projectile.damage);
if (!bart.stunned) {
bart.stunned = true;
bart.stunnedTimer = projectile.stunDuration;
}
} else {
bart.takeDamage(projectile.damage);
}
projectile.destroy();
enemyProjectiles.splice(i, 1);
}
}
for (var i = alienMeals.length - 1; i >= 0; i--) {
var meal = alienMeals[i];
if (meal.shouldDestroy) {
meal.destroy();
alienMeals.splice(i, 1);
}
}
levelText.setText('Level ' + bart.level);
xpBarFill.scaleX = bart.xp / bart.xpToNext;
};
LK.playMusic('battle');
Bart holding a slingshot. In-Game asset. 2d. High contrast. No shadows
Alien mutant from the Simpsons. In-Game asset. 2d. High contrast. No shadows
Make my character purple
Krusty Burger. In-Game asset. 2d. High contrast. No shadows
Remove Krusty burger
Make my character red
Make my character turquoise and make him hold a bowling ball
Bart holding a plasma gun. In-Game asset. 2d. High contrast. No shadows
Bart holding a shotgun with 2 duck heads instead of barrels and make sure that Bart's body is fully visible In-Game asset. 2d. High contrast. No shadows
Bart in a fighting pose with a flower's head in his shirt. In-Game asset. 2d. High contrast. No shadows
Plasma projectile. In-Game asset. 2d. High contrast. No shadows
Red bowling ball. In-Game asset. 2d. High contrast. No shadows
Santa's Little Helper the Simpsons In-Game asset. 2d. High contrast. No shadows
Make my character have White Classical hair and make him hold a poem
Make my character orange, have a chef's hat and make him hold some Alien Jelly
Alien food: Some green, oozing jelly and some purple shrimp with blue Human eyes all on a plate In-Game asset. 2d. High contrast. No shadows.
Bart holding a light brown slingshot shaped like a peanut. Make him be in a fighting stance In-Game asset. 2d. High contrast. No shadows
Bart holding a purple Spraycan while he is wearing purple shoes and shorts. Show all of his body in a fighting stance In-Game asset. 2d. High contrast. No shadows
Peanut. In-Game asset. 2d. High contrast. No shadows
Chestnut. In-Game asset. 2d. High contrast. No shadows
Add outlines
Make my character dark yellow and have a red samurai helmet
Katana. In-Game asset. 2d. High contrast. No shadows
Make my character have more tentacle based hands and make him have dark black hair with a ponytail (make my character's background white)
Make my character have cute white hair and make him hold a microphone
Make my character pink and make him have rock hair and a rock guitar
Make my character have a brown mustache, hold a gun and have a sergeant's hat
Bart is tired. In-Game asset. 2d. High contrast. No shadows
Bullet. In-Game asset. 2d. High contrast. No shadows
Topdown stageplay design no instruments or crowd, only the base. In-Game asset. 2d. High contrast. No shadows
Bart holding a toy bow and has a quiver full of toy arrows. In-Game asset. 2d. High contrast. No shadows
Bart holding a pot with a plant and is about to throw it. In-Game asset. 2d. High contrast. No shadows
Potted plant. In-Game asset. 2d. High contrast. No shadows
Pottery sherd. In-Game asset. 2d. High contrast. No shadows
Make my character inside an UFO armed with a laser cannon and make him drive it
Itchy's head. In-Game asset. 2d. High contrast. No shadows. Simpsons
Scratchy's head. In-Game asset. 2d. High contrast. No shadows. Simpsons
Itchy and scratchy show!. In-Game asset. 2d. High contrast. No shadows