User prompt
Make Joystick use those assets
User prompt
Change Bart's movement to use a joystick (not the ones for console, a joystick used in action mobile games)
User prompt
Low quality mode changes resolution from HD to FHD
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'resolution')' in or related to this line: 'game.renderer.resolution = 0.5; // Reduce resolution by 50%' Line Number: 3406
User prompt
Add a low quality mode that makes the game much smoother but reduces the quality to 360p
User prompt
Remove the new subweapons
User prompt
I can't buy the new subweapons: Fix that
User prompt
Add assets for new subweapons
User prompt
Now you can watch a 30 second Itchy and Scratchy show ad to skip fees in Giant Mutant rush
User prompt
Add new feature: Carnival! Play mini games to get some coins. There's an entry fee of 10 coins per mini game (Minigames: Itchy tac Scratchy: It's basically tic tac toe, nothing special; Hit the mole: hit 5 Scratchies in a row to win coins, however, if you hit an Itchy, you lose; Horse betting: Bet between Itchy's or Scratchy's horse in a race, if you bet correctly, you gain coins!) and don't forget to add assets and make them highly polished ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add new feature: Carnival! Play mini games to get some coins. There's an entry fee of 10 coins per mini game (Minigames: Itchy tac Scratchy: It's basically tic tac toe, nothing special; Hit the mole: hit 5 Scratchies in a row to win coins, however, if you hit an Itchy, you lose; Horse betting: Bet between Itchy's or Scratchy's horse in a race, if you bet correctly, you gain coins!)
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.statusText.style.fill = 0xFF0000;' Line Number: 1295
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.cells[row][col].text.style.fill = player === 1 ? 0xFF0000 : 0x0000FF;' Line Number: 1690
User prompt
Add new feature: Carnival! Play mini games to get some coins. There's an entry fee of 10 coins per mini game (Minigames: Itchy tac Scratchy: It's basically tic tac toe but with 5 rows and 5 columns; Hit the mole: hit 5 Scratchies in a row to win coins, however, if you hit an Itchy, you lose; Horse betting: Bet between Itchy's or Scratchy's horse in a race, if you bet correctly, you gain coins!) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add 3 sub weapons of YOUR CHOICE
User prompt
Add assets for UFO striker
User prompt
I can't buy new subweapons
User prompt
I can't buy new subweapons
User prompt
Add new Sub weapons: Marge (Marge can cook Cakes that have an aura around them that heals Bart: The cakes last for roughly 10 seconds and Marge cooks them every 7.5 seconds), Toy store: Allows you to switch weapons (not subweapons) during battle! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add Encyclopedia entries for Giant Mutants
User prompt
UFO Striker should be faster
User prompt
Add new Giant Mutant: UFO Striker! A slow moving UFO that has 30550 HP and will try to kidnap you! Being kidnapped is a 5 seconds cut scene and happens whenever the UFO touches Bart! (Abilities: Stun-Ray: a projectile that stuns Bart for 0.75 seconds: being stunned means that you can't move until the stun ends; Replica: does a random move from any random boss every 7.5 seconds; Clone: The boss makes a blue tinted Replica of itself every 100 seconds: the Replica has 10000 HP) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When pots explode, they should disappear
User prompt
Now pots always drop pottery sherds
User prompt
Pots now explode after 4 seconds of being created to "Reduce lag" ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * 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');
===================================================================
--- original.js
+++ change.js
@@ -4519,28 +4519,22 @@
game.addChild(activeSubweapon);
}
}
// Create joystick
- joystick = LK.gui.bottomLeft.attachAsset('healthbar_bg', {
+ joystick = LK.gui.bottomLeft.attachAsset('joystick_base', {
anchorX: 0.5,
anchorY: 0.5,
x: joystickCenter.x,
- y: -150,
- scaleX: 2,
- scaleY: 2
+ y: -150
});
- joystick.tint = 0x333333;
- joystick.alpha = 0.6;
- joystickKnob = LK.gui.bottomLeft.attachAsset('healthbar_fill', {
+ joystick.alpha = 0.8;
+ joystickKnob = LK.gui.bottomLeft.attachAsset('joystick_knob', {
anchorX: 0.5,
anchorY: 0.5,
x: joystickCenter.x,
- y: -150,
- scaleX: 1.5,
- scaleY: 1.5
+ y: -150
});
- joystickKnob.tint = 0x00FF00;
- joystickKnob.alpha = 0.8;
+ joystickKnob.alpha = 0.9;
// Show initial wave text
waveText.setText('Wave 1');
if (!isLowQualityMode) {
tween(waveText, {
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