User prompt
şöyle bir sorun var 10 level bosunu kestiğimde iki mermi atmaya başladığımda düşman kestiğimde itemler çift çift çıkıyor bunun olmasını istemiyorum tek tek çıksın bunu fixle mermi sayısı ne olursa olsun çıkan item değişmesin ve health packlerin düşme oranlarını biraz azaltırmısın çok sık düşüyorlar
User prompt
20 level dan sonra bütün düşmanlardan özel turuncu renkli 10x coin çıkma olasılığı yüzde 2 olsun 40 levelda bu oran yüzde 10 olsun 50 levelde yüzde 15 olsun ve sonraki levellerdede değişmesin bu coinin değeri o anda bulunduğu levelde çıkan coin değerinin 10 katı olsun bu özel coin in adı ember olsun ve bana bu coin için asset oluşturabilir misin
User prompt
her bos kesildiğinde çıkan mermi sayısı arttıran item sadece fire ball a etki etsin yani diğer yeşil düşmandan çıkan itemler hala tek mermi atsın
User prompt
20 . levelda gelen boss dan bossu yenince tıpkı 10. levelden gelen boss ile aynı itemler düşsün 20. levelden gelen boss un maximum 15 düşman spawmlama hakkı olsun spawmladığı düşman sayısı toplamda 15 i geçmesin sniper riffle itemini yerden alınca neden bilmiyorum ama düşmanlar ana karakterle temas etmedikleri halde ana karaktere az bir mesafe kala ana karakterin canı gidiyor bunu düzeltirmisin temas anında can gidecek 20 leveldan sonra oyun kasıyor nedenini bulup sorunu çözer misin ve 30 lv bosu ve attığı mermi için assety oluştururmusun bu arada 30 level bosundan da aynı itemler düşsün diğer bosslarla en son 30 level bosu kesildiğinde 40 level de 10 level bosu gelsin 50 levelde 20 level bosu 60 levelde 30 level bosu ve bu şekilde döngü olarak devam etsin taaki 200 levele kadar 200 level oyunun sonu
User prompt
yeşil düşmandan çıkan roket atar iteminin patlama çapını arttır yani daha fazla düşmana aynanda vurabilsin
User prompt
roket atar iteminin patlama çağını arttır lütfen yani daha geniş bir alana damage vursun
User prompt
speed itemi fire rate vermesin sadece 2x hareket hızı versin
User prompt
level 30 da bir bos gelsin bu bosun özelliği bos tek tek mermi atsın mermi hızı ana karakterin o anki mermi hızının yüzde 50 si kadar olsun attığı mermiler ana karaktere isabet ederse ana karakterden bos can çeksin çektiği can oranı bosun vurduğu damage in yüzde 3 ü kadar olsun bosun damagesi kendinden bir önceki leveldaki düşmanlar kadar olsun can değeri ise 3 katı olsun bu bosun bir özelliği daha olsun canı yarıya indiğinde kendinin birebir kopyasından 1 adet daha çıkartsın bu kopyanın bütün özellikleri ana boss un yüzde 20 si kadar olsun ve bu kopyalama özelliği dakikada bir çalışsın
User prompt
20 levelda gelen bosun canı yarıya geldiğinde her 8 saniyede bir 5 düşman yanında spawmlasın 5 saniyede değil
User prompt
sniper rifle ın sağ tarafta gösterilen özellikleri bütün ekranı kaplıyor yazıyı alt satıra geçecek şekilde yazar mısın
User prompt
sniper rifle üst üste alındığında radiusda değişiklik olmasın aynı itemi tekrar aldığımızda sadece süre yenilensin başka birşey olmasın bu diğer bütün itemlerde de böyle olsun
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'attackRange')' in or related to this line: 'if (distanceFromStart > player.attackRange || self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {' Line Number: 2396
User prompt
makineli tüfek iteminde hızı 3x yapmıştık ama ekran sağındaki bilgilendirmede hala 5x yazıyor onu düzeltir misin
User prompt
sniper riflenin görüntüsünü ve fırlattığı mermileri assetlerden ben ayarlamak istiyorum
User prompt
yeşil düşmanlardan çıkan itemlere yeni bir item daha eklemek istiyorum itemin adı sniper rifle bu item yerden alındığında ana karaktere mevcut radiusunun 3 katı bir radius alanı açılsın tabi bu alanın rengi şeffaf yeşil olsun bu sniper itemi bu radiusun içinde kalan bütün rakiplere atış yapabilsin ve attığı mermiler değdiği düşmanlara zarar verip düşmanı delip geçsinler mermi radius alanının terk edene kadar yol alsın sonra kaybolsun atış hızı karakterin atış hızının yarısı kadar olsun bütün özellikleri ekranın sağında bilgilendirme olarak yazsın düşmanlara vurduğu hasar ana karakterin o anki hasarının 3 katı olsun ve itemin süresi 30sn olsun 30 sn sonra özellik ve radius alanı eskiye dönsün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Oyunun adı Fight Bacteria olsun
User prompt
düşman sayısı 15 e gelince birdaha artmasın
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'x')' in or related to this line: 'healText.x = currentBoss.x;' Line Number: 1291
User prompt
boslardan çıkan mermi artırma itemlerinden nekadar çok alırsak alalım ana karakterin aynanda fırlatacağı maximum mermi sayısı 3 ü geçmesin
User prompt
level 20 de assetlerdeki spawner boss gelsin bu bosun özelliği her 5 saniyede 1 yanından standart enemy spwmlasın canı yarıya indiğinde 5 saniyede 5 standart enemy spawmlasın o spawmladığı enemylerin gücü bir önceki leveldeki enemy lerin gücüyle eşit olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
beni 20 leveldeki boss dan başlatırmısın
User prompt
tek mermi ateşleyim lütfen ve atack speed im 400 olsun
User prompt
beni 19 .levelden başlar ve statlarımı çok yüksek yap
User prompt
beni 19 levelden başlatabilir misin
User prompt
beni 20. levelden başlatır mısın
/****
* 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 + Math.max(0, currentLevel - 10) * 0.1;
var baseDamage = 30;
var bossNumber = Math.floor(currentLevel / 10); // Boss 1 at level 10, Boss 2 at level 20, etc.
var damageMultiplier = 1 + (bossNumber - 1) * 0.5; // 50% increase per boss
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) {
// Determine number of bullets based on health
var bulletsToFire = self.health <= self.maxHealth / 2 ? 3 : 1;
// Shoot bullets at player
for (var b = 0; b < bulletsToFire; b++) {
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) {
// Add spread for multiple bullets
var spreadAngle = 0;
if (bulletsToFire > 1) {
spreadAngle = (b - (bulletsToFire - 1) / 2) * 0.3; // Spread bullets
}
var angle = Math.atan2(dy, dx) + spreadAngle;
bullet.velocityX = Math.cos(angle) * 6;
bullet.velocityY = Math.sin(angle) * 6;
// Set bullet rotation to face movement direction
if (bullet.setRotation) {
bullet.setRotation(bullet.velocityX, bullet.velocityY);
}
}
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 guaranteed 10-20 coins
var numCoins = 10 + Math.floor(Math.random() * 11); // 10-20 coins
for (var i = 0; i < numCoins; i++) {
var coin = new Coin();
// Calculate coin value - first 5 levels = 10, then +5 every 5 levels
var levelGroup = Math.floor((currentLevel - 1) / 5);
if (levelGroup === 0) {
coin.value = 10; // Levels 1-5
} else {
coin.value = 10 + levelGroup * 5; // Level 6-10 = 15, 11-15 = 20, etc.
}
coin.x = self.x + (Math.random() - 0.5) * 150;
coin.y = self.y + (Math.random() - 0.5) * 150;
coins.push(coin);
game.addChild(coin);
}
// Drop permanent bullet upgrade
var bulletUpgrade = new BulletUpgrade();
bulletUpgrade.x = self.x + (Math.random() - 0.5) * 100;
bulletUpgrade.y = self.y + (Math.random() - 0.5) * 100;
powerUps.push(bulletUpgrade);
game.addChild(bulletUpgrade);
// Guaranteed diamond drop
var diamond1 = new Diamond();
// Calculate diamond value - 5x current coin value
var levelGroup = Math.floor((currentLevel - 1) / 5);
var coinValue;
if (levelGroup === 0) {
coinValue = 10; // Levels 1-5
} else {
coinValue = 10 + levelGroup * 5; // Level 6-10 = 15, 11-15 = 20, etc.
}
diamond1.value = coinValue * 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();
// Calculate diamond value - 5x current coin value
var levelGroup = Math.floor((currentLevel - 1) / 5);
var coinValue;
if (levelGroup === 0) {
coinValue = 10; // Levels 1-5
} else {
coinValue = 10 + levelGroup * 5; // Level 6-10 = 15, 11-15 = 20, etc.
}
diamond.value = coinValue * 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);
}
}
currentBoss = null;
self.destroy();
// Boss is defeated, level progression will be handled in main update loop
enemiesKilled = 0;
};
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;
// Set rotation method for bullet orientation
self.setRotation = function (vx, vy) {
graphics.rotation = Math.atan2(vy, vx);
};
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 BulletUpgrade = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFD700,
scaleX: 1.5,
scaleY: 1.5
});
self.creationTime = LK.ticks;
self.expirationStarted = false;
self.update = function () {
// Never expire - permanent upgrade
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) {
// Permanently increase bullet count
playerBulletCount++;
LK.getSound('coinCollect').play();
// Remove from powerUps array
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i] === self) {
powerUps.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
});
// Calculate coin value - first 5 levels = 10, then +5 every 5 levels
var levelGroup = Math.floor((currentLevel - 1) / 5);
if (levelGroup === 0) {
self.value = 10; // Levels 1-5
} else {
self.value = 10 + levelGroup * 5; // Level 6-10 = 15, 11-15 = 20, etc.
}
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(playerCoins.toString());
LK.getSound('coinCollect').play();
// Create floating value text
var displayValue = wealthActive ? self.value * 2 : self.value;
var valueText = new Text2('+' + displayValue, {
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 <= player.attackRange && distance > collectionDistance) {
// Coin is within magnet range (entire scene) 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 with much stronger pull when magnet is active
var pullStrength = magnetActive ? 0.25 : 0.04; // Much 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 ? 100 : 400,
easing: tween.easeOut
});
} else if (!magnetActive && distance > player.attackRange) {
// Coin is outside attack range and magnet is not active - 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(playerCoins.toString());
LK.getSound('coinCollect').play();
// Create floating value text
var displayValue = wealthActive ? self.value * 2 : self.value;
var valueText = new Text2('+' + displayValue, {
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 <= player.attackRange && distance > collectionDistance) {
if (!self.magnetismActive) {
self.magnetismActive = true;
tween.stop(self, {
x: true,
y: true
});
}
var pullStrength = magnetActive ? 0.25 : 0.04;
var targetX = self.x + dx * pullStrength;
var targetY = self.y + dy * pullStrength;
tween(self, {
x: targetX,
y: targetY
}, {
duration: magnetActive ? 100 : 400,
easing: tween.easeOut
});
} else if (!magnetActive && distance > player.attackRange) {
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 with optimized collision avoidance
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Calculate base movement direction toward player
var targetAngle = Math.atan2(dy, dx);
var baseMovementX = Math.cos(targetAngle) * effectiveSpeed;
var baseMovementY = Math.sin(targetAngle) * effectiveSpeed;
// Only check collision avoidance every 3 frames to reduce CPU load
if (LK.ticks % 3 === 0) {
// Calculate avoidance vector
var avoidanceX = 0;
var avoidanceY = 0;
var nearbyEnemyCount = 0;
var maxChecks = Math.min(10, enemies.length); // Limit checks to 10 nearest enemies
// Check collision with limited number of other enemies
for (var e = 0; e < maxChecks && e < enemies.length; e++) {
var otherEnemy = enemies[e];
if (otherEnemy !== self) {
var otherDx = self.x - otherEnemy.x;
var otherDy = self.y - otherEnemy.y;
// Use faster distance check (no sqrt for initial filtering)
var otherDistanceSq = otherDx * otherDx + otherDy * otherDy;
if (otherDistanceSq < 10000 && otherDistanceSq > 0) {
// 100^2 = 10000
var otherDistance = Math.sqrt(otherDistanceSq);
// Calculate avoidance force that gets stronger as enemies get closer
var avoidanceStrength = (100 - otherDistance) / 100;
avoidanceX += otherDx / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
avoidanceY += otherDy / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
nearbyEnemyCount++;
}
}
}
// Check collision with limited number of green enemies
var maxGreenChecks = Math.min(5, greenEnemies.length); // Limit green enemy checks
for (var g = 0; g < maxGreenChecks && g < greenEnemies.length; g++) {
var otherGreen = greenEnemies[g];
if (otherGreen !== self) {
var otherDx = self.x - otherGreen.x;
var otherDy = self.y - otherGreen.y;
var otherDistanceSq = otherDx * otherDx + otherDy * otherDy;
if (otherDistanceSq < 10000 && otherDistanceSq > 0) {
var otherDistance = Math.sqrt(otherDistanceSq);
var avoidanceStrength = (100 - otherDistance) / 100;
avoidanceX += otherDx / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
avoidanceY += otherDy / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
nearbyEnemyCount++;
}
}
}
// Store avoidance for next few frames
self.cachedAvoidanceX = avoidanceX;
self.cachedAvoidanceY = avoidanceY;
self.cachedNearbyCount = nearbyEnemyCount;
}
// Combine movement and avoidance forces
var finalMovementX = baseMovementX;
var finalMovementY = baseMovementY;
if (self.cachedNearbyCount > 0) {
// Add cached avoidance when enemies are nearby
finalMovementX += (self.cachedAvoidanceX || 0) * 0.8; // Strong avoidance
finalMovementY += (self.cachedAvoidanceY || 0) * 0.8;
// Normalize the final movement to maintain consistent speed
var finalDistance = Math.sqrt(finalMovementX * finalMovementX + finalMovementY * finalMovementY);
if (finalDistance > effectiveSpeed) {
finalMovementX = finalMovementX / finalDistance * effectiveSpeed;
finalMovementY = finalMovementY / finalDistance * effectiveSpeed;
}
}
// Apply final movement
self.x += finalMovementX;
self.y += finalMovementY;
}
// 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 ? 135 : 45; // 3x stronger 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: 200,
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 - first 5 levels = 10, then +5 every 5 levels
var levelGroup = Math.floor((currentLevel - 1) / 5);
var coinValue;
if (levelGroup === 0) {
coinValue = 10; // Levels 1-5
} else {
coinValue = 10 + levelGroup * 5; // Level 6-10 = 15, 11-15 = 20, etc.
}
// 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);
// Drop diamond (5% chance, 30% during wealth effect)
var diamondChance = wealthActive ? 0.30 : 0.05;
if (Math.random() < diamondChance) {
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 with optimized collision avoidance
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Calculate base movement direction toward player
var targetAngle = Math.atan2(dy, dx);
var baseMovementX = Math.cos(targetAngle) * effectiveSpeed;
var baseMovementY = Math.sin(targetAngle) * effectiveSpeed;
// Only check collision avoidance every 3 frames to reduce CPU load
if (LK.ticks % 3 === 0) {
// Calculate avoidance vector
var avoidanceX = 0;
var avoidanceY = 0;
var nearbyEnemyCount = 0;
var maxChecks = Math.min(10, enemies.length); // Limit checks to 10 nearest enemies
// Check collision with limited number of regular enemies
for (var e = 0; e < maxChecks && e < enemies.length; e++) {
var otherEnemy = enemies[e];
var otherDx = self.x - otherEnemy.x;
var otherDy = self.y - otherEnemy.y;
// Use faster distance check (no sqrt for initial filtering)
var otherDistanceSq = otherDx * otherDx + otherDy * otherDy;
if (otherDistanceSq < 10000 && otherDistanceSq > 0) {
// 100^2 = 10000
var otherDistance = Math.sqrt(otherDistanceSq);
// Calculate avoidance force that gets stronger as enemies get closer
var avoidanceStrength = (100 - otherDistance) / 100;
avoidanceX += otherDx / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
avoidanceY += otherDy / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
nearbyEnemyCount++;
}
}
// Check collision with limited number of other green enemies
var maxGreenChecks = Math.min(5, greenEnemies.length); // Limit green enemy checks
for (var g = 0; g < maxGreenChecks && g < greenEnemies.length; g++) {
var otherGreen = greenEnemies[g];
if (otherGreen !== self) {
var otherDx = self.x - otherGreen.x;
var otherDy = self.y - otherGreen.y;
var otherDistanceSq = otherDx * otherDx + otherDy * otherDy;
if (otherDistanceSq < 10000 && otherDistanceSq > 0) {
var otherDistance = Math.sqrt(otherDistanceSq);
var avoidanceStrength = (100 - otherDistance) / 100;
avoidanceX += otherDx / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
avoidanceY += otherDy / otherDistance * avoidanceStrength * effectiveSpeed * 1.5;
nearbyEnemyCount++;
}
}
}
// Store avoidance for next few frames
self.cachedAvoidanceX = avoidanceX;
self.cachedAvoidanceY = avoidanceY;
self.cachedNearbyCount = nearbyEnemyCount;
}
// Combine movement and avoidance forces
var finalMovementX = baseMovementX;
var finalMovementY = baseMovementY;
if (self.cachedNearbyCount > 0) {
// Add cached avoidance when enemies are nearby
finalMovementX += (self.cachedAvoidanceX || 0) * 0.8; // Strong avoidance
finalMovementY += (self.cachedAvoidanceY || 0) * 0.8;
// Normalize the final movement to maintain consistent speed
var finalDistance = Math.sqrt(finalMovementX * finalMovementX + finalMovementY * finalMovementY);
if (finalDistance > effectiveSpeed) {
finalMovementX = finalMovementX / finalDistance * effectiveSpeed;
finalMovementY = finalMovementY / finalDistance * effectiveSpeed;
}
}
// Apply final movement
self.x += finalMovementX;
self.y += finalMovementY;
}
// 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 ? 135 : 45; // 3x stronger 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: 200,
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();
}
});
}
// Drop diamond (5% chance, 30% during wealth effect)
var diamondChance = wealthActive ? 0.30 : 0.05;
if (Math.random() < diamondChance) {
// Calculate coin value - first 5 levels = 10, then +5 every 5 levels
var levelGroup = Math.floor((currentLevel - 1) / 5);
var coinValue;
if (levelGroup === 0) {
coinValue = 10; // Levels 1-5
} else {
coinValue = 10 + levelGroup * 5; // Level 6-10 = 15, 11-15 = 20, etc.
}
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);
}
// 100% chance to drop power-up with equal chances for all items
if (Math.random() < 1.0) {
var powerUpTypes = [Magnet, Speed, Wealth, IronBody, HealingNeedle, MachineGun, RocketLauncher, FreezeBomb];
var randomIndex = Math.floor(Math.random() * powerUpTypes.length);
var powerUp = new powerUpTypes[randomIndex]();
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 HealingNeedleBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('healingNeedleBullet', {
anchorX: 0.5,
anchorY: 0.5
});
// Apply special healing needle visual effect
graphics.tint = 0x00FF88; // Bright green healing color
graphics.scaleX = 1.2;
graphics.scaleY = 1.2;
// Add pulsing glow effect
tween(graphics, {
scaleX: 1.4,
scaleY: 1.4,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00FF88
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 20;
// Set rotation method for bullet orientation
self.setRotation = function (vx, vy) {
graphics.rotation = Math.atan2(vy, vx);
};
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)) {
enemy.takeDamage(self.damage + (player ? player.damage : 0));
// Apply healing needle effect when hitting enemies
if (player) {
var healAmount = Math.floor(player.maxHealth * 0.1); // 10% of max health
player.health = Math.min(player.maxHealth, player.health + healAmount);
// Create floating heal text
var healText = new Text2('+' + healAmount + ' HP', {
size: 40,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = enemy.x;
healText.y = enemy.y;
game.addChild(healText);
// Animate the heal text floating up and fading out
tween(healText, {
y: healText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
healText.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)) {
greenEnemy.takeDamage(self.damage + (player ? player.damage : 0));
// Apply healing needle effect when hitting green enemies
if (player) {
var healAmount = Math.floor(player.maxHealth * 0.1); // 10% of max health
player.health = Math.min(player.maxHealth, player.health + healAmount);
// Create floating heal text
var healText = new Text2('+' + healAmount + ' HP', {
size: 40,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = greenEnemy.x;
healText.y = greenEnemy.y;
game.addChild(healText);
// Animate the heal text floating up and fading out
tween(healText, {
y: healText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
healText.destroy();
}
});
}
LK.getSound('enemyHit').play();
self.removeFromGame();
return;
}
}
// Check collision with boss
if (currentBoss && self.intersects(currentBoss)) {
currentBoss.takeDamage(self.damage + (player ? player.damage : 0));
// Apply healing needle effect when hitting boss
if (player) {
var healAmount = Math.floor(player.maxHealth * 0.1); // 10% of max health
player.health = Math.min(player.maxHealth, player.health + healAmount);
// Create floating heal text
var healText = new Text2('+' + healAmount + ' HP', {
size: 40,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = currentBoss.x;
healText.y = currentBoss.y;
game.addChild(healText);
// Animate the heal text floating up and fading out
tween(healText, {
y: healText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
healText.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 HealthPack = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 0.20; // 20% 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 (affects entire scene)
if (magnetActive && distance > collectionDistance) {
if (!self.magnetismActive) {
self.magnetismActive = true;
tween.stop(self, {
x: true,
y: true
});
}
var pullStrength = 0.25;
var targetX = self.x + dx * pullStrength;
var targetY = self.y + dy * pullStrength;
tween(self, {
x: targetX,
y: targetY
}, {
duration: 100,
easing: tween.easeOut
});
} else if (!magnetActive) {
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 MachineGunBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('machineGunBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 20; // Same as regular bullet damage
// Set rotation method for bullet orientation
self.setRotation = function (vx, vy) {
graphics.rotation = Math.atan2(vy, vx);
};
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 (limit checks for performance)
var maxEnemyChecks = Math.min(15, enemies.length); // Limit enemy checks for machine gun bullets
for (var i = 0; i < maxEnemyChecks; i++) {
var enemy = enemies[i];
if (self.intersects(enemy)) {
enemy.takeDamage(self.damage + (player ? player.damage : 0));
// 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 floating heal text
var healText = new Text2('+' + healAmount + ' HP', {
size: 40,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = enemy.x;
healText.y = enemy.y;
game.addChild(healText);
// Animate the heal text floating up and fading out
tween(healText, {
y: healText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
healText.destroy();
}
});
}
// Create spark effect for machine gun bullets
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 (limit checks for performance)
var maxGreenChecks = Math.min(8, greenEnemies.length); // Limit green enemy checks for machine gun bullets
for (var g = 0; g < maxGreenChecks; g++) {
var greenEnemy = greenEnemies[g];
if (self.intersects(greenEnemy)) {
greenEnemy.takeDamage(self.damage + (player ? player.damage : 0));
// 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 floating heal text
var healText = new Text2('+' + healAmount + ' HP', {
size: 40,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = greenEnemy.x;
healText.y = greenEnemy.y;
game.addChild(healText);
// Animate the heal text floating up and fading out
tween(healText, {
y: healText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
healText.destroy();
}
});
}
// Create spark effect for machine gun bullets
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)) {
currentBoss.takeDamage(self.damage + (player ? player.damage : 0));
// 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 floating heal text
var healText = new Text2('+' + healAmount + ' HP', {
size: 40,
fill: 0x00ff00
});
healText.anchor.set(0.5, 0.5);
healText.x = currentBoss.x;
healText.y = currentBoss.y;
game.addChild(healText);
// Animate the heal text floating up and fading out
tween(healText, {
y: healText.y - 80,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
healText.destroy();
}
});
}
// Create spark effect for machine gun bullets
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 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 = 50;
self.health = self.maxHealth;
self.speed = 2.2;
self.damage = 5;
self.attackSpeed = 103;
self.attackRange = 300; // Base attack range radius
self.lastShot = 0;
self.update = function () {
if (gameState === 'playing') {
// Apply Iron Body visual effect
if (ironBodyActive) {
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 * self.speed;
self.y += dy / distance * self.speed;
// 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 / 3); // 3x faster
}
if (self.lastShot >= effectiveAttackSpeed && target) {
// Limit machine gun bullets to prevent performance issues
if (machineGunActive && playerBullets.length > 30) {
// Skip shooting if too many bullets exist
self.lastShot = Math.floor(effectiveAttackSpeed * 0.8); // Slight delay
} else {
self.shoot();
self.lastShot = 0;
}
}
}
};
self.shoot = function () {
var target = self.findNearestEnemy();
if (target) {
// Fire multiple bullets based on playerBulletCount
for (var b = 0; b < playerBulletCount; b++) {
var bullet;
// Create appropriate bullet type based on active power-ups
if (rocketLauncherActive) {
bullet = new RocketBullet();
} else if (machineGunActive) {
bullet = new MachineGunBullet();
} else if (healingNeedleActive) {
bullet = new HealingNeedleBullet();
} else {
bullet = new PlayerBullet();
}
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 bullet rotation to face movement direction
if (bullet.setRotation) {
bullet.setRotation(bullet.velocityX, bullet.velocityY);
}
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.1); // 90% 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);
var graphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
// Set rotation method for bullet orientation
self.setRotation = function (vx, vy) {
graphics.rotation = Math.atan2(vy, vx);
};
self.damage = 20;
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 (limit checks for performance)
var maxEnemyChecks = Math.min(20, enemies.length);
for (var i = 0; i < maxEnemyChecks; i++) {
var enemy = enemies[i];
if (self.intersects(enemy)) {
enemy.takeDamage(self.damage + (player ? player.damage : 0));
LK.getSound('enemyHit').play();
self.removeFromGame();
return;
}
}
// Check collision with green enemies (limit checks for performance)
var maxGreenChecks = Math.min(10, greenEnemies.length);
for (var g = 0; g < maxGreenChecks; g++) {
var greenEnemy = greenEnemies[g];
if (self.intersects(greenEnemy)) {
greenEnemy.takeDamage(self.damage + (player ? player.damage : 0));
LK.getSound('enemyHit').play();
self.removeFromGame();
return;
}
}
// Check collision with boss
if (currentBoss && self.intersects(currentBoss)) {
currentBoss.takeDamage(self.damage + (player ? player.damage : 0));
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 RocketBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('rocketBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 20;
// Set rotation method for bullet orientation
self.setRotation = function (vx, vy) {
graphics.rotation = Math.atan2(vy, vx);
};
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)) {
// 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 <= 200) {
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 <= 200) {
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 ? player.damage : 0));
}
// Create explosion effect
var explosion = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 400,
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();
}
});
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)) {
// 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 <= 200) {
splashEnemy.takeDamage(self.damage + (player ? player.damage : 0));
}
}
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 <= 200) {
splashGreen.takeDamage(self.damage + (player ? player.damage : 0));
}
}
// Create explosion effect
var explosion = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 400,
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();
}
});
LK.getSound('enemyHit').play();
self.removeFromGame();
return;
}
}
// Check collision with boss
if (currentBoss && self.intersects(currentBoss)) {
// Splash damage on boss
var explosion = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 400,
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 ? player.damage : 0));
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 SpawnerBoss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('spawnerBoss', {
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 * 4; // Stronger than regular boss
self.health = self.maxHealth;
self.speed = 0.6; // Slower than regular boss
var baseDamage = 25;
self.damage = baseDamage;
self.lastAttack = 0;
self.enemySpawnTimer = 0;
self.enemySpawnInterval = 300; // 5 seconds at 60 FPS
// Create boss health bar background
self.healthBarBg = LK.getAsset('enemyHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 250,
height: 35
});
self.healthBarBg.y = -90;
self.addChild(self.healthBarBg);
// Create boss health bar fill
self.healthBarFill = LK.getAsset('enemyHealthBarFill', {
anchorX: 0,
anchorY: 0.5,
width: 246,
height: 31
});
self.healthBarFill.x = -123;
self.healthBarFill.y = -90;
self.addChild(self.healthBarFill);
self.attackCooldown = 180; // Slower attack than regular boss
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 slowly
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;
}
// Enemy spawning mechanic
self.enemySpawnTimer++;
if (self.enemySpawnTimer >= self.enemySpawnInterval) {
var enemiesToSpawn = self.health <= self.maxHealth / 2 ? 5 : 1;
// Spawn enemies around the boss
for (var e = 0; e < enemiesToSpawn; e++) {
var enemy = new Enemy();
var angle = Math.PI * 2 / enemiesToSpawn * e;
var spawnDistance = 150;
enemy.x = self.x + Math.cos(angle) * spawnDistance;
enemy.y = self.y + Math.sin(angle) * spawnDistance;
// Keep enemies within screen bounds
enemy.x = Math.max(50, Math.min(1998, enemy.x));
enemy.y = Math.max(50, Math.min(2682, enemy.y));
enemies.push(enemy);
game.addChild(enemy);
}
self.enemySpawnTimer = 0;
}
// Attack player occasionally
self.lastAttack++;
if (self.lastAttack >= self.attackCooldown) {
// Simple bullet attack
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) {
var angle = Math.atan2(dy, dx);
bullet.velocityX = Math.cos(angle) * 4; // Slower bullets
bullet.velocityY = Math.sin(angle) * 4;
// Set bullet rotation to face movement direction
if (bullet.setRotation) {
bullet.setRotation(bullet.velocityX, bullet.velocityY);
}
}
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 = 246 * healthPercent;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Create massive explosion effect
for (var e = 0; e < 10; e++) {
var explosionCircle = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5,
width: 80 + e * 30,
height: 80 + e * 30,
alpha: 1.0 - e * 0.08,
tint: e === 0 ? 0xFF0000 : e === 1 ? 0xFF4400 : e === 2 ? 0xFF6600 : e === 3 ? 0xFF8800 : e === 4 ? 0xFFAA00 : 0xFFCC00
});
explosionCircle.x = self.x + (Math.random() - 0.5) * 100;
explosionCircle.y = self.y + (Math.random() - 0.5) * 100;
game.addChild(explosionCircle);
// Animate explosion
tween(explosionCircle, {
scaleX: 6 + e * 0.5,
scaleY: 6 + e * 0.5,
alpha: 0,
x: explosionCircle.x + (Math.random() - 0.5) * 250,
y: explosionCircle.y + (Math.random() - 0.5) * 250
}, {
duration: 1000 + e * 100,
easing: tween.easeOut,
onFinish: function onFinish() {
explosionCircle.destroy();
}
});
}
// Drop guaranteed coins
var numCoins = 15 + Math.floor(Math.random() * 11); // 15-25 coins
for (var i = 0; i < numCoins; i++) {
var coin = new Coin();
// Calculate coin value
var levelGroup = Math.floor((currentLevel - 1) / 5);
if (levelGroup === 0) {
coin.value = 10; // Levels 1-5
} else {
coin.value = 10 + levelGroup * 5;
}
coin.x = self.x + (Math.random() - 0.5) * 200;
coin.y = self.y + (Math.random() - 0.5) * 200;
coins.push(coin);
game.addChild(coin);
}
// Drop permanent bullet upgrade
var bulletUpgrade = new BulletUpgrade();
bulletUpgrade.x = self.x + (Math.random() - 0.5) * 120;
bulletUpgrade.y = self.y + (Math.random() - 0.5) * 120;
powerUps.push(bulletUpgrade);
game.addChild(bulletUpgrade);
// Drop guaranteed diamonds
for (var d = 0; d < 3; d++) {
var diamond = new Diamond();
var levelGroup = Math.floor((currentLevel - 1) / 5);
var coinValue;
if (levelGroup === 0) {
coinValue = 10;
} else {
coinValue = 10 + levelGroup * 5;
}
diamond.value = coinValue * 5;
diamond.x = self.x + (Math.random() - 0.5) * 150;
diamond.y = self.y + (Math.random() - 0.5) * 150;
diamonds.push(diamond);
game.addChild(diamond);
}
currentBoss = null;
self.destroy();
enemiesKilled = 0;
};
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
// Only store original speed if not already active
if (!speedActive || speedOriginalSpeed === 0) {
speedOriginalSpeed = player.speed;
}
player.speed = speedOriginalSpeed * 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 = 19;
var enemiesKilled = 0;
var enemiesPerLevel = 5;
var playerCoins = 50000;
var touchPosition = null;
// Player upgrade levels and costs - reset to zero for each new game
var healthUpgradeLevel = 50;
var attackSpeedUpgradeLevel = 50;
var attackPowerUpgradeLevel = 50;
var movementSpeedUpgradeLevel = 50;
var attackRangeUpgradeLevel = 50;
// 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;
// Boss fight green enemy spawning
var bossGreenEnemyTimer = 0;
var bossGreenEnemyInterval = 1800; // 30 seconds at 60 FPS
// UI elements
var levelText = new Text2('Level: 19', {
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 (longer and slimmer black rectangle) at top of screen
var playerHealthBarBg = LK.getAsset('enemyHealthBarBg', {
anchorX: 0.5,
anchorY: 0,
width: 600,
height: 60,
tint: 0x000000
});
playerHealthBarBg.x = 0;
playerHealthBarBg.y = 50;
LK.gui.top.addChild(playerHealthBarBg);
// Create player health bar fill (longer and slimmer green rectangle)
var playerHealthBarFill = LK.getAsset('enemyHealthBarFill', {
anchorX: 0,
anchorY: 0,
width: 592,
height: 52,
tint: 0x00ff00
});
playerHealthBarFill.x = -296;
playerHealthBarFill.y = 54;
LK.gui.top.addChild(playerHealthBarFill);
// Create player health text (smaller white text)
var playerHealthBarText = new Text2('30', {
size: 42,
fill: 0xffffff,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
playerHealthBarText.anchor.set(0.5, 0.5);
playerHealthBarText.x = 0;
playerHealthBarText.y = 87;
LK.gui.top.addChild(playerHealthBarText);
// Create coin display container below health bar
var coinDisplayContainer = new Container();
// Create spinning coin icon
var coinIcon = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
coinIcon.x = -30; // Position to the left of text
coinIcon.y = 0;
// Start continuous coin spinning animation
function startCoinSpin() {
tween(coinIcon, {
scaleX: -0.8
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinIcon, {
scaleX: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
startCoinSpin(); // Loop the animation
}
});
}
});
}
startCoinSpin();
var coinText = new Text2('50000', {
size: 40,
fill: 0xF1C40F
});
coinText.anchor.set(0, 0.5);
coinText.x = 10; // Position to the right of icon
coinText.y = 0;
coinDisplayContainer.addChild(coinIcon);
coinDisplayContainer.addChild(coinText);
// Position container below health bar
coinDisplayContainer.x = 0;
coinDisplayContainer.y = 160;
LK.gui.top.addChild(coinDisplayContainer);
// 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 = 50;
var attackPowerStatText = new Text2('Attack: 5', {
size: 35,
fill: 0xFF6B6B
});
attackPowerStatText.anchor.set(1, 0);
attackPowerStatText.x = -50;
attackPowerStatText.y = 90;
var attackSpeedStatText = new Text2('A.Speed: 120', {
size: 35,
fill: 0x4ECDC4
});
attackSpeedStatText.anchor.set(1, 0);
attackSpeedStatText.x = -50;
attackSpeedStatText.y = 130;
var movementSpeedStatText = new Text2('M.Speed: 2.0', {
size: 35,
fill: 0x45B7D1
});
movementSpeedStatText.anchor.set(1, 0);
movementSpeedStatText.x = -50;
movementSpeedStatText.y = 170;
var attackRangeStatText = new Text2('Range: 600', {
size: 35,
fill: 0x9B59B6
});
attackRangeStatText.anchor.set(1, 0);
attackRangeStatText.x = -50;
attackRangeStatText.y = 210;
// 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;
var wealthValueText = new Text2('', {
size: 35,
fill: 0xFFD700
});
wealthValueText.anchor.set(1, 0);
wealthValueText.x = -50;
wealthValueText.y = 250;
wealthValueText.visible = false;
var speedValueText = new Text2('', {
size: 35,
fill: 0x44ff44
});
speedValueText.anchor.set(1, 0);
speedValueText.x = -50;
speedValueText.y = 290;
speedValueText.visible = false;
var magnetValueText = new Text2('', {
size: 35,
fill: 0xaa44ff
});
magnetValueText.anchor.set(1, 0);
magnetValueText.x = -50;
magnetValueText.y = 330;
magnetValueText.visible = false;
var ironBodyValueText = new Text2('', {
size: 35,
fill: 0x888888
});
ironBodyValueText.anchor.set(1, 0);
ironBodyValueText.x = -50;
ironBodyValueText.y = 370;
ironBodyValueText.visible = false;
var healingNeedleValueText = new Text2('', {
size: 35,
fill: 0xff4488
});
healingNeedleValueText.anchor.set(1, 0);
healingNeedleValueText.x = -50;
healingNeedleValueText.y = 410;
healingNeedleValueText.visible = false;
var machineGunValueText = new Text2('', {
size: 35,
fill: 0xffff44
});
machineGunValueText.anchor.set(1, 0);
machineGunValueText.x = -50;
machineGunValueText.y = 450;
machineGunValueText.visible = false;
var rocketLauncherValueText = new Text2('', {
size: 35,
fill: 0xff4444
});
rocketLauncherValueText.anchor.set(1, 0);
rocketLauncherValueText.x = -50;
rocketLauncherValueText.y = 490;
rocketLauncherValueText.visible = false;
var freezeBombValueText = new Text2('', {
size: 35,
fill: 0x44aaff
});
freezeBombValueText.anchor.set(1, 0);
freezeBombValueText.x = -50;
freezeBombValueText.y = 530;
freezeBombValueText.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(wealthValueText);
LK.gui.topRight.addChild(speedValueText);
LK.gui.topRight.addChild(magnetValueText);
LK.gui.topRight.addChild(ironBodyValueText);
LK.gui.topRight.addChild(healingNeedleValueText);
LK.gui.topRight.addChild(machineGunValueText);
LK.gui.topRight.addChild(rocketLauncherValueText);
LK.gui.topRight.addChild(freezeBombValueText);
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 +10', 'Attack Power +10', 'Move Speed +0.8', 'Range +100'];
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;
// Apply high stats based on upgrade levels
player.maxHealth = 50 + healthUpgradeLevel * 15; // Base 50 + 15 per level
player.health = player.maxHealth;
player.damage = 5 + attackPowerUpgradeLevel * 10; // Base 5 + 10 per level
player.speed = 2.2 + movementSpeedUpgradeLevel * 0.8; // Base 2.2 + 0.8 per level
player.attackRange = 300 + attackRangeUpgradeLevel * 50; // Base 300 + 50 per level
// Calculate attack speed (higher upgrade level = faster attack)
var baseAttackSpeed = 103;
var displayValue = 120 + attackSpeedUpgradeLevel * 10; // Start at 120, add 10 per level
player.attackSpeed = 400; // Set fixed attack speed to 400
// 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;
// Give player multiple bullets
playerBulletCount = 1; // Single bullet only
game.addChild(player);
// Spawn initial enemies
function spawnEnemies() {
// No enemies during boss rounds (every 10 levels: 10, 20, 30, etc.)
if (currentLevel % 10 === 0) {
return;
}
// Calculate enemy count: starts at level 1 with 1 enemy, adds 1 per level
var enemiesToSpawn = currentLevel;
remainingEnemies = enemiesToSpawn;
remainingText.setText('Enemies: ' + remainingEnemies);
// Guarantee 30% chance to spawn exactly one green enemy per level (limited to 1 per level)
var shouldSpawnGreen = Math.random() < 0.3;
var greenEnemySpawned = false;
for (var i = 0; i < enemiesToSpawn; i++) {
// Spawn green enemy on first iteration if we should spawn one and haven't yet
var isGreen = shouldSpawnGreen && !greenEnemySpawned;
if (isGreen) {
greenEnemySpawned = true; // Mark that we've spawned our one green enemy for this level
}
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() {
// Spawn different boss types based on level
if (currentLevel === 20) {
currentBoss = new SpawnerBoss();
} else {
currentBoss = new Boss();
}
currentBoss.x = 1024;
currentBoss.y = 200;
game.addChild(currentBoss);
// Reset boss green enemy timer
bossGreenEnemyTimer = 0;
}
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;
}
// Hide health packs when shop opens
for (var i = 0; i < healthPacks.length; i++) {
healthPacks[i].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;
}
// Show health packs when shop closes
for (var i = 0; i < healthPacks.length; i++) {
healthPacks[i].visible = true;
}
// Resume all game objects
for (var i = 0; i < enemies.length; i++) {
enemies[i].visible = true;
}
// Check if current level is a boss level and spawn boss instead of regular enemies
if (currentLevel % 10 === 0) {
// Spawn boss at boss levels
spawnBoss();
} else {
// Spawn regular enemies for non-boss levels
spawnEnemies();
}
}
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();
}
}
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(playerCoins.toString());
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;
// Calculate new attack speed to increase display by exactly 10
var currentDisplayValue = Math.round(3600 / player.attackSpeed);
var newDisplayValue = currentDisplayValue + 10;
player.attackSpeed = Math.round(3600 / newDisplayValue);
player.attackSpeed = Math.max(5, player.attackSpeed);
break;
case 2:
// Attack Power upgrade
attackPowerUpgradeLevel++;
storage.attackPowerUpgradeLevel = attackPowerUpgradeLevel;
player.damage += 10;
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 += 50;
// 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: ' + Math.round(3600 / 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 = 592 * healthPercent;
// Health bar color: green when above 20%, red when 20% or below
if (healthPercent <= 0.2) {
playerHealthBarFill.tint = 0xff0000; // Red when health is 20% or less
} else {
playerHealthBarFill.tint = 0x00ff00; // Green when health is above 20%
}
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;
rocketLauncherValueText.visible = false;
} else {
var remainingTime = Math.ceil((rocketLauncherEndTime - LK.ticks) / 60);
rocketTimerText.setText('Rocket: ' + remainingTime + 's');
rocketTimerText.visible = true;
rocketLauncherValueText.setText('Splash Damage');
rocketLauncherValueText.visible = true;
}
} else {
rocketTimerText.visible = false;
rocketLauncherValueText.visible = false;
}
if (freezeEffectActive) {
if (LK.ticks >= freezeEffectEndTime) {
freezeEffectActive = false;
freezeTimerText.visible = false;
freezeBombValueText.visible = false;
} else {
var remainingTime = Math.ceil((freezeEffectEndTime - LK.ticks) / 60);
freezeTimerText.setText('Freeze: ' + remainingTime + 's');
freezeTimerText.visible = true;
freezeBombValueText.setText('Slow Enemies 50%');
freezeBombValueText.visible = true;
}
} else {
freezeTimerText.visible = false;
freezeBombValueText.visible = false;
}
if (machineGunActive) {
if (LK.ticks >= machineGunEndTime) {
machineGunActive = false;
machineGunTimerText.visible = false;
machineGunValueText.visible = false;
} else {
var remainingTime = Math.ceil((machineGunEndTime - LK.ticks) / 60);
machineGunTimerText.setText('Machine Gun: ' + remainingTime + 's');
machineGunTimerText.visible = true;
machineGunValueText.setText('5x Fire Rate');
machineGunValueText.visible = true;
}
} else {
machineGunTimerText.visible = false;
machineGunValueText.visible = false;
}
if (magnetActive) {
if (LK.ticks >= magnetEndTime) {
magnetActive = false;
magnetTimerText.visible = false;
magnetValueText.visible = false;
} else {
var remainingTime = Math.ceil((magnetEndTime - LK.ticks) / 60);
magnetTimerText.setText('Magnet: ' + remainingTime + 's');
magnetTimerText.visible = true;
magnetValueText.setText('Attract Items');
magnetValueText.visible = true;
}
} else {
magnetTimerText.visible = false;
magnetValueText.visible = false;
}
if (speedActive) {
if (LK.ticks >= speedEndTime) {
speedActive = false;
if (player) {
player.speed = speedOriginalSpeed;
}
speedTimerText.visible = false;
speedValueText.visible = false;
} else {
var remainingTime = Math.ceil((speedEndTime - LK.ticks) / 60);
speedTimerText.setText('Speed: ' + remainingTime + 's');
speedTimerText.visible = true;
speedValueText.setText('2x Move Speed + Fire Rate');
speedValueText.visible = true;
}
} else {
speedTimerText.visible = false;
speedValueText.visible = false;
}
if (wealthActive) {
if (LK.ticks >= wealthEndTime) {
wealthActive = false;
wealthTimerText.visible = false;
wealthValueText.visible = false;
} else {
var remainingTime = Math.ceil((wealthEndTime - LK.ticks) / 60);
wealthTimerText.setText('Wealth: ' + remainingTime + 's');
wealthTimerText.visible = true;
wealthValueText.setText('2x Coin Value + 30% Diamond Drop');
wealthValueText.visible = true;
}
} else {
wealthTimerText.visible = false;
wealthValueText.visible = false;
}
if (ironBodyActive) {
if (LK.ticks >= ironBodyEndTime) {
ironBodyActive = false;
ironBodyTimerText.visible = false;
ironBodyValueText.visible = false;
} else {
var remainingTime = Math.ceil((ironBodyEndTime - LK.ticks) / 60);
ironBodyTimerText.setText('Iron Body: ' + remainingTime + 's');
ironBodyTimerText.visible = true;
ironBodyValueText.setText('90% Dmg Reduction + 3x Push Back');
ironBodyValueText.visible = true;
}
} else {
ironBodyTimerText.visible = false;
ironBodyValueText.visible = false;
}
if (healingNeedleActive) {
if (LK.ticks >= healingNeedleEndTime) {
healingNeedleActive = false;
healingNeedleTimerText.visible = false;
healingNeedleValueText.visible = false;
} else {
var remainingTime = Math.ceil((healingNeedleEndTime - LK.ticks) / 60);
healingNeedleTimerText.setText('Healing: ' + remainingTime + 's');
healingNeedleTimerText.visible = true;
healingNeedleValueText.setText('Heal on Hit');
healingNeedleValueText.visible = true;
}
} else {
healingNeedleTimerText.visible = false;
healingNeedleValueText.visible = false;
}
// Spawn green enemies during boss fights every 1 minute
if (gameState === 'playing' && currentBoss) {
bossGreenEnemyTimer++;
if (bossGreenEnemyTimer >= bossGreenEnemyInterval) {
// Spawn one green enemy at random location on the map
var greenEnemy = new GreenEnemy();
var validPosition = false;
var attempts = 0;
// Try to find non-overlapping position anywhere on the map
while (!validPosition && attempts < 50) {
// Spawn at random location on the map
greenEnemy.x = Math.random() * 2048;
greenEnemy.y = Math.random() * 2732;
// Check if position is far enough from player and boss
validPosition = true;
if (player) {
var dx = greenEnemy.x - player.x;
var dy = greenEnemy.y - player.y;
var distanceToPlayer = Math.sqrt(dx * dx + dy * dy);
if (distanceToPlayer < 200) {
validPosition = false;
}
}
if (currentBoss && validPosition) {
var dx = greenEnemy.x - currentBoss.x;
var dy = greenEnemy.y - currentBoss.y;
var distanceToBoss = Math.sqrt(dx * dx + dy * dy);
if (distanceToBoss < 200) {
validPosition = false;
}
}
// Check if position overlaps with existing enemies
for (var e = 0; e < enemies.length && validPosition; e++) {
var dx = greenEnemy.x - enemies[e].x;
var dy = greenEnemy.y - enemies[e].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
validPosition = false;
}
}
for (var g = 0; g < greenEnemies.length && validPosition; g++) {
var dx = greenEnemy.x - greenEnemies[g].x;
var dy = greenEnemy.y - greenEnemies[g].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
validPosition = false;
}
}
attempts++;
}
greenEnemies.push(greenEnemy);
game.addChild(greenEnemy);
// Reset timer for next spawn
bossGreenEnemyTimer = 0;
}
}
// Clean up excess bullets during machine gun usage to prevent performance issues
if (machineGunActive && playerBullets.length > 40) {
// Remove oldest bullets that are off-screen or furthest from enemies
var bulletsToRemove = [];
for (var i = 0; i < playerBullets.length; i++) {
var bullet = playerBullets[i];
// Remove bullets that are far off-screen
if (bullet.x < -200 || bullet.x > 2248 || bullet.y < -200 || bullet.y > 2932) {
bulletsToRemove.push(i);
}
}
// Remove bullets starting from the end to avoid index issues
for (var r = bulletsToRemove.length - 1; r >= 0; r--) {
var bulletIndex = bulletsToRemove[r];
if (playerBullets[bulletIndex]) {
playerBullets[bulletIndex].destroy();
playerBullets.splice(bulletIndex, 1);
}
}
}
// Check if all enemies are defeated and no boss exists
if (gameState === 'playing' && enemies.length === 0 && greenEnemies.length === 0 && !currentBoss) {
// Progress to next level first
currentLevel++;
levelText.setText('Level: ' + currentLevel);
enemiesKilled = 0;
// Check win condition at level 200
if (currentLevel > 200) {
LK.showYouWin();
return;
}
// Check if current level requires shop or boss
if (currentLevel % 10 === 0) {
// Boss levels (10, 20, 30, etc.) - show shop first, then boss
showShop();
} else if (currentLevel % 5 === 0) {
// Non-boss multiples of 5 (5, 15, 25, etc.) - show shop
showShop();
} else {
// Regular levels - spawn enemies
spawnEnemies();
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -3050,15 +3050,15 @@
player.attackRange = 300 + attackRangeUpgradeLevel * 50; // Base 300 + 50 per level
// Calculate attack speed (higher upgrade level = faster attack)
var baseAttackSpeed = 103;
var displayValue = 120 + attackSpeedUpgradeLevel * 10; // Start at 120, add 10 per level
-player.attackSpeed = Math.max(5, Math.round(3600 / displayValue));
+player.attackSpeed = 400; // Set fixed attack speed to 400
// 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;
// Give player multiple bullets
-playerBulletCount = Math.min(10, 1 + Math.floor(currentLevel / 3)); // More bullets at higher levels
+playerBulletCount = 1; // Single bullet only
game.addChild(player);
// Spawn initial enemies
function spawnEnemies() {
// No enemies during boss rounds (every 10 levels: 10, 20, 30, etc.)
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