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