User prompt
The main character’s health bar should start green. When health drops to 20% or less of max health, the bar color should change to red. Also, make the health bar a bit longer and slimmer. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the number of enemies increases, they get stuck together and start circling in groups instead of attacking the main character. Please fix this so enemies don't bunch up and properly target the character. I want to be able to choose the visuals of the bullets fired when using the Healing Needle item. Make the main character’s health bar larger, with a sharper-edged rectangular shape, and increase the size of the numerical health value displayed inside it. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the number of enemies increases, they get stuck together and start circling in groups instead of attacking the main character. Please fix this so enemies don't bunch up and properly target the character. I want to be able to choose the visuals of the bullets fired when using the Healing Needle item. Make the main character’s health bar larger, with a sharper-edged rectangular shape, and increase the size of the numerical health value displayed inside it. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
After level 10, boss fights should only appear every 10 levels and not immediately repeat after finishing one. When the boss’s health drops to exactly half, it should start firing 3 bullets at a time. Upon defeating the boss, it should guarantee dropping between 10 and 20 coins. Additionally, it should drop 1 permanent item that increases the main character’s number of fired bullets by +1. When this item is collected, the character’s bullet count permanently increases by 1. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
After level 10, boss fights should only appear every 10 levels and not immediately repeat after finishing one. When the boss’s health drops to exactly half, it should start firing 3 bullets at a time. Upon defeating the boss, it should guarantee dropping between 10 and 20 coins. Additionally, it should drop 1 permanent item that increases the main character’s number of fired bullets by +1. When this item is collected, the character’s bullet count permanently increases by 1. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Remove the slow effect from the Iron Body item, and instead reduce all damage taken by 90% while it’s active.
User prompt
The Magnet item should affect the entire scene, not just the range area, and have a much stronger pull force to attract coins, diamonds, and health packs quickly to the main character. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
For the Iron Body item: The main character’s movement speed should be reduced to half of the current value. The character’s color should change to a metallic gray. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The rocket launcher’s projectile should deal area damage, allowing it to hit up to 4 enemies at once if they are standing side by side. Add new item drops from green enemies: a) Magnet When picked up, for 60 seconds, all coins, diamonds, and health packs on the map will be attracted to the main character. However, health packs will only be pulled if the character is not at full health. b) Speed When picked up, the character’s movement speed is doubled for 30 seconds. c) Wealth When picked up, for 30 seconds, the value of all collected coins and diamonds is doubled. d) Iron Body When picked up, the character’s color changes to gray for 30 seconds, and during this time: The character takes 80% less damage from all enemies. Every enemy (except bosses) that touches the character is pushed back slightly. e) Healing Needle When picked up, for 30 seconds, each bullet that hits an enemy restores the character’s health by 10% of their maximum HP. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The chance for a green enemy to appear each level should be 20%.
User prompt
Enemies affected by the freeze effect should turn blue while the effect is active. Once the effect ends, their color should return to normal. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the freeze item is picked up from the ground, all enemies on the map should slow down for 20 seconds. The slow effect should reduce their movement speed to half of their original speed. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Green enemies should be able to deal damage to the main character just like regular enemies. Their health should be the same as the current regular enemies. Only one green enemy should be able to spawn per level, with a 10% chance of appearing.
User prompt
I want to choose the visual appearance of the bullets fired by both the rocket launcher and the machine gun. When the rocket launcher’s bullet hits an enemy, it should trigger small explosions and deal damage to 3–4 enemies at once. When the machine gun bullets hit, small sparks should appear at the point of impact. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The remaining time for each picked-up item should be displayed as a countdown timer. The chance for a green enemy to spawn in each level should be 10%. Green enemies should have a 100% chance to drop one of the special items. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I want to define the appearance of the bullets fired by the boss myself. After defeating the boss, remove the body part selection screen. Instead, open the shop screen. When this shop screen opens, any remaining coins and diamonds on the ground should quickly be pulled toward the main character. Each time a boss (every 10 levels) is defeated, increase the number of bullets fired by the main character by +1. When a boss is defeated, there should be a 50% chance to drop 2 diamonds and a guaranteed drop of 1 diamond (100% chance). In every level, there should be a 20% chance for a green-colored enemy to spawn. This green enemy has a 50% chance to drop one of the following items: a) Rocket Launcher: If picked up, the player fires explosive rockets for 30 seconds, dealing splash damage to enemies. b) Freeze Bomb: If picked up, all enemy movement speed is reduced by 50% for 30 seconds. c) Machine Gun: If picked up, the player's attack speed and damage are multiplied by 5 for 30 seconds. Each of these items disappears 30 seconds after being picked up, and the corresponding effect ends. The effect remains inactive until the player picks up the item again. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
The items should appear immediately as soon as the puff effect finishes. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The items should appear immediately as soon as the puff effect finishes. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
puflama animasyonu coin gibi çekilmesin önce puf olsun sonra itemler çıksın içinden ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the puff animation just slightly slower. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make it a little faster. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Can the puff animation happen a bit faster ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the death animation for enemies a shrinking “puff” effect—where the enemy gradually gets smaller and then disappears in a soft puff. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please create a more subtle, puff-like death animation for enemies instead of the current dizzying effect. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
A small death animation should play each time an enemy is killed. ↪💡 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 Boss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
// Calculate total health of enemies from previous level (currentLevel - 1)
var previousLevel = Math.max(1, currentLevel - 1);
var enemyMaxHealth = 40 + (previousLevel - 1) * 8;
var enemiesInPreviousLevel = Math.floor(enemiesPerLevel * (1 + Math.floor((previousLevel - 1) / 5) * 0.4));
var totalEnemyHealth = enemyMaxHealth * enemiesInPreviousLevel;
self.maxHealth = totalEnemyHealth * 3;
self.health = self.maxHealth;
self.speed = 0.8 + (currentLevel - 10) * 0.1;
var baseDamage = 30;
var levelsSinceBoss1 = Math.floor((currentLevel - 10) / 10);
var damageMultiplier = 1 + levelsSinceBoss1 * 0.25; // 25% increase per 10 levels
self.damage = Math.floor(baseDamage * damageMultiplier);
self.lastAttack = 0;
// Create boss health bar background
self.healthBarBg = LK.getAsset('enemyHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 30
});
self.healthBarBg.y = -80;
self.addChild(self.healthBarBg);
// Create boss health bar fill
self.healthBarFill = LK.getAsset('enemyHealthBarFill', {
anchorX: 0,
anchorY: 0.5,
width: 196,
height: 26
});
self.healthBarFill.x = -98;
self.healthBarFill.y = -80;
self.addChild(self.healthBarFill);
self.attackCooldown = 120;
self.update = function () {
if (gameState === 'playing' && player) {
// Apply freeze effect if active
var effectiveSpeed = self.speed;
if (freezeEffectActive) {
effectiveSpeed *= 0.5;
// Apply blue tint when frozen
if (graphics.tint !== 0x4444ff) {
graphics.tint = 0x4444ff;
}
} else {
// Remove blue tint when not frozen
if (graphics.tint !== 0xffffff) {
graphics.tint = 0xffffff;
}
}
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * effectiveSpeed;
self.y += dy / distance * effectiveSpeed;
}
// Attack player on physical contact only
self.lastAttack++;
if (self.lastAttack >= self.attackCooldown) {
// Shoot bullet at player
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.velocityX = dx / distance * 6;
bullet.velocityY = dy / distance * 6;
}
bossBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.lastAttack = 0;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
// Update boss health bar
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.width = 196 * healthPercent;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Create massive explosion effect with multiple waves of particles
for (var e = 0; e < 8; e++) {
var explosionCircle = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 60 + e * 25,
height: 60 + e * 25,
alpha: 1.0 - e * 0.1,
tint: e === 0 ? 0xFF0000 : e === 1 ? 0xFF2200 : e === 2 ? 0xFF4500 : e === 3 ? 0xFF6600 : e === 4 ? 0xFF8800 : e === 5 ? 0xFFAA00 : e === 6 ? 0xFFCC00 : 0xFFFF00
});
explosionCircle.x = self.x + (Math.random() - 0.5) * 80;
explosionCircle.y = self.y + (Math.random() - 0.5) * 80;
game.addChild(explosionCircle);
// Animate explosion with dramatic scaling and movement
tween(explosionCircle, {
scaleX: 5 + e * 0.8,
scaleY: 5 + e * 0.8,
alpha: 0,
x: explosionCircle.x + (Math.random() - 0.5) * 200,
y: explosionCircle.y + (Math.random() - 0.5) * 200
}, {
duration: 800 + e * 150,
easing: e % 3 === 0 ? tween.easeOut : e % 3 === 1 ? tween.easeInOut : tween.bounceOut,
onFinish: function onFinish() {
explosionCircle.destroy();
}
});
}
// Drop multiple coins with value based on current level
for (var i = 0; i < 5; i++) {
var coin = new Coin();
coin.value = 2 + Math.floor((currentLevel - 1) / 5) * 2; // Boss coins use same formula as regular enemies
coin.x = self.x + (Math.random() - 0.5) * 100;
coin.y = self.y + (Math.random() - 0.5) * 100;
coins.push(coin);
game.addChild(coin);
}
// Guaranteed diamond drop
var diamond1 = new Diamond();
diamond1.value = (2 + Math.floor((currentLevel - 1) / 5) * 2) * 5; // Boss diamonds worth 5x current coin value
diamond1.x = self.x + (Math.random() - 0.5) * 100;
diamond1.y = self.y + (Math.random() - 0.5) * 100;
diamonds.push(diamond1);
game.addChild(diamond1);
// 50% chance for 2 additional diamonds
if (Math.random() < 0.50) {
for (var d = 0; d < 2; d++) {
var diamond = new Diamond();
diamond.value = (2 + Math.floor((currentLevel - 1) / 5) * 2) * 5;
diamond.x = self.x + (Math.random() - 0.5) * 100;
diamond.y = self.y + (Math.random() - 0.5) * 100;
diamonds.push(diamond);
game.addChild(diamond);
}
}
// Increase player bullet count after boss defeat
if (player) {
playerBulletCount++;
}
currentBoss = null;
self.destroy();
// Show shop instead of body part selection
showShop();
};
return self;
});
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 15;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.removeFromGame();
}
// Check collision with player using precise distance calculation
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collisionDistance = (player.width + self.width) / 8; // Tight collision bounds
if (distance <= collisionDistance) {
player.takeDamage(self.damage);
self.removeFromGame();
}
}
};
self.removeFromGame = function () {
for (var i = 0; i < bossBullets.length; i++) {
if (bossBullets[i] === self) {
bossBullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 10;
self.creationTime = LK.ticks; // Track when coin was created
self.expirationStarted = false;
// Start continuous Y-axis rotation
self.startRotation = function () {
tween(graphics, {
scaleX: -1
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(graphics, {
scaleX: 1
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.expirationStarted) {
self.startRotation();
}
}
});
}
});
};
self.startRotation();
self.update = function () {
// Check for expiration after 30 seconds (30 * 60 = 1800 ticks at 60 FPS)
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
// Start fade out animation over 1 second
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
// Remove from coins array
for (var i = 0; i < coins.length; i++) {
if (coins[i] === self) {
coins.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
// Check if coin is within player's attack range for magnetism
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4; // Tight collision bounds for collection
// Only collect on precise physical contact using distance calculation
if (distance <= collectionDistance) {
var coinValue = self.value;
if (wealthActive) {
coinValue *= 2; // Double value during wealth effect
}
playerCoins += coinValue;
coinText.setText('Coins: ' + playerCoins);
LK.getSound('coinCollect').play();
// Create floating value text
var valueText = new Text2('+' + self.value, {
size: 45,
fill: 0x00ff00
});
valueText.anchor.set(0.5, 0.5);
valueText.x = self.x;
valueText.y = self.y;
game.addChild(valueText);
// Animate the value text floating up and fading out
tween(valueText, {
y: valueText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
valueText.destroy();
}
});
// Remove from coins array
for (var i = 0; i < coins.length; i++) {
if (coins[i] === self) {
coins.splice(i, 1);
break;
}
}
self.destroy();
} else if (magnetActive && distance <= 400 || distance <= player.attackRange && distance > collectionDistance) {
// Coin is within magnet range or attack range but not collected yet - apply magnetism
if (!self.magnetismActive) {
self.magnetismActive = true;
// Stop any existing movement tweens
tween.stop(self, {
x: true,
y: true
});
}
// Calculate target position slightly closer to player
var pullStrength = magnetActive ? 0.08 : 0.04; // Stronger pull with magnet
var targetX = self.x + dx * pullStrength;
var targetY = self.y + dy * pullStrength;
// Smoothly move toward player using tween
tween(self, {
x: targetX,
y: targetY
}, {
duration: magnetActive ? 200 : 400,
easing: tween.easeOut
});
} else if (!magnetActive && distance > player.attackRange || magnetActive && distance > 400) {
// Coin is outside attack range - stop magnetism
if (self.magnetismActive) {
self.magnetismActive = false;
tween.stop(self, {
x: true,
y: true
});
}
}
}
};
return self;
});
var Diamond = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('diamond', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 10;
self.creationTime = LK.ticks;
self.expirationStarted = false;
// Start continuous Y-axis rotation
self.startRotation = function () {
tween(graphics, {
scaleX: -1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(graphics, {
scaleX: 1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.expirationStarted) {
self.startRotation();
}
}
});
}
});
};
self.startRotation();
self.update = function () {
// Check for expiration after 45 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 2700) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < diamonds.length; i++) {
if (diamonds[i] === self) {
diamonds.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
var diamondValue = self.value;
if (wealthActive) {
diamondValue *= 2; // Double value during wealth effect
}
playerCoins += diamondValue;
coinText.setText('Coins: ' + playerCoins);
LK.getSound('coinCollect').play();
// Create floating value text
var valueText = new Text2('+' + self.value, {
size: 45,
fill: 0x00ff00
});
valueText.anchor.set(0.5, 0.5);
valueText.x = self.x;
valueText.y = self.y;
game.addChild(valueText);
// Animate the value text floating up and fading out
tween(valueText, {
y: valueText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
valueText.destroy();
}
});
for (var i = 0; i < diamonds.length; i++) {
if (diamonds[i] === self) {
diamonds.splice(i, 1);
break;
}
}
self.destroy();
} else if (magnetActive && distance <= 400 || distance <= player.attackRange && distance > collectionDistance) {
if (!self.magnetismActive) {
self.magnetismActive = true;
tween.stop(self, {
x: true,
y: true
});
}
var pullStrength = magnetActive ? 0.08 : 0.04;
var targetX = self.x + dx * pullStrength;
var targetY = self.y + dy * pullStrength;
tween(self, {
x: targetX,
y: targetY
}, {
duration: magnetActive ? 200 : 400,
easing: tween.easeOut
});
} else if (!magnetActive && distance > player.attackRange || magnetActive && distance > 400) {
if (self.magnetismActive) {
self.magnetismActive = false;
tween.stop(self, {
x: true,
y: true
});
}
}
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 40 + (currentLevel - 1) * 8;
self.health = self.maxHealth;
self.speed = 1.5 + (currentLevel - 1) * 0.15;
self.damage = 10 * (1 + (currentLevel - 1) * 0.1);
self.lastAttack = 0;
self.attackCooldown = 120;
// Create enemy health bar background (simple rectangle)
self.healthBarBg = LK.getAsset('enemyHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
self.healthBarBg.y = -70;
self.addChild(self.healthBarBg);
// Create enemy health bar fill (simple rectangle)
self.healthBarFill = LK.getAsset('enemyHealthBarFill', {
anchorX: 0,
anchorY: 0.5
});
self.healthBarFill.x = -59;
self.healthBarFill.y = -70;
self.addChild(self.healthBarFill);
self.update = function () {
if (gameState === 'playing' && player) {
// Apply freeze effect if active
var effectiveSpeed = self.speed;
if (freezeEffectActive) {
effectiveSpeed *= 0.5;
// Apply blue tint when frozen
if (graphics.tint !== 0x4444ff) {
graphics.tint = 0x4444ff;
}
} else {
// Remove blue tint when not frozen
if (graphics.tint !== 0xffffff) {
graphics.tint = 0xffffff;
}
}
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var newX = self.x + dx / distance * effectiveSpeed;
var newY = self.y + dy / distance * effectiveSpeed;
// Check collision with other enemies
var canMove = true;
var collisionAngle = 0;
for (var e = 0; e < enemies.length; e++) {
var otherEnemy = enemies[e];
if (otherEnemy !== self) {
var otherDx = newX - otherEnemy.x;
var otherDy = newY - otherEnemy.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
if (otherDistance < 80) {
// Minimum distance between enemies
canMove = false;
// Calculate avoidance angle
collisionAngle = Math.atan2(otherDy, otherDx);
break;
}
}
}
if (canMove) {
self.x = newX;
self.y = newY;
} else {
// Apply collision avoidance - move perpendicular to collision
var avoidanceAngle1 = collisionAngle + Math.PI / 2;
var avoidanceAngle2 = collisionAngle - Math.PI / 2;
// Try both perpendicular directions
var avoidX1 = self.x + Math.cos(avoidanceAngle1) * effectiveSpeed;
var avoidY1 = self.y + Math.sin(avoidanceAngle1) * effectiveSpeed;
var avoidX2 = self.x + Math.cos(avoidanceAngle2) * effectiveSpeed;
var avoidY2 = self.y + Math.sin(avoidanceAngle2) * effectiveSpeed;
// Check which avoidance direction is clearer
var canAvoid1 = true;
var canAvoid2 = true;
for (var e = 0; e < enemies.length; e++) {
var otherEnemy = enemies[e];
if (otherEnemy !== self) {
var dist1 = Math.sqrt((avoidX1 - otherEnemy.x) * (avoidX1 - otherEnemy.x) + (avoidY1 - otherEnemy.y) * (avoidY1 - otherEnemy.y));
var dist2 = Math.sqrt((avoidX2 - otherEnemy.x) * (avoidX2 - otherEnemy.x) + (avoidY2 - otherEnemy.y) * (avoidY2 - otherEnemy.y));
if (dist1 < 70) canAvoid1 = false;
if (dist2 < 70) canAvoid2 = false;
}
}
// Move in the clearest direction
if (canAvoid1) {
self.x = avoidX1;
self.y = avoidY1;
} else if (canAvoid2) {
self.x = avoidX2;
self.y = avoidY2;
} else {
// If both directions blocked, move slightly away from collision
self.x += Math.cos(collisionAngle) * (effectiveSpeed * 0.5);
self.y += Math.sin(collisionAngle) * (effectiveSpeed * 0.5);
}
}
}
// Attack player on physical contact only
self.lastAttack++;
if (self.lastAttack >= self.attackCooldown) {
// Only damage on direct collision using precise distance calculation
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collisionDistance = (player.width + self.width) / 8; // Much tighter collision bounds
if (distance <= collisionDistance) {
player.takeDamage(self.damage);
self.lastAttack = 0;
// Push back enemy by a small amount (larger if Iron Body is active)
var pushDistance = ironBodyActive ? 60 : 30; // Larger pushback with Iron Body
var pushbackX = self.x - dx / distance * pushDistance;
var pushbackY = self.y - dy / distance * pushDistance;
// Use tween to animate the pushback
tween(self, {
x: pushbackX,
y: pushbackY
}, {
duration: 150,
easing: tween.easeOut
});
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
// Update enemy health bar
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.width = 118 * healthPercent;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Store position for item drops
var deathX = self.x;
var deathY = self.y;
// Enemy death animation - shrinking puff effect
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create soft puff particles after shrinking
for (var e = 0; e < 4; e++) {
var puffCircle = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 20 + e * 10,
height: 20 + e * 10,
alpha: 0.4 - e * 0.08,
tint: e === 0 ? 0xFFFFFF : e === 1 ? 0xF8F8F8 : e === 2 ? 0xF0F0F0 : 0xE8E8E8
});
puffCircle.x = deathX + (Math.random() - 0.5) * 30;
puffCircle.y = deathY + (Math.random() - 0.5) * 30;
game.addChild(puffCircle);
// Animate puff with gentle expansion and fade
tween(puffCircle, {
scaleX: 2.2 + e * 0.3,
scaleY: 2.2 + e * 0.3,
alpha: 0,
y: puffCircle.y - 20 - e * 8
}, {
duration: 500 + e * 120,
easing: tween.easeOut,
onFinish: function onFinish() {
puffCircle.destroy();
}
});
}
// Drop items immediately after puff effect starts
// Calculate coin value - increases by +2 every 5 levels
var baseValue = 2 + Math.floor((currentLevel - 1) / 5) * 2;
var coinValue = baseValue;
// Drop coin with doubled value every 10 levels
var coin = new Coin();
coin.value = coinValue;
coin.x = deathX;
coin.y = deathY;
coins.push(coin);
game.addChild(coin);
// Rarely drop diamond (1% chance)
if (Math.random() < 0.01) {
var diamond = new Diamond();
diamond.value = coinValue * 3; // 3x current coin value
diamond.x = deathX + (Math.random() - 0.5) * 60;
diamond.y = deathY + (Math.random() - 0.5) * 60;
diamonds.push(diamond);
game.addChild(diamond);
}
// Rarely drop health pack (10% chance)
if (Math.random() < 0.10) {
var healthPack = new HealthPack();
healthPack.x = deathX + (Math.random() - 0.5) * 60;
healthPack.y = deathY + (Math.random() - 0.5) * 60;
healthPacks.push(healthPack);
game.addChild(healthPack);
}
// Remove from enemies array
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
enemiesKilled++;
remainingEnemies--;
}
});
};
return self;
});
var FreezeBomb = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('freezeBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate freeze effect
freezeEffectActive = true;
freezeEffectEndTime = LK.ticks + 1200; // 20 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var GreenEnemy = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('greenEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 40 + (currentLevel - 1) * 8; // Same health as regular enemies
self.health = self.maxHealth;
self.speed = 1.5 + (currentLevel - 1) * 0.15; // Same speed as regular enemies
self.damage = 10 * (1 + (currentLevel - 1) * 0.1); // Same damage as regular enemies
self.lastAttack = 0;
self.attackCooldown = 120;
// Create enemy health bar background
self.healthBarBg = LK.getAsset('enemyHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
self.healthBarBg.y = -70;
self.addChild(self.healthBarBg);
// Create enemy health bar fill
self.healthBarFill = LK.getAsset('enemyHealthBarFill', {
anchorX: 0,
anchorY: 0.5
});
self.healthBarFill.x = -59;
self.healthBarFill.y = -70;
self.addChild(self.healthBarFill);
self.update = function () {
if (gameState === 'playing' && player) {
// Apply freeze effect if active
var effectiveSpeed = self.speed;
if (freezeEffectActive) {
effectiveSpeed *= 0.5;
// Apply blue tint when frozen
if (graphics.tint !== 0x4444ff) {
graphics.tint = 0x4444ff;
}
} else {
// Remove blue tint when not frozen (return to green color)
if (graphics.tint !== 0x00ff00) {
graphics.tint = 0x00ff00;
}
}
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var newX = self.x + dx / distance * effectiveSpeed;
var newY = self.y + dy / distance * effectiveSpeed;
// Collision avoidance logic (same as regular enemy)
var canMove = true;
var collisionAngle = 0;
for (var e = 0; e < enemies.length; e++) {
var otherEnemy = enemies[e];
if (otherEnemy !== self) {
var otherDx = newX - otherEnemy.x;
var otherDy = newY - otherEnemy.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
if (otherDistance < 80) {
canMove = false;
collisionAngle = Math.atan2(otherDy, otherDx);
break;
}
}
}
for (var g = 0; g < greenEnemies.length; g++) {
var otherGreen = greenEnemies[g];
if (otherGreen !== self) {
var otherDx = newX - otherGreen.x;
var otherDy = newY - otherGreen.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
if (otherDistance < 80) {
canMove = false;
collisionAngle = Math.atan2(otherDy, otherDx);
break;
}
}
}
if (canMove) {
self.x = newX;
self.y = newY;
} else {
// Apply collision avoidance
var avoidanceAngle1 = collisionAngle + Math.PI / 2;
var avoidanceAngle2 = collisionAngle - Math.PI / 2;
var avoidX1 = self.x + Math.cos(avoidanceAngle1) * effectiveSpeed;
var avoidY1 = self.y + Math.sin(avoidanceAngle1) * effectiveSpeed;
var avoidX2 = self.x + Math.cos(avoidanceAngle2) * effectiveSpeed;
var avoidY2 = self.y + Math.sin(avoidanceAngle2) * effectiveSpeed;
var canAvoid1 = true;
var canAvoid2 = true;
// Check avoidance paths against all enemies
for (var e = 0; e < enemies.length; e++) {
var otherEnemy = enemies[e];
if (otherEnemy !== self) {
var dist1 = Math.sqrt((avoidX1 - otherEnemy.x) * (avoidX1 - otherEnemy.x) + (avoidY1 - otherEnemy.y) * (avoidY1 - otherEnemy.y));
var dist2 = Math.sqrt((avoidX2 - otherEnemy.x) * (avoidX2 - otherEnemy.x) + (avoidY2 - otherEnemy.y) * (avoidY2 - otherEnemy.y));
if (dist1 < 70) canAvoid1 = false;
if (dist2 < 70) canAvoid2 = false;
}
}
for (var g = 0; g < greenEnemies.length; g++) {
var otherGreen = greenEnemies[g];
if (otherGreen !== self) {
var dist1 = Math.sqrt((avoidX1 - otherGreen.x) * (avoidX1 - otherGreen.x) + (avoidY1 - otherGreen.y) * (avoidY1 - otherGreen.y));
var dist2 = Math.sqrt((avoidX2 - otherGreen.x) * (avoidX2 - otherGreen.x) + (avoidY2 - otherGreen.y) * (avoidY2 - otherGreen.y));
if (dist1 < 70) canAvoid1 = false;
if (dist2 < 70) canAvoid2 = false;
}
}
if (canAvoid1) {
self.x = avoidX1;
self.y = avoidY1;
} else if (canAvoid2) {
self.x = avoidX2;
self.y = avoidY2;
} else {
self.x += Math.cos(collisionAngle) * (effectiveSpeed * 0.5);
self.y += Math.sin(collisionAngle) * (effectiveSpeed * 0.5);
}
}
}
// Attack player on physical contact
self.lastAttack++;
if (self.lastAttack >= self.attackCooldown) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collisionDistance = (player.width + self.width) / 8;
if (distance <= collisionDistance) {
player.takeDamage(self.damage);
self.lastAttack = 0;
var pushDistance = ironBodyActive ? 60 : 30; // Larger pushback with Iron Body
var pushbackX = self.x - dx / distance * pushDistance;
var pushbackY = self.y - dy / distance * pushDistance;
tween(self, {
x: pushbackX,
y: pushbackY
}, {
duration: 150,
easing: tween.easeOut
});
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health < 0) self.health = 0;
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.width = 118 * healthPercent;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
var deathX = self.x;
var deathY = self.y;
// Death animation
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Puff effect
for (var e = 0; e < 4; e++) {
var puffCircle = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 20 + e * 10,
height: 20 + e * 10,
alpha: 0.4 - e * 0.08,
tint: e === 0 ? 0x00FF00 : e === 1 ? 0x44FF44 : e === 2 ? 0x88FF88 : 0xAAFFAA
});
puffCircle.x = deathX + (Math.random() - 0.5) * 30;
puffCircle.y = deathY + (Math.random() - 0.5) * 30;
game.addChild(puffCircle);
tween(puffCircle, {
scaleX: 2.2 + e * 0.3,
scaleY: 2.2 + e * 0.3,
alpha: 0,
y: puffCircle.y - 20 - e * 8
}, {
duration: 500 + e * 120,
easing: tween.easeOut,
onFinish: function onFinish() {
puffCircle.destroy();
}
});
}
// 100% chance to drop power-up
if (Math.random() < 1.0) {
var powerUpType = Math.floor(Math.random() * 5);
var powerUp;
switch (powerUpType) {
case 0:
powerUp = new Magnet();
break;
case 1:
powerUp = new Speed();
break;
case 2:
powerUp = new Wealth();
break;
case 3:
powerUp = new IronBody();
break;
case 4:
powerUp = new HealingNeedle();
break;
}
powerUp.x = deathX;
powerUp.y = deathY;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Remove from greenEnemies array
for (var i = 0; i < greenEnemies.length; i++) {
if (greenEnemies[i] === self) {
greenEnemies.splice(i, 1);
break;
}
}
self.destroy();
enemiesKilled++;
remainingEnemies--;
}
});
};
return self;
});
var HealingNeedle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('healingNeedle', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate healing needle effect
healingNeedleActive = true;
healingNeedleEndTime = LK.ticks + 1800; // 30 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 0.15; // 15% of max health
self.creationTime = LK.ticks; // Track when health pack was created
self.expirationStarted = false;
// Start continuous Y-axis rotation
self.startRotation = function () {
tween(graphics, {
scaleX: -1
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(graphics, {
scaleX: 1
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.expirationStarted) {
self.startRotation();
}
}
});
}
});
};
self.startRotation();
self.update = function () {
// Check for expiration after 1 minute (60 * 60 = 3600 ticks at 60 FPS)
if (!self.expirationStarted && LK.ticks - self.creationTime >= 3600) {
self.expirationStarted = true;
// Start fade out animation over 1 second
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
// Remove from healthPacks array
for (var i = 0; i < healthPacks.length; i++) {
if (healthPacks[i] === self) {
healthPacks.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player && player.health < player.maxHealth) {
// Only collect on precise physical contact using distance calculation
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4; // Tight collision bounds for collection
// Apply magnet effect if active and player is not at full health
if (magnetActive && distance <= 400 && distance > collectionDistance) {
if (!self.magnetismActive) {
self.magnetismActive = true;
tween.stop(self, {
x: true,
y: true
});
}
var pullStrength = 0.08;
var targetX = self.x + dx * pullStrength;
var targetY = self.y + dy * pullStrength;
tween(self, {
x: targetX,
y: targetY
}, {
duration: 200,
easing: tween.easeOut
});
} else if (magnetActive && distance > 400) {
if (self.magnetismActive) {
self.magnetismActive = false;
tween.stop(self, {
x: true,
y: true
});
}
}
if (distance <= collectionDistance) {
var healValue = Math.floor(player.maxHealth * self.healAmount);
player.health = Math.min(player.maxHealth, player.health + healValue);
LK.getSound('coinCollect').play();
// Remove from healthPacks array
for (var i = 0; i < healthPacks.length; i++) {
if (healthPacks[i] === self) {
healthPacks.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var IronBody = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('ironBody', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate iron body effect
ironBodyActive = true;
ironBodyEndTime = LK.ticks + 1800; // 30 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var MachineGun = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('machineGun', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate machine gun effect
machineGunActive = true;
machineGunEndTime = LK.ticks + 1800; // 30 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var Magnet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('magnet', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate magnet effect
magnetActive = true;
magnetEndTime = LK.ticks + 3600; // 60 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Add attack range visual
var rangeGraphics = self.attachAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.2,
width: 600,
// 300 radius * 2
height: 600 // 300 radius * 2
});
self.maxHealth = 30;
self.health = self.maxHealth;
self.speed = 2.0;
self.damage = 5;
self.attackSpeed = 120;
self.attackRange = 300; // Base attack range radius
self.lastShot = 0;
self.update = function () {
if (gameState === 'playing') {
// Apply Iron Body visual effect and speed reduction
var effectiveSpeed = self.speed;
if (ironBodyActive) {
effectiveSpeed *= 0.5; // Reduce movement speed to half
if (graphics.tint !== 0x808080) {
graphics.tint = 0x808080; // Metallic gray color
}
} else {
if (graphics.tint !== 0xffffff) {
graphics.tint = 0xffffff; // Normal color
}
}
// Move towards touch position if touching
if (touchPosition && (Math.abs(self.x - touchPosition.x) > 5 || Math.abs(self.y - touchPosition.y) > 5)) {
var dx = touchPosition.x - self.x;
var dy = touchPosition.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * effectiveSpeed;
self.y += dy / distance * effectiveSpeed;
// Make player face movement direction
if (dx > 0) {
graphics.scaleX = -Math.abs(graphics.scaleX); // Face right
} else if (dx < 0) {
graphics.scaleX = Math.abs(graphics.scaleX); // Face left
}
}
}
// Auto-shoot when enemies are in range
self.lastShot++;
var target = self.findNearestEnemy();
var effectiveAttackSpeed = self.attackSpeed;
if (machineGunActive) {
effectiveAttackSpeed = Math.floor(self.attackSpeed / 5); // 5x faster
}
if (self.lastShot >= effectiveAttackSpeed && target) {
self.shoot();
self.lastShot = 0;
}
}
};
self.shoot = function () {
var target = self.findNearestEnemy();
if (target) {
// Calculate bullet damage based on active power-ups
var bulletDamage = 20;
if (machineGunActive) {
bulletDamage *= 5;
}
// Fire multiple bullets based on playerBulletCount
for (var b = 0; b < playerBulletCount; b++) {
var bullet = new PlayerBullet();
// Set weapon type flags before creating graphics
if (rocketLauncherActive) {
bullet.isRocket = true;
}
if (machineGunActive) {
bullet.isMachineGun = true;
}
// Now create the bullet with proper graphics
bullet = new PlayerBullet();
bullet.damage = bulletDamage;
bullet.x = self.x;
bullet.y = self.y;
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Spread bullets slightly if multiple
var spreadAngle = 0;
if (playerBulletCount > 1) {
spreadAngle = (b - (playerBulletCount - 1) / 2) * 0.2; // Small spread
}
var angle = Math.atan2(dy, dx) + spreadAngle;
bullet.velocityX = Math.cos(angle) * 8;
bullet.velocityY = Math.sin(angle) * 8;
// Set weapon type flags after creation
if (rocketLauncherActive) {
bullet.isRocket = true;
}
if (machineGunActive) {
bullet.isMachineGun = true;
}
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
};
self.findNearestEnemy = function () {
if (currentBoss) {
var dx = currentBoss.x - self.x;
var dy = currentBoss.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange) return currentBoss;
}
var nearest = null;
var nearestDistance = Infinity;
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 distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && distance < nearestDistance) {
nearestDistance = distance;
nearest = enemy;
}
}
for (var g = 0; g < greenEnemies.length; g++) {
var greenEnemy = greenEnemies[g];
var dx = greenEnemy.x - self.x;
var dy = greenEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && distance < nearestDistance) {
nearestDistance = distance;
nearest = greenEnemy;
}
}
return nearest;
};
self.takeDamage = function (damage) {
var actualDamage = damage;
// Apply Iron Body damage reduction
if (ironBodyActive) {
actualDamage = Math.floor(damage * 0.2); // 80% reduction
}
self.health -= actualDamage;
if (self.health < 0) self.health = 0;
// Health bar now handled in GUI
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
// Remove player from scene
self.destroy();
player = null;
// Trigger nova explosion when player dies
for (var e = 0; e < 12; e++) {
var explosionCircle = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 80 + e * 40,
height: 80 + e * 40,
alpha: 1.0 - e * 0.08,
tint: e % 4 === 0 ? 0xFFFFFF : e % 4 === 1 ? 0xFFFF00 : e % 4 === 2 ? 0xFF8800 : 0xFF0000
});
explosionCircle.x = self.x + (Math.random() - 0.5) * 100;
explosionCircle.y = self.y + (Math.random() - 0.5) * 100;
game.addChild(explosionCircle);
// Animate massive nova explosion
tween(explosionCircle, {
scaleX: 8 + e * 1.2,
scaleY: 8 + e * 1.2,
alpha: 0,
x: explosionCircle.x + (Math.random() - 0.5) * 300,
y: explosionCircle.y + (Math.random() - 0.5) * 300
}, {
duration: 1500 + e * 200,
easing: e % 3 === 0 ? tween.easeOut : e % 3 === 1 ? tween.easeInOut : tween.bounceOut,
onFinish: function onFinish() {
explosionCircle.destroy();
}
});
}
// Show Game Over after 3 seconds with level display
LK.setTimeout(function () {
// Create custom game over display with level info
var gameOverContainer = new Container();
var gameOverBg = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 12,
scaleY: 6,
x: 0,
y: 0,
tint: 0x000000
});
gameOverContainer.addChild(gameOverBg);
var gameOverText = new Text2('GAME OVER', {
size: 120,
fill: 0xFF0000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = -200;
gameOverContainer.addChild(gameOverText);
var levelReachedText = new Text2('Level Reached: ' + currentLevel, {
size: 80,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
levelReachedText.anchor.set(0.5, 0.5);
levelReachedText.x = 0;
levelReachedText.y = -350;
gameOverContainer.addChild(levelReachedText);
gameOverContainer.x = 1024;
gameOverContainer.y = 2732;
game.addChild(gameOverContainer);
// Show standard game over after displaying custom info
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}, 3000);
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
self.velocityX = 0;
self.velocityY = 0;
self.damage = 20;
self.isRocket = false;
self.isMachineGun = false;
var graphics;
// Choose bullet asset based on weapon type
if (self.isRocket) {
graphics = self.attachAsset('rocketBullet', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.isMachineGun) {
graphics = self.attachAsset('machineGunBullet', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.removeFromGame();
}
// Check collision with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (self.intersects(enemy)) {
if (self.isRocket) {
// Rocket splash damage - damage up to 4 nearest enemies within range
var nearbyEnemies = [];
// Collect all enemies within splash radius
for (var e = 0; e < enemies.length; e++) {
var splashEnemy = enemies[e];
var dx = splashEnemy.x - self.x;
var dy = splashEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 150) {
nearbyEnemies.push({
enemy: splashEnemy,
distance: distance
});
}
}
for (var g = 0; g < greenEnemies.length; g++) {
var splashGreen = greenEnemies[g];
var dx = splashGreen.x - self.x;
var dy = splashGreen.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 150) {
nearbyEnemies.push({
enemy: splashGreen,
distance: distance
});
}
}
// Sort by distance and damage up to 4 closest enemies
nearbyEnemies.sort(function (a, b) {
return a.distance - b.distance;
});
var enemiesToDamage = Math.min(4, nearbyEnemies.length);
for (var i = 0; i < enemiesToDamage; i++) {
nearbyEnemies[i].enemy.takeDamage(self.damage + player.damage);
}
// Create explosion effect
var explosion = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 300,
alpha: 0.6,
tint: 0xFF6600
});
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
} else {
enemy.takeDamage(self.damage + player.damage);
// Apply healing needle effect when hitting enemies
if (healingNeedleActive && player) {
var healAmount = Math.floor(player.maxHealth * 0.1); // 10% of max health
player.health = Math.min(player.maxHealth, player.health + healAmount);
}
// Create spark effect for machine gun bullets
if (self.isMachineGun) {
for (var s = 0; s < 3; s++) {
var spark = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 8 + s * 4,
height: 8 + s * 4,
alpha: 0.8 - s * 0.2,
tint: s === 0 ? 0xFFFF44 : s === 1 ? 0xFFAA00 : 0xFF6600
});
spark.x = self.x + (Math.random() - 0.5) * 20;
spark.y = self.y + (Math.random() - 0.5) * 20;
game.addChild(spark);
tween(spark, {
scaleX: 1.5 + s * 0.3,
scaleY: 1.5 + s * 0.3,
alpha: 0,
x: spark.x + (Math.random() - 0.5) * 40,
y: spark.y + (Math.random() - 0.5) * 40
}, {
duration: 200 + s * 50,
easing: tween.easeOut,
onFinish: function onFinish() {
spark.destroy();
}
});
}
}
}
LK.getSound('enemyHit').play();
self.removeFromGame();
return;
}
}
// Check collision with green enemies
for (var g = 0; g < greenEnemies.length; g++) {
var greenEnemy = greenEnemies[g];
if (self.intersects(greenEnemy)) {
if (self.isRocket) {
// Rocket splash damage
for (var e = 0; e < enemies.length; e++) {
var splashEnemy = enemies[e];
var dx = splashEnemy.x - self.x;
var dy = splashEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 150) {
splashEnemy.takeDamage(self.damage + player.damage);
}
}
for (var gg = 0; gg < greenEnemies.length; gg++) {
var splashGreen = greenEnemies[gg];
var dx = splashGreen.x - self.x;
var dy = splashGreen.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 150) {
splashGreen.takeDamage(self.damage + player.damage);
}
}
// Create explosion effect
var explosion = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 300,
alpha: 0.6,
tint: 0xFF6600
});
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
} else {
greenEnemy.takeDamage(self.damage + player.damage);
// Apply healing needle effect when hitting green enemies
if (healingNeedleActive && player) {
var healAmount = Math.floor(player.maxHealth * 0.1); // 10% of max health
player.health = Math.min(player.maxHealth, player.health + healAmount);
}
// Create spark effect for machine gun bullets
if (self.isMachineGun) {
for (var s = 0; s < 3; s++) {
var spark = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 8 + s * 4,
height: 8 + s * 4,
alpha: 0.8 - s * 0.2,
tint: s === 0 ? 0xFFFF44 : s === 1 ? 0xFFAA00 : 0xFF6600
});
spark.x = self.x + (Math.random() - 0.5) * 20;
spark.y = self.y + (Math.random() - 0.5) * 20;
game.addChild(spark);
tween(spark, {
scaleX: 1.5 + s * 0.3,
scaleY: 1.5 + s * 0.3,
alpha: 0,
x: spark.x + (Math.random() - 0.5) * 40,
y: spark.y + (Math.random() - 0.5) * 40
}, {
duration: 200 + s * 50,
easing: tween.easeOut,
onFinish: function onFinish() {
spark.destroy();
}
});
}
}
}
LK.getSound('enemyHit').play();
self.removeFromGame();
return;
}
}
// Check collision with boss
if (currentBoss && self.intersects(currentBoss)) {
if (self.isRocket) {
// Splash damage on boss
var explosion = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 300,
alpha: 0.6,
tint: 0xFF6600
});
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
}
currentBoss.takeDamage(self.damage + player.damage);
// Apply healing needle effect when hitting boss
if (healingNeedleActive && player) {
var healAmount = Math.floor(player.maxHealth * 0.1); // 10% of max health
player.health = Math.min(player.maxHealth, player.health + healAmount);
}
// Create spark effect for machine gun bullets
if (self.isMachineGun) {
for (var s = 0; s < 3; s++) {
var spark = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 8 + s * 4,
height: 8 + s * 4,
alpha: 0.8 - s * 0.2,
tint: s === 0 ? 0xFFFF44 : s === 1 ? 0xFFAA00 : 0xFF6600
});
spark.x = self.x + (Math.random() - 0.5) * 20;
spark.y = self.y + (Math.random() - 0.5) * 20;
game.addChild(spark);
tween(spark, {
scaleX: 1.5 + s * 0.3,
scaleY: 1.5 + s * 0.3,
alpha: 0,
x: spark.x + (Math.random() - 0.5) * 40,
y: spark.y + (Math.random() - 0.5) * 40
}, {
duration: 200 + s * 50,
easing: tween.easeOut,
onFinish: function onFinish() {
spark.destroy();
}
});
}
}
LK.getSound('enemyHit').play();
self.removeFromGame();
}
};
self.removeFromGame = function () {
for (var i = 0; i < playerBullets.length; i++) {
if (playerBullets[i] === self) {
playerBullets.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var RocketLauncher = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('rocketLauncher', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate rocket launcher effect
rocketLauncherActive = true;
rocketLauncherEndTime = LK.ticks + 1800; // 30 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var Speed = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('speed', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate speed effect
speedActive = true;
speedEndTime = LK.ticks + 1800; // 30 seconds
speedOriginalSpeed = player.speed;
player.speed *= 2;
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
var Wealth = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wealth', {
anchorX: 0.5,
anchorY: 0.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Expire after 30 seconds
if (!self.expirationStarted && LK.ticks - self.creationTime >= 1800) {
self.expirationStarted = true;
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
});
}
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collectionDistance = (player.width + self.width) / 4;
if (distance <= collectionDistance) {
// Activate wealth effect
wealthActive = true;
wealthEndTime = LK.ticks + 1800; // 30 seconds
LK.getSound('coinCollect').play();
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.splice(i, 1);
break;
}
}
self.destroy();
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var gameState = 'playing'; // 'playing', 'shop', 'bodyPartSelection'
var currentLevel = 1;
var enemiesKilled = 0;
var enemiesPerLevel = 5;
var playerCoins = 0;
var touchPosition = null;
// Player upgrade levels and costs - reset to zero for each new game
var healthUpgradeLevel = 0;
var attackSpeedUpgradeLevel = 0;
var attackPowerUpgradeLevel = 0;
var movementSpeedUpgradeLevel = 0;
var attackRangeUpgradeLevel = 0;
// Game objects
var player = null;
var enemies = [];
var greenEnemies = [];
var playerBullets = [];
var bossBullets = [];
var coins = [];
var diamonds = [];
var healthPacks = [];
var powerUps = [];
var currentBoss = null;
var remainingEnemies = 0;
var playerBulletCount = 1;
// Power-up effects
var rocketLauncherActive = false;
var rocketLauncherEndTime = 0;
var freezeEffectActive = false;
var freezeEffectEndTime = 0;
var machineGunActive = false;
var machineGunEndTime = 0;
var magnetActive = false;
var magnetEndTime = 0;
var speedActive = false;
var speedEndTime = 0;
var speedOriginalSpeed = 0;
var wealthActive = false;
var wealthEndTime = 0;
var ironBodyActive = false;
var ironBodyEndTime = 0;
var healingNeedleActive = false;
var healingNeedleEndTime = 0;
// UI elements
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 50;
levelText.y = 50;
LK.gui.topLeft.addChild(levelText);
var remainingText = new Text2('Enemies: 0', {
size: 45,
fill: 0xFFFFFF
});
remainingText.anchor.set(0, 0);
remainingText.x = 50;
remainingText.y = 120;
LK.gui.topLeft.addChild(remainingText);
// Create player health bar background (black square) at top of screen
var playerHealthBarBg = LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0,
width: 320,
height: 55,
tint: 0x000000
});
playerHealthBarBg.x = 0;
playerHealthBarBg.y = 50;
LK.gui.top.addChild(playerHealthBarBg);
// Create player health bar fill (red square that fades to white)
var playerHealthBarFill = LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0,
width: 316,
height: 51,
tint: 0xff0000
});
playerHealthBarFill.x = -158;
playerHealthBarFill.y = 52;
LK.gui.top.addChild(playerHealthBarFill);
// Create player health text (white text)
var playerHealthBarText = new Text2('30', {
size: 38,
fill: 0xffffff
});
playerHealthBarText.anchor.set(0.5, 0.5);
playerHealthBarText.x = 0;
playerHealthBarText.y = 77;
LK.gui.top.addChild(playerHealthBarText);
var coinText = new Text2('Coins: 0', {
size: 40,
fill: 0xF1C40F
});
coinText.anchor.set(1, 0);
coinText.x = -50;
coinText.y = 50;
LK.gui.topRight.addChild(coinText);
// Stats display in top-right corner
var statsContainer = new Container();
var healthStatText = new Text2('Health: 30', {
size: 35,
fill: 0xE74C3C
});
healthStatText.anchor.set(1, 0);
healthStatText.x = -50;
healthStatText.y = 100;
var attackPowerStatText = new Text2('Attack: 5', {
size: 35,
fill: 0xFF6B6B
});
attackPowerStatText.anchor.set(1, 0);
attackPowerStatText.x = -50;
attackPowerStatText.y = 140;
var attackSpeedStatText = new Text2('A.Speed: 120', {
size: 35,
fill: 0x4ECDC4
});
attackSpeedStatText.anchor.set(1, 0);
attackSpeedStatText.x = -50;
attackSpeedStatText.y = 180;
var movementSpeedStatText = new Text2('M.Speed: 2.0', {
size: 35,
fill: 0x45B7D1
});
movementSpeedStatText.anchor.set(1, 0);
movementSpeedStatText.x = -50;
movementSpeedStatText.y = 220;
var attackRangeStatText = new Text2('Range: 600', {
size: 35,
fill: 0x9B59B6
});
attackRangeStatText.anchor.set(1, 0);
attackRangeStatText.x = -50;
attackRangeStatText.y = 260;
// Power-up timer displays
var rocketTimerText = new Text2('', {
size: 30,
fill: 0xff4444
});
rocketTimerText.anchor.set(0, 0);
rocketTimerText.x = 50;
rocketTimerText.y = 200;
rocketTimerText.visible = false;
var freezeTimerText = new Text2('', {
size: 30,
fill: 0x44aaff
});
freezeTimerText.anchor.set(0, 0);
freezeTimerText.x = 50;
freezeTimerText.y = 240;
freezeTimerText.visible = false;
var machineGunTimerText = new Text2('', {
size: 30,
fill: 0xffff44
});
machineGunTimerText.anchor.set(0, 0);
machineGunTimerText.x = 50;
machineGunTimerText.y = 280;
machineGunTimerText.visible = false;
var magnetTimerText = new Text2('', {
size: 30,
fill: 0xaa44ff
});
magnetTimerText.anchor.set(0, 0);
magnetTimerText.x = 50;
magnetTimerText.y = 320;
magnetTimerText.visible = false;
var speedTimerText = new Text2('', {
size: 30,
fill: 0x44ff44
});
speedTimerText.anchor.set(0, 0);
speedTimerText.x = 50;
speedTimerText.y = 360;
speedTimerText.visible = false;
var wealthTimerText = new Text2('', {
size: 30,
fill: 0xffaa44
});
wealthTimerText.anchor.set(0, 0);
wealthTimerText.x = 50;
wealthTimerText.y = 400;
wealthTimerText.visible = false;
var ironBodyTimerText = new Text2('', {
size: 30,
fill: 0x888888
});
ironBodyTimerText.anchor.set(0, 0);
ironBodyTimerText.x = 50;
ironBodyTimerText.y = 440;
ironBodyTimerText.visible = false;
var healingNeedleTimerText = new Text2('', {
size: 30,
fill: 0xff4488
});
healingNeedleTimerText.anchor.set(0, 0);
healingNeedleTimerText.x = 50;
healingNeedleTimerText.y = 480;
healingNeedleTimerText.visible = false;
LK.gui.topLeft.addChild(rocketTimerText);
LK.gui.topLeft.addChild(freezeTimerText);
LK.gui.topLeft.addChild(machineGunTimerText);
LK.gui.topLeft.addChild(magnetTimerText);
LK.gui.topLeft.addChild(speedTimerText);
LK.gui.topLeft.addChild(wealthTimerText);
LK.gui.topLeft.addChild(ironBodyTimerText);
LK.gui.topLeft.addChild(healingNeedleTimerText);
LK.gui.topRight.addChild(healthStatText);
LK.gui.topRight.addChild(attackPowerStatText);
LK.gui.topRight.addChild(attackSpeedStatText);
LK.gui.topRight.addChild(movementSpeedStatText);
LK.gui.topRight.addChild(attackRangeStatText);
// Shop UI (hidden initially)
var shopContainer = new Container();
var shopBackground = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 6,
x: 0,
y: 0
});
shopContainer.addChild(shopBackground);
var shopTitle = new Text2('SHOP', {
size: 120,
fill: 0x000000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 0;
shopTitle.y = -400;
shopContainer.addChild(shopTitle);
var upgradeButtons = [];
var upgradeLabels = [];
var upgradePlusButtons = [];
var upgradeCostLabels = [];
var upgradeNames = ['Health +15', 'Attack Speed +', 'Attack Power +8', 'Move Speed +0.8', 'Range +20'];
for (var i = 0; i < 5; i++) {
var buttonBg = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: -220 + i * 130
});
shopContainer.addChild(buttonBg);
upgradeButtons.push(buttonBg);
var label = new Text2(upgradeNames[i], {
size: 30,
fill: 0x000000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
label.anchor.set(0.5, 0.5);
label.x = -200;
label.y = -220 + i * 130;
shopContainer.addChild(label);
upgradeLabels.push(label);
// Plus button for each upgrade
var plusButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
x: 100,
y: -220 + i * 130,
tint: 0xff0000
});
shopContainer.addChild(plusButton);
upgradePlusButtons.push(plusButton);
// Plus text
var plusText = new Text2('+', {
size: 40,
fill: 0x000000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
plusText.anchor.set(0.5, 0.5);
plusText.x = 100;
plusText.y = -220 + i * 130;
shopContainer.addChild(plusText);
// Cost label
var costLabel = new Text2('Cost: 0', {
size: 28,
fill: 0x000000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
costLabel.anchor.set(0.5, 0.5);
costLabel.x = 280;
costLabel.y = -220 + i * 130;
shopContainer.addChild(costLabel);
upgradeCostLabels.push(costLabel);
}
var closeShopButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 500,
y: -250,
scaleX: 0.7,
scaleY: 0.7
});
shopContainer.addChild(closeShopButton);
var closeShopText = new Text2('CLOSE', {
size: 40,
fill: 0x000000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
closeShopText.anchor.set(0.5, 0.5);
closeShopText.x = 500;
closeShopText.y = -250;
shopContainer.addChild(closeShopText);
shopContainer.x = 1024;
shopContainer.y = 1366;
shopContainer.visible = false;
// Body part selection UI (hidden initially)
var bodyPartContainer = new Container();
var bodyPartBackground = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 8,
x: 0,
y: 0
});
bodyPartContainer.addChild(bodyPartBackground);
var bodyPartTitle = new Text2('CHOOSE BODY PART', {
size: 70,
fill: 0xFFFFFF
});
bodyPartTitle.anchor.set(0.5, 0.5);
bodyPartTitle.x = 0;
bodyPartTitle.y = -250;
bodyPartContainer.addChild(bodyPartTitle);
var bodyPartButtons = [];
for (var i = 0; i < 3; i++) {
var partButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100 + i * 120
});
bodyPartContainer.addChild(partButton);
bodyPartButtons.push(partButton);
}
bodyPartContainer.x = 1024;
bodyPartContainer.y = 1366;
bodyPartContainer.visible = false;
game.addChild(shopContainer);
game.addChild(bodyPartContainer);
// Initialize player
player = new Player();
player.x = 1024;
player.y = 1366;
game.addChild(player);
// Spawn initial enemies
function spawnEnemies() {
// No enemies during boss rounds (every 10 levels)
if (currentLevel % 10 === 0) {
return;
}
var enemiesToSpawn = Math.floor(enemiesPerLevel * (1 + Math.floor((currentLevel - 1) / 5) * 0.4));
remainingEnemies = enemiesToSpawn;
remainingText.setText('Enemies: ' + remainingEnemies);
// Determine if we should spawn one green enemy for this level (20% chance)
var shouldSpawnGreen = Math.random() < 0.2;
var greenSpawned = false;
for (var i = 0; i < enemiesToSpawn; i++) {
// Only spawn green enemy if we haven't spawned one yet and we should spawn one
var isGreen = shouldSpawnGreen && !greenSpawned;
if (isGreen) {
greenSpawned = true;
}
var enemy = isGreen ? new GreenEnemy() : new Enemy();
var validPosition = false;
var attempts = 0;
// Try to find non-overlapping position
while (!validPosition && attempts < 50) {
// Spawn from edges
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2782;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
// Check if position overlaps with existing enemies
validPosition = true;
for (var j = 0; j < enemies.length; j++) {
var dx = enemy.x - enemies[j].x;
var dy = enemy.y - enemies[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
// Minimum distance between enemies
validPosition = false;
break;
}
}
for (var g = 0; g < greenEnemies.length; g++) {
var dx = enemy.x - greenEnemies[g].x;
var dy = enemy.y - greenEnemies[g].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
validPosition = false;
break;
}
}
attempts++;
}
if (isGreen) {
greenEnemies.push(enemy);
} else {
enemies.push(enemy);
}
game.addChild(enemy);
}
}
function spawnBoss() {
currentBoss = new Boss();
currentBoss.x = 1024;
currentBoss.y = 200;
game.addChild(currentBoss);
}
function showShop() {
gameState = 'shop';
shopContainer.visible = true;
updateShopDisplay();
// Restore player health to full when entering shop
if (player) {
player.health = player.maxHealth;
}
// Attract all coins and diamonds currently on the ground toward player
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
// Stop any existing movement tweens
tween.stop(coin, {
x: true,
y: true
});
// Calculate duration based on distance to player
var dx = player.x - coin.x;
var dy = player.y - coin.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var duration = Math.min(1000, distance * 2); // Max 1 second, scale with distance
// Tween coin toward player
tween(coin, {
x: player.x,
y: player.y
}, {
duration: duration,
easing: tween.easeInOut
});
}
for (var i = 0; i < diamonds.length; i++) {
var diamond = diamonds[i];
// Stop any existing movement tweens
tween.stop(diamond, {
x: true,
y: true
});
// Calculate duration based on distance to player
var dx = player.x - diamond.x;
var dy = player.y - diamond.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var duration = Math.min(1000, distance * 2); // Max 1 second, scale with distance
// Tween diamond toward player
tween(diamond, {
x: player.x,
y: player.y
}, {
duration: duration,
easing: tween.easeInOut
});
}
// Hide player if within shop area to prevent overlap
if (player) {
player.visible = false;
}
// Pause all game objects
for (var i = 0; i < enemies.length; i++) {
enemies[i].visible = false;
}
}
function updateShopDisplay() {
var baseCosts = [15, 15, 15, 15, 15];
var upgradeLevels = [healthUpgradeLevel, attackSpeedUpgradeLevel, attackPowerUpgradeLevel, movementSpeedUpgradeLevel, attackRangeUpgradeLevel];
var anyAffordable = false;
for (var i = 0; i < 5; i++) {
var cost = Math.floor(baseCosts[i] * Math.pow(2.5, upgradeLevels[i]));
upgradeCostLabels[i].setText('Cost: ' + cost);
// Enable/disable plus button based on affordability
if (playerCoins >= cost) {
upgradePlusButtons[i].visible = true;
upgradePlusButtons[i].alpha = 1.0;
anyAffordable = true;
} else {
upgradePlusButtons[i].visible = true;
upgradePlusButtons[i].alpha = 0.3;
}
}
// Show/hide close button based on affordability
if (!anyAffordable) {
closeShopButton.visible = true;
closeShopText.visible = true;
} else {
closeShopButton.visible = true;
closeShopText.visible = true;
}
}
function hideShop() {
gameState = 'playing';
shopContainer.visible = false;
// Show player again
if (player) {
player.visible = true;
}
// Resume all game objects
for (var i = 0; i < enemies.length; i++) {
enemies[i].visible = true;
}
// Check if we need to spawn boss after shop
if (currentLevel % 10 === 0) {
spawnBoss();
}
}
function showBodyPartSelection() {
gameState = 'bodyPartSelection';
bodyPartContainer.visible = true;
}
function hideBodyPartSelection() {
gameState = 'playing';
bodyPartContainer.visible = false;
// Level progression is now handled in game.update
enemiesKilled = 0;
spawnEnemies();
}
// Event handlers
game.down = function (x, y, obj) {
touchPosition = {
x: x,
y: y
};
if (gameState === 'shop') {
// Convert screen coordinates to shop container coordinates
var shopPos = {
x: x - shopContainer.x,
y: y - shopContainer.y
};
// Check plus buttons
for (var i = 0; i < upgradePlusButtons.length; i++) {
var plusButton = upgradePlusButtons[i];
if (plusButton.visible && Math.abs(shopPos.x - plusButton.x) < 80 && Math.abs(shopPos.y - plusButton.y) < 40) {
var baseCosts = [15, 15, 15, 15, 15];
var upgradeLevels = [healthUpgradeLevel, attackSpeedUpgradeLevel, attackPowerUpgradeLevel, movementSpeedUpgradeLevel, attackRangeUpgradeLevel];
var cost = Math.floor(baseCosts[i] * Math.pow(2.5, upgradeLevels[i]));
if (playerCoins >= cost) {
purchaseUpgrade(i);
updateShopDisplay();
}
return;
}
}
// Check close button
if (Math.abs(shopPos.x - closeShopButton.x) < 120 && Math.abs(shopPos.y - closeShopButton.y) < 50) {
hideShop();
spawnEnemies();
}
}
if (gameState === 'bodyPartSelection') {
// Convert screen coordinates to body part container coordinates
var bodyPos = {
x: x - bodyPartContainer.x,
y: y - bodyPartContainer.y
};
for (var i = 0; i < bodyPartButtons.length; i++) {
var button = bodyPartButtons[i];
if (Math.abs(bodyPos.x - button.x) < 200 && Math.abs(bodyPos.y - button.y) < 80) {
selectBodyPart(i);
hideBodyPartSelection();
return;
}
}
}
};
game.move = function (x, y, obj) {
if (gameState === 'playing') {
touchPosition = {
x: x,
y: y
};
}
};
game.up = function (x, y, obj) {
touchPosition = null;
};
function purchaseUpgrade(upgradeIndex) {
var baseCosts = [15, 15, 15, 15, 15];
var upgradeLevels = [healthUpgradeLevel, attackSpeedUpgradeLevel, attackPowerUpgradeLevel, movementSpeedUpgradeLevel, attackRangeUpgradeLevel];
var cost = Math.floor(baseCosts[upgradeIndex] * Math.pow(2.5, upgradeLevels[upgradeIndex]));
if (playerCoins >= cost) {
playerCoins -= cost;
coinText.setText('Coins: ' + playerCoins);
switch (upgradeIndex) {
case 0:
// Health upgrade
healthUpgradeLevel++;
storage.healthUpgradeLevel = healthUpgradeLevel;
player.maxHealth += 15;
player.health = player.maxHealth;
break;
case 1:
// Attack Speed upgrade
attackSpeedUpgradeLevel++;
storage.attackSpeedUpgradeLevel = attackSpeedUpgradeLevel;
player.attackSpeed = Math.max(10, player.attackSpeed - 5);
break;
case 2:
// Attack Power upgrade
attackPowerUpgradeLevel++;
storage.attackPowerUpgradeLevel = attackPowerUpgradeLevel;
player.damage += 8;
break;
case 3:
// Movement Speed upgrade
movementSpeedUpgradeLevel++;
storage.movementSpeedUpgradeLevel = movementSpeedUpgradeLevel;
player.speed += 0.8;
break;
case 4:
// Attack Range upgrade
attackRangeUpgradeLevel++;
storage.attackRangeUpgradeLevel = attackRangeUpgradeLevel;
player.attackRange += 20;
// Update visual range circle
var rangeGraphics = player.children[1]; // Second child is the range circle
rangeGraphics.width = player.attackRange * 2;
rangeGraphics.height = player.attackRange * 2;
break;
}
updateStatsDisplay();
}
}
function updateStatsDisplay() {
healthStatText.setText('Health: ' + player.maxHealth);
attackPowerStatText.setText('Attack: ' + player.damage);
attackSpeedStatText.setText('A.Speed: ' + (130 - player.attackSpeed));
movementSpeedStatText.setText('M.Speed: ' + player.speed.toFixed(1));
attackRangeStatText.setText('Range: ' + player.attackRange * 2);
}
function selectBodyPart(partIndex) {
switch (partIndex) {
case 0:
// Strong Arms - More damage
player.damage += 25;
player.scaleX *= 1.1;
break;
case 1:
// Swift Legs - More speed
player.speed += 2;
player.scaleY *= 1.1;
break;
case 2:
// Tough Body - More health
player.maxHealth += 50;
player.health = player.maxHealth;
player.scaleX *= 1.05;
player.scaleY *= 1.05;
break;
}
}
// Spawn initial enemies
spawnEnemies();
game.update = function () {
// Update player health bar at top of screen only if player exists
if (player) {
var healthPercent = player.health / player.maxHealth;
playerHealthBarFill.width = 316 * healthPercent;
// Fade from red to white based on health percentage
var redValue = Math.floor(255 * healthPercent + 255 * (1 - healthPercent));
var greenValue = Math.floor(0 * healthPercent + 255 * (1 - healthPercent));
var blueValue = Math.floor(0 * healthPercent + 255 * (1 - healthPercent));
var newColor = redValue << 16 | greenValue << 8 | blueValue;
playerHealthBarFill.tint = newColor;
playerHealthBarText.setText(player.health.toString());
} else {
// Hide health bar when player is dead
playerHealthBarFill.width = 0;
playerHealthBarText.setText('0');
}
// Update stats display only if player exists
if (player) {
updateStatsDisplay();
}
// Update remaining enemies counter
if (currentBoss) {
remainingText.setText('Boss Fight!');
} else {
remainingText.setText('Enemies: ' + (enemies.length + greenEnemies.length));
}
// Check power-up expiration and update timers
if (rocketLauncherActive) {
if (LK.ticks >= rocketLauncherEndTime) {
rocketLauncherActive = false;
rocketTimerText.visible = false;
} else {
var remainingTime = Math.ceil((rocketLauncherEndTime - LK.ticks) / 60);
rocketTimerText.setText('Rocket: ' + remainingTime + 's');
rocketTimerText.visible = true;
}
} else {
rocketTimerText.visible = false;
}
if (freezeEffectActive) {
if (LK.ticks >= freezeEffectEndTime) {
freezeEffectActive = false;
freezeTimerText.visible = false;
} else {
var remainingTime = Math.ceil((freezeEffectEndTime - LK.ticks) / 60);
freezeTimerText.setText('Freeze: ' + remainingTime + 's');
freezeTimerText.visible = true;
}
} else {
freezeTimerText.visible = false;
}
if (machineGunActive) {
if (LK.ticks >= machineGunEndTime) {
machineGunActive = false;
machineGunTimerText.visible = false;
} else {
var remainingTime = Math.ceil((machineGunEndTime - LK.ticks) / 60);
machineGunTimerText.setText('Machine Gun: ' + remainingTime + 's');
machineGunTimerText.visible = true;
}
} else {
machineGunTimerText.visible = false;
}
if (magnetActive) {
if (LK.ticks >= magnetEndTime) {
magnetActive = false;
magnetTimerText.visible = false;
} else {
var remainingTime = Math.ceil((magnetEndTime - LK.ticks) / 60);
magnetTimerText.setText('Magnet: ' + remainingTime + 's');
magnetTimerText.visible = true;
}
} else {
magnetTimerText.visible = false;
}
if (speedActive) {
if (LK.ticks >= speedEndTime) {
speedActive = false;
if (player) {
player.speed = speedOriginalSpeed;
}
speedTimerText.visible = false;
} else {
var remainingTime = Math.ceil((speedEndTime - LK.ticks) / 60);
speedTimerText.setText('Speed: ' + remainingTime + 's');
speedTimerText.visible = true;
}
} else {
speedTimerText.visible = false;
}
if (wealthActive) {
if (LK.ticks >= wealthEndTime) {
wealthActive = false;
wealthTimerText.visible = false;
} else {
var remainingTime = Math.ceil((wealthEndTime - LK.ticks) / 60);
wealthTimerText.setText('Wealth: ' + remainingTime + 's');
wealthTimerText.visible = true;
}
} else {
wealthTimerText.visible = false;
}
if (ironBodyActive) {
if (LK.ticks >= ironBodyEndTime) {
ironBodyActive = false;
ironBodyTimerText.visible = false;
} else {
var remainingTime = Math.ceil((ironBodyEndTime - LK.ticks) / 60);
ironBodyTimerText.setText('Iron Body: ' + remainingTime + 's');
ironBodyTimerText.visible = true;
}
} else {
ironBodyTimerText.visible = false;
}
if (healingNeedleActive) {
if (LK.ticks >= healingNeedleEndTime) {
healingNeedleActive = false;
healingNeedleTimerText.visible = false;
} else {
var remainingTime = Math.ceil((healingNeedleEndTime - LK.ticks) / 60);
healingNeedleTimerText.setText('Healing: ' + remainingTime + 's');
healingNeedleTimerText.visible = true;
}
} else {
healingNeedleTimerText.visible = false;
}
// Check if all enemies are defeated
if (gameState === 'playing' && enemies.length === 0 && greenEnemies.length === 0 && !currentBoss) {
// Progress to next level
currentLevel++;
levelText.setText('Level: ' + currentLevel);
enemiesKilled = 0;
if (currentLevel % 10 === 0) {
// Show shop before boss fight every 10 levels
showShop();
} else if (currentLevel % 5 === 0) {
// Shop level every 5 levels (but not on boss levels)
showShop();
} else {
// Regular level
spawnEnemies();
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1297,12 +1297,14 @@
self.attackRange = 300; // Base attack range radius
self.lastShot = 0;
self.update = function () {
if (gameState === 'playing') {
- // Apply Iron Body visual effect
+ // Apply Iron Body visual effect and speed reduction
+ var effectiveSpeed = self.speed;
if (ironBodyActive) {
+ effectiveSpeed *= 0.5; // Reduce movement speed to half
if (graphics.tint !== 0x808080) {
- graphics.tint = 0x808080; // Gray color
+ graphics.tint = 0x808080; // Metallic gray color
}
} else {
if (graphics.tint !== 0xffffff) {
graphics.tint = 0xffffff; // Normal color
@@ -1313,10 +1315,10 @@
var dx = touchPosition.x - self.x;
var dy = touchPosition.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
- self.x += dx / distance * self.speed;
- self.y += dy / distance * self.speed;
+ self.x += dx / distance * effectiveSpeed;
+ self.y += dy / distance * effectiveSpeed;
// Make player face movement direction
if (dx > 0) {
graphics.scaleX = -Math.abs(graphics.scaleX); // Face right
} else if (dx < 0) {
coin. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
health pack. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
scary toothed germ style enemy. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
cloud. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
emerald. In-Game asset. 2d. High contrast. No shadows
blue hand granade. In-Game asset. 2d. High contrast. No shadows
a green scary ball with metal teeth. In-Game asset. 2d. High contrast. No shadows
green poison ball. In-Game asset. 2d. High contrast. No shadows
machine gun. In-Game asset. 2d. High contrast. No shadows
machine gun bullet. In-Game asset. 2d. High contrast. No shadows
rocket launcher. In-Game asset. 2d. High contrast. No shadows
horizontal rocket bullet. In-Game asset. 2d. High contrast. No shadows
treasure chest. In-Game asset. 2d. High contrast. No shadows
vaccine with a plus sign. In-Game asset. 2d. High contrast. No shadows
blue steel vest. In-Game asset. 2d. High contrast. No shadows
u magnet. In-Game asset. 2d. High contrast. No shadows
red shoes with a 2x. In-Game asset. 2d. High contrast. No shadows
horizontal needle. In-Game asset. 2d. High contrast. No shadows
horizontal fire ball. In-Game asset. 2d. High contrast. No shadows
blue
pink blue black and orange mixed horizontal fire ball. In-Game asset. 2d. High contrast. No shadows
robot virüs. In-Game asset. 2d. High contrast. No shadows
artı işareti yeşil olsun bu artı işareti tedavi artı işareti yukarıda boyadığım kısım kırmızı olsun
metal kaplı görünsün
amber stone. In-Game asset. 2d. High contrast. No shadows
rengi mor olsun