User prompt
why can't I move after level 2? fix it
User prompt
enemies other than bosses and big enemies drop 1 xp
User prompt
make sound when ı take healt or speed or shoot
User prompt
have a boss fight every 10 levels, no other enemies around the boss when it comes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
have big and small enemies, big enemies die in 2 hits or 3 hits depending on their size, have a health bar on them.
User prompt
Please fix the bug: 'TypeError: enemies[i].update is not a function' in or related to this line: 'enemies[i].update();' Line Number: 682
User prompt
make different enemies and as I get stronger, they come in droves
User prompt
when ı level up, enemies faster
User prompt
max level 50
User prompt
not teleport to where I click, just move when I drag
Code edit (1 edits merged)
Please save this source code
User prompt
Auto Shooter Evolution
Initial prompt
When a man who shoots automatically collects the new stats that appear on the screen, he gains stats such as rate of fire, new shooting mode, flamethrower, double shot, new weapon. Every time you kill an enemy, points drop from enemies, allowing you to level up. Each time he levels up he chooses one of 3 options, extra health, speed, new weapon or different features.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BossHealthBar = Container.expand(function (boss) { var self = Container.call(this); self.boss = boss; self.barWidth = 600; self.barHeight = 30; // Background bar self.background = LK.getAsset('enemy', { width: self.barWidth, height: self.barHeight, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); // Health bar self.foreground = LK.getAsset('boss', { width: self.barWidth, height: self.barHeight, anchorX: 0.5, anchorY: 0.5, tint: 0xFF4444 }); // Boss name text self.nameText = new Text2('BOSS', { size: 32, fill: 0xFFFFFF }); self.nameText.anchor.set(0.5, 0.5); self.nameText.x = 0; self.nameText.y = -50; // Health text self.healthText = new Text2('', { size: 24, fill: 0xFFFFFF }); self.healthText.anchor.set(0.5, 0.5); self.healthText.x = 0; self.healthText.y = 50; self.addChild(self.background); self.addChild(self.foreground); self.addChild(self.nameText); self.addChild(self.healthText); self.update = function () { if (!self.boss || self.boss.health <= 0) { self.removeSelf(); return; } // Update health display var healthPercent = self.boss.health / self.boss.maxHealth; self.foreground.width = self.barWidth * healthPercent; // Update health text self.healthText.setText(self.boss.health + ' / ' + self.boss.maxHealth); // Position at top center of screen self.x = 1024; self.y = 150; }; self.removeSelf = function () { self.destroy(); }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; var baseDamage = player ? player.damage || 25 : 25; self.damage = baseDamage; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.removeSelf(); } for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (self.intersects(enemy)) { enemy.takeDamage(self.damage); self.removeSelf(); break; } } }; self.removeSelf = function () { var index = bullets.indexOf(self); if (index !== -1) { bullets.splice(index, 1); } self.destroy(); }; return self; }); var DamageBoostItem = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('damageBoostItem', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF2222 }); self.lifeTime = 0; self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer than normal) self.update = function () { self.lifeTime++; // Fade out and remove after lifetime expires if (self.lifeTime >= self.maxLifeTime) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { self.removeSelf(); } }); return; } // Check for player collection var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { self.applyEffect(); self.removeSelf(); } }; self.applyEffect = function () { // Activate damage boost for 15 seconds player.damageBoostActive = true; player.damageBoostDuration = 900; // 15 seconds at 60fps player.originalDamage = player.damage || 25; player.damage = Math.floor(player.originalDamage * 1.3); // 30% more damage // Visual effect tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut }); LK.getSound('pickup').play(); }; self.removeSelf = function () { var index = damageBoostItems.indexOf(self); if (index !== -1) { damageBoostItems.splice(index, 1); } self.destroy(); }; return self; }); var EnemyBase = Container.expand(function (assetType, health, speed, damage, xpValue) { var self = Container.call(this); var enemyGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); self.health = health || 20; self.maxHealth = self.health; self.speed = speed || 1; self.damage = damage || 10; self.xpValue = xpValue || 3; self.lastDamageTime = 0; self.baseSpeed = self.speed; self.assetType = assetType; self.healthBar = null; self.needsHealthBar = health > 50; // Big enemies (TankEnemy, ShooterEnemy) get health bars self.update = function () { self.updateMovement(); self.checkPlayerCollision(); if (self.healthBar) { self.healthBar.update(); } }; self.updateMovement = function () { 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 * self.speed; self.y += dy / distance * self.speed; } }; self.checkPlayerCollision = function () { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50 && LK.ticks - self.lastDamageTime > 30) { player.takeDamage(self.damage); self.lastDamageTime = LK.ticks; } }; self.takeDamage = function (damage) { self.health -= damage; // Create health bar if this enemy needs one and doesn't have one yet if (self.needsHealthBar && !self.healthBar) { var barSize = enemyHealthBarSizes[self.assetType] || { width: 40, height: 6 }; self.healthBar = new EnemyHealthBar(self, barSize.width, barSize.height); game.addChild(self.healthBar); } if (self.health <= 0) { self.die(); } }; self.die = function () { // Death effect animation tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0, tint: 0xff4444, rotation: Math.PI * 0.5 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Clean up health bar if it exists if (self.healthBar) { self.healthBar.removeSelf(); self.healthBar = null; } for (var i = 0; i < self.xpValue; i++) { var xpOrb = new XPOrb(); xpOrb.x = self.x + (Math.random() - 0.5) * 50; xpOrb.y = self.y + (Math.random() - 0.5) * 50; xpOrbs.push(xpOrb); game.addChild(xpOrb); } var index = enemies.indexOf(self); if (index !== -1) { enemies.splice(index, 1); } self.destroy(); } }); }; return self; }); var TankEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'tankEnemy', 250, 0.5, 20, 8); // High health (10 hits), slow speed, high damage self.needsHealthBar = true; // Tank enemies get health bars due to high health return self; }); var SummonerEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'summonerEnemy', 60, 0.5, 10, 4); self.summonTimer = 0; self.summonRate = 180; // 3 seconds self.maxSummons = 3; self.currentSummons = 0; self.shootTimer = 0; self.updateMovement = function () { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Keep far distance from player and shoot if (distance > 400) { if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else if (distance < 300) { // Move away if too close if (distance > 0) { self.x -= dx / distance * self.speed; self.y -= dy / distance * self.speed; } } else { // In optimal range - shoot at player self.shootTimer++; if (self.shootTimer >= 90) { // Shoot every 1.5 seconds self.shootAtPlayer(); self.shootTimer = 0; } } // Summon minions self.summonTimer++; if (self.summonTimer >= self.summonRate && self.currentSummons < self.maxSummons) { self.summonMinion(); self.summonTimer = 0; } }; self.summonMinion = function () { var minion = new BasicEnemy(); minion.x = self.x + (Math.random() - 0.5) * 100; minion.y = self.y + (Math.random() - 0.5) * 100; minion.summoner = self; // Reference to summoner enemies.push(minion); game.addChild(minion); self.currentSummons++; // Visual summoning effect tween(minion, { scaleX: 0.1, scaleY: 0.1, alpha: 0 }, { duration: 0 }); tween(minion, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 500, easing: tween.bounceOut }); }; self.shootAtPlayer = function () { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { bullet.velocityX = dx / distance * 5; bullet.velocityY = dy / distance * 5; enemyBullets.push(bullet); game.addChild(bullet); } // Visual shooting effect tween(self, { tint: 0xff6600 }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 200 }); } }); }; self.die = function () { // Kill all summoned minions first for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i].summoner === self) { enemies[i].die(); } } // Death effect animation tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0, tint: 0xff4444, rotation: Math.PI * 0.5 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Clean up health bar if it exists if (self.healthBar) { self.healthBar.removeSelf(); self.healthBar = null; } for (var i = 0; i < self.xpValue; i++) { var xpOrb = new XPOrb(); xpOrb.x = self.x + (Math.random() - 0.5) * 50; xpOrb.y = self.y + (Math.random() - 0.5) * 50; xpOrbs.push(xpOrb); game.addChild(xpOrb); } var index = enemies.indexOf(self); if (index !== -1) { enemies.splice(index, 1); } self.destroy(); } }); }; return self; }); var StealthEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'enemy', 25, 2, 15, 1); self.stealthTimer = 0; self.stealthDuration = 120; // 2 seconds invisible self.visibleDuration = 180; // 3 seconds visible self.isStealthed = false; self.update = function () { self.updateMovement(); self.checkPlayerCollision(); self.updateStealth(); if (self.healthBar) { self.healthBar.update(); } }; self.updateStealth = function () { self.stealthTimer++; if (self.isStealthed) { if (self.stealthTimer >= self.stealthDuration) { self.becomeVisible(); self.stealthTimer = 0; } } else { if (self.stealthTimer >= self.visibleDuration) { self.becomeStealth(); self.stealthTimer = 0; } } }; self.becomeStealth = function () { self.isStealthed = true; tween(self, { alpha: 0.2 }, { duration: 300 }); // Increase speed while stealthed self.speed = self.baseSpeed * 1.5; }; self.becomeVisible = function () { self.isStealthed = false; tween(self, { alpha: 1 }, { duration: 300 }); // Reset speed self.speed = self.baseSpeed; }; self.takeDamage = function (damage) { // Take less damage while stealthed var actualDamage = self.isStealthed ? damage * 0.5 : damage; self.health -= actualDamage; // Become visible when hit if (self.isStealthed) { self.becomeVisible(); self.stealthTimer = 0; } if (self.needsHealthBar && !self.healthBar) { var barSize = enemyHealthBarSizes[self.assetType] || { width: 40, height: 6 }; self.healthBar = new EnemyHealthBar(self, barSize.width, barSize.height); game.addChild(self.healthBar); } if (self.health <= 0) { self.die(); } }; return self; }); var ShooterEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'shooterEnemy', 75, 0.8, 12, 5); // Increased health to 75 (3 hits to kill) self.shootTimer = 0; self.shootRate = 120; self.updateMovement = function () { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Attack from long range instead of close contact if (distance > 400) { if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else if (distance < 300) { // Move away if too close if (distance > 0) { self.x -= dx / distance * self.speed * 0.5; self.y -= dy / distance * self.speed * 0.5; } } else { // In optimal range - shoot at player self.shootTimer++; if (self.shootTimer >= self.shootRate) { self.shootAtPlayer(); self.shootTimer = 0; } } }; self.shootAtPlayer = function () { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.damage = 0.91; // Reduced damage by 35% from 1.4 to 0.91 (1.4 * 0.65 = 0.91) var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { bullet.velocityX = dx / distance * 6; bullet.velocityY = dy / distance * 6; enemyBullets.push(bullet); game.addChild(bullet); } }; return self; }); var FastEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'fastEnemy', 10, 2.5, 8, 1); return self; }); var ExplodingEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'fastEnemy', 30, 1.5, 25, 1); self.explosionRange = 120; self.hasExploded = false; self.checkPlayerCollision = function () { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.explosionRange && !self.hasExploded) { self.explode(); } else if (distance < 50 && LK.ticks - self.lastDamageTime > 30) { player.takeDamage(self.damage); self.lastDamageTime = LK.ticks; } }; self.explode = function () { self.hasExploded = true; // Visual explosion effect tween(self, { scaleX: 3, scaleY: 3, alpha: 0, tint: 0xff4400 }, { duration: 400, easing: tween.easeOut }); // Damage player if in range var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.explosionRange) { player.takeDamage(self.damage * 2); } // Remove after explosion LK.setTimeout(function () { self.die(); }, 400); }; self.takeDamage = function (damage) { self.health -= damage; if (self.needsHealthBar && !self.healthBar) { var barSize = enemyHealthBarSizes[self.assetType] || { width: 40, height: 6 }; self.healthBar = new EnemyHealthBar(self, barSize.width, barSize.height); game.addChild(self.healthBar); } if (self.health <= 0) { self.explode(); // Explode when killed } }; return self; }); var Boss2 = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'boss2', 6000, 1.0, 30, 60); // Increased damage from 25 to 30 (20% increase) // Boss 2 has more health and damage than Boss 1 self.maxHealth = 6000 + Math.floor((player.level - 1) / 10) * 2400; self.health = self.maxHealth; self.needsHealthBar = true; self.attackTimer = 0; self.attackPhase = 0; self.isCharging = false; self.chargeTarget = { x: 0, y: 0 }; self.teleportTimer = 0; self.isTeleporting = false; // Boss entrance animation self.alpha = 0; tween(self, { alpha: 1 }, { duration: 2000, easing: tween.easeOut }); tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 1000, easing: tween.bounceOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 500 }); } }); self.updateMovement = function () { if (self.isCharging || self.isTeleporting) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // More aggressive movement than Boss 1 if (distance > 250) { if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else if (distance < 150) { if (distance > 0) { self.x -= dx / distance * self.speed * 0.7; self.y -= dy / distance * self.speed * 0.7; } } }; self.update = function () { self.updateMovement(); self.checkPlayerCollision(); self.updateAttacks(); self.updateTeleport(); if (self.healthBar) { self.healthBar.update(); } }; self.updateTeleport = function () { // Teleport every 8 seconds self.teleportTimer++; if (self.teleportTimer >= 480 && !self.isTeleporting) { self.performTeleport(); self.teleportTimer = 0; } }; self.performTeleport = function () { self.isTeleporting = true; // Fade out tween(self, { alpha: 0.2, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { // Teleport to random position self.x = 300 + Math.random() * 1448; self.y = 300 + Math.random() * 1732; // Fade back in tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, onFinish: function onFinish() { self.isTeleporting = false; } }); } }); }; self.updateAttacks = function () { self.attackTimer++; // Attack every 1.5 seconds if (self.attackTimer >= 90) { self.attackPhase = (self.attackPhase + 1) % 4; self.performAttack(); self.attackTimer = 0; } }; self.performAttack = function () { switch (self.attackPhase) { case 0: self.crossAttack(); break; case 1: self.chargeAttack(); break; case 2: self.circularAttack(); break; case 3: self.rapidFireAttack(); break; } }; self.crossAttack = function () { // Fire bullets in cross pattern var directions = [{ x: 1, y: 0 }, { x: -1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: -1 }, { x: 0.7, y: 0.7 }, { x: -0.7, y: 0.7 }, { x: 0.7, y: -0.7 }, { x: -0.7, y: -0.7 }]; for (var i = 0; i < directions.length; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.velocityX = directions[i].x * 6; bullet.velocityY = directions[i].y * 6; bullet.damage = 10; enemyBullets.push(bullet); game.addChild(bullet); } // Visual effect tween(self, { tint: 0x4444ff }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 200 }); } }); }; self.chargeAttack = function () { // Similar to Boss 1 but faster self.isCharging = true; self.chargeTarget.x = player.x; self.chargeTarget.y = player.y; tween(self, { tint: 0xff00ff, scaleX: 1.4, scaleY: 1.4 }, { duration: 150, onFinish: function onFinish() { tween(self, { x: self.chargeTarget.x, y: self.chargeTarget.y }, { duration: 250, easing: tween.easeOut, onFinish: function onFinish() { self.isCharging = false; tween(self, { tint: 0xffffff, scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } }); }; self.circularAttack = function () { // Fire bullets in expanding circle for (var i = 0; i < 16; i++) { var angle = i / 16 * Math.PI * 2; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.velocityX = Math.cos(angle) * 5; bullet.velocityY = Math.sin(angle) * 5; bullet.damage = 8; enemyBullets.push(bullet); game.addChild(bullet); } }; self.rapidFireAttack = function () { // Fire multiple bullets rapidly at player for (var i = 0; i < 5; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.damage = 6; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var spread = (i - 2) * 0.2; if (distance > 0) { var angle = Math.atan2(dy, dx) + spread; bullet.velocityX = Math.cos(angle) * 9; bullet.velocityY = Math.sin(angle) * 9; enemyBullets.push(bullet); game.addChild(bullet); } } }; self.die = function () { // Boss death animation tween(self, { alpha: 0, scaleX: 2.5, scaleY: 2.5, rotation: Math.PI * 1.5 }, { duration: 2500, easing: tween.easeOut, onFinish: function onFinish() { // Clean up health bar if it exists if (self.healthBar) { self.healthBar.removeSelf(); self.healthBar = null; } // Drop reduced XP (88% less total) for (var i = 0; i < Math.floor(self.xpValue * 0.12); i++) { var xpOrb = new XPOrb(); xpOrb.x = self.x + (Math.random() - 0.5) * 150; xpOrb.y = self.y + (Math.random() - 0.5) * 150; xpOrbs.push(xpOrb); game.addChild(xpOrb); } // Drop even fewer items - 0.2 chance for range item if (Math.random() < 0.2) { var fireRangeItem = new FireRangeItem(); fireRangeItem.x = self.x + (Math.random() - 0.5) * 150; fireRangeItem.y = self.y + (Math.random() - 0.5) * 150; fireRangeItems.push(fireRangeItem); game.addChild(fireRangeItem); } // Drop 40% more fire rate items - 0.28 chance for fire rate item (0.2 * 1.4) if (Math.random() < 0.28) { var fireRateItem = new FireRateItem(); fireRateItem.x = self.x + (Math.random() - 0.5) * 150; fireRateItem.y = self.y + (Math.random() - 0.5) * 150; fireRateItems.push(fireRateItem); game.addChild(fireRateItem); } // Drop even fewer items - 0.2 chance for health item if (Math.random() < 0.2) { var healthItem = new HealthItem(); healthItem.x = self.x + (Math.random() - 0.5) * 150; healthItem.y = self.y + (Math.random() - 0.5) * 150; healthItems.push(healthItem); game.addChild(healthItem); } var index = enemies.indexOf(self); if (index !== -1) { enemies.splice(index, 1); } // Clean up boss health bar if (bossHealthBar) { bossHealthBar.removeSelf(); bossHealthBar = null; } // End boss fight isBossFight = false; // Make player 40% stronger after boss defeat player.damage = (player.damage || 25) * 1.4; // 40% more damage player.fireRate = Math.max(5, Math.floor(player.fireRate * 0.7)); // 30% faster fire rate (multiplicative with 40% boost) player.speed = player.speed * 1.4; // 40% faster movement self.destroy(); } }); }; return self; }); var Boss = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'boss', 2800, 0.8, 24, 50); // Increased damage from 20 to 24 (20% increase) // Reduced health by 68% total (20% + 40% + 8%) and damage by 20% self.maxHealth = 2800 + Math.floor((player.level - 1) / 10) * 1120; // Reduced scaling by 68% total self.health = self.maxHealth; self.needsHealthBar = true; self.attackTimer = 0; self.attackPhase = 0; self.isCharging = false; self.chargeTarget = { x: 0, y: 0 }; // Boss entrance animation self.alpha = 0; tween(self, { alpha: 1 }, { duration: 2000, easing: tween.easeOut }); tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 1000, easing: tween.bounceOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 500 }); } }); self.updateMovement = function () { if (self.isCharging) return; // Don't move normally when charging var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Keep distance from player but still move towards them slowly if (distance > 300) { if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else if (distance < 200) { // Move away if too close if (distance > 0) { self.x -= dx / distance * self.speed * 0.5; self.y -= dy / distance * self.speed * 0.5; } } }; self.update = function () { self.updateMovement(); self.checkPlayerCollision(); self.updateAttacks(); if (self.healthBar) { self.healthBar.update(); } }; self.updateAttacks = function () { self.attackTimer++; // Reduced attack frequency by 50% total - every 1.67 seconds instead of 1.07 seconds if (self.attackTimer >= 100) { // 1.67 seconds (83 * 1.2 = 100 for 20% additional reduction) self.attackPhase = (self.attackPhase + 1) % 3; self.performAttack(); self.attackTimer = 0; } }; self.performAttack = function () { switch (self.attackPhase) { case 0: self.spiralAttack(); break; case 1: self.chargeAttack(); break; case 2: self.burstAttack(); break; } }; self.spiralAttack = function () { // Fire 30% fewer bullets in a spiral pattern (30% less than 11 = 8 bullets) for (var i = 0; i < 8; i++) { var angle = i / 8 * Math.PI * 2 + LK.ticks * 0.15; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.velocityX = Math.cos(angle) * 7; bullet.velocityY = Math.sin(angle) * 7; enemyBullets.push(bullet); game.addChild(bullet); } // Visual effect tween(self, { tint: 0xff4444 }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 200 }); } }); }; self.chargeAttack = function () { // Charge towards player self.isCharging = true; self.chargeTarget.x = player.x; self.chargeTarget.y = player.y; // Shorter warning time, faster charge tween(self, { tint: 0xff0000, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, onFinish: function onFinish() { // Perform the charge much faster tween(self, { x: self.chargeTarget.x, y: self.chargeTarget.y }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.isCharging = false; tween(self, { tint: 0xffffff, scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } }); }; self.burstAttack = function () { // Fire 30% fewer bullets towards player in multiple bursts (30% less than 17 = 12 bullets) for (var i = 0; i < 12; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.damage = 12; // Reduced damage by 50% (from 25 to 12) var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var spread = (i - 6) * 0.15; // Adjusted spread center for 12 bullets if (distance > 0) { var angle = Math.atan2(dy, dx) + spread; bullet.velocityX = Math.cos(angle) * 8; bullet.velocityY = Math.sin(angle) * 8; enemyBullets.push(bullet); game.addChild(bullet); } } }; self.die = function () { // Boss death animation tween(self, { alpha: 0, scaleX: 2, scaleY: 2, rotation: Math.PI }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { // Clean up health bar if it exists if (self.healthBar) { self.healthBar.removeSelf(); self.healthBar = null; } // Drop reduced XP (88% less total) for (var i = 0; i < Math.floor(self.xpValue * 0.12); i++) { var xpOrb = new XPOrb(); xpOrb.x = self.x + (Math.random() - 0.5) * 100; xpOrb.y = self.y + (Math.random() - 0.5) * 100; xpOrbs.push(xpOrb); game.addChild(xpOrb); } // Drop even fewer items - 0.2 chance for range item if (Math.random() < 0.2) { var fireRangeItem = new FireRangeItem(); fireRangeItem.x = self.x + (Math.random() - 0.5) * 150; fireRangeItem.y = self.y + (Math.random() - 0.5) * 150; fireRangeItems.push(fireRangeItem); game.addChild(fireRangeItem); } // Drop 40% more fire rate items - 0.28 chance for fire rate item (0.2 * 1.4) if (Math.random() < 0.28) { var fireRateItem = new FireRateItem(); fireRateItem.x = self.x + (Math.random() - 0.5) * 150; fireRateItem.y = self.y + (Math.random() - 0.5) * 150; fireRateItems.push(fireRateItem); game.addChild(fireRateItem); } // Drop even fewer items - 0.2 chance for health item if (Math.random() < 0.2) { var healthItem = new HealthItem(); healthItem.x = self.x + (Math.random() - 0.5) * 150; healthItem.y = self.y + (Math.random() - 0.5) * 150; healthItems.push(healthItem); game.addChild(healthItem); } var index = enemies.indexOf(self); if (index !== -1) { enemies.splice(index, 1); } // Clean up boss health bar if (bossHealthBar) { bossHealthBar.removeSelf(); bossHealthBar = null; } // End boss fight isBossFight = false; // Mark first boss as defeated for enemy spawn rate reduction if (!firstBossDefeated) { firstBossDefeated = true; // Make player 40% stronger after first boss defeat player.damage = (player.damage || 25) * 1.4; // 40% more damage player.fireRate = Math.max(5, Math.floor(player.fireRate * 0.7)); // 30% faster fire rate (multiplicative with 40% boost) player.speed = player.speed * 1.4; // 40% faster movement } self.destroy(); } }); }; return self; }); var BasicEnemy = EnemyBase.expand(function () { var self = EnemyBase.call(this, 'enemy', 20, 1, 10, 1); return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0xff0000 }); self.velocityX = 0; self.velocityY = 0; self.damage = 7; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.removeSelf(); } var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 30) { player.takeDamage(self.damage); self.removeSelf(); } }; self.removeSelf = function () { var index = enemyBullets.indexOf(self); if (index !== -1) { enemyBullets.splice(index, 1); } self.destroy(); }; return self; }); var EnemyHealthBar = Container.expand(function (enemy, barWidth, barHeight) { var self = Container.call(this); self.enemy = enemy; self.barWidth = barWidth || 40; self.barHeight = barHeight || 6; self.background = LK.getAsset('enemy', { width: self.barWidth, height: self.barHeight, anchorX: 0.5, anchorY: 0.5, tint: 0x666666 }); self.foreground = LK.getAsset('healthItem', { width: self.barWidth, height: self.barHeight, anchorX: 0.5, anchorY: 0.5, tint: 0x4CAF50 }); self.addChild(self.background); self.addChild(self.foreground); self.update = function () { // Position above enemy self.x = self.enemy.x; self.y = self.enemy.y - 30; // Update health display var healthPercent = self.enemy.health / self.enemy.maxHealth; self.foreground.width = self.barWidth * healthPercent; // Hide if enemy is at full health self.visible = healthPercent < 1.0; }; self.removeSelf = function () { self.destroy(); }; return self; }); var ExperienceBar = Container.expand(function () { var self = Container.call(this); self.background = LK.getAsset('enemy', { width: 300, height: 15, anchorX: 0, anchorY: 0, tint: 0x333333 }); self.foreground = LK.getAsset('xp', { width: 300, height: 15, anchorX: 0, anchorY: 0, tint: 0x9C27B0 }); self.addChild(self.background); self.addChild(self.foreground); self.updateDisplay = function () { var xpPercent = player.experience / player.experienceToNext; self.foreground.width = 300 * xpPercent; }; return self; }); var FireRangeItem = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('fireRangeItem', { anchorX: 0.5, anchorY: 0.5, tint: 0x00AAFF }); self.lifeTime = 0; self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer) self.update = function () { self.lifeTime++; // Fade out and remove after lifetime expires if (self.lifeTime >= self.maxLifeTime) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { self.removeSelf(); } }); return; } // Check for player collection var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { self.applyEffect(); self.removeSelf(); } }; self.applyEffect = function () { // Increase fire range by 10% player.fireRange = player.fireRange * 1.1; // Visual effect tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut }); LK.getSound('pickup').play(); }; self.removeSelf = function () { var index = fireRangeItems.indexOf(self); if (index !== -1) { fireRangeItems.splice(index, 1); } self.destroy(); }; return self; }); var FireRateItem = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('fireRateItem', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFAA00 }); self.lifeTime = 0; self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer) self.update = function () { self.lifeTime++; // Fade out and remove after lifetime expires if (self.lifeTime >= self.maxLifeTime) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { self.removeSelf(); } }); return; } // Check for player collection var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { self.applyEffect(); self.removeSelf(); } }; self.applyEffect = function () { // Increase fire rate (lower fireRate value means faster shooting) player.fireRate = Math.max(5, player.fireRate - 8); // Visual effect tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut }); LK.getSound('pickup').play(); }; self.removeSelf = function () { var index = fireRateItems.indexOf(self); if (index !== -1) { fireRateItems.splice(index, 1); } self.destroy(); }; return self; }); var HealthBar = Container.expand(function () { var self = Container.call(this); self.background = LK.getAsset('enemy', { width: 200, height: 20, anchorX: 0, anchorY: 0, tint: 0x333333 }); self.foreground = LK.getAsset('player', { width: 200, height: 20, anchorX: 0, anchorY: 0, tint: 0x4CAF50 }); self.addChild(self.background); self.addChild(self.foreground); self.updateDisplay = function () { var healthPercent = player.health / player.maxHealth; self.foreground.width = 200 * healthPercent; }; return self; }); var HealthItem = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('healthItem', { anchorX: 0.5, anchorY: 0.5 }); self.lifeTime = 0; self.update = function () { self.lifeTime++; if (self.lifeTime > 1800) { self.removeSelf(); } var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { self.applyEffect(); self.removeSelf(); } }; self.applyEffect = function () { player.health = Math.min(player.maxHealth, player.health + 25); healthBar.updateDisplay(); LK.getSound('pickup').play(); }; self.removeSelf = function () { var index = healthItems.indexOf(self); if (index !== -1) { healthItems.splice(index, 1); } self.destroy(); }; return self; }); var MagnetItem = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('magnetItem', { anchorX: 0.5, anchorY: 0.5, tint: 0x9C27B0 }); self.lifeTime = 0; self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer) self.update = function () { self.lifeTime++; if (self.lifeTime >= self.maxLifeTime) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { self.removeSelf(); } }); return; } var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { self.applyEffect(); self.removeSelf(); } }; self.applyEffect = function () { player.magnetRange = 200; player.magnetDuration = 1200; // 20 seconds (10 seconds longer) tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut }); LK.getSound('pickup').play(); }; self.removeSelf = function () { var index = magnetItems.indexOf(self); if (index !== -1) { magnetItems.splice(index, 1); } self.destroy(); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.health = 60; self.maxHealth = 60; self.speed = 2; self.fireRate = 75; self.fireTimer = 0; self.experience = 0; self.level = 1; self.experienceToNext = 5; self.magnetRange = 0; self.magnetDuration = 0; self.fireRange = 1000; // Default fire range set to 1000 self.subMachineGunActive = false; self.subMachineGunDuration = 0; self.originalFireRate = 75; self.damageBoostActive = false; self.damageBoostDuration = 0; self.originalDamage = 25; self.damage = 25; self.update = function () { self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireAtNearestEnemy(); self.fireTimer = 0; } // Update magnet duration if (self.magnetDuration > 0) { self.magnetDuration--; if (self.magnetDuration <= 0) { self.magnetRange = 0; } } // Update sub machine gun duration if (self.subMachineGunDuration > 0) { self.subMachineGunDuration--; if (self.subMachineGunDuration <= 0) { self.subMachineGunActive = false; self.fireRate = self.originalFireRate; } } // Update damage boost duration if (self.damageBoostDuration > 0) { self.damageBoostDuration--; if (self.damageBoostDuration <= 0) { self.damageBoostActive = false; self.damage = self.originalDamage; } } }; self.fireAtNearestEnemy = function () { var nearestEnemy = 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 < nearestDistance && distance < self.fireRange) { nearestDistance = distance; nearestEnemy = enemy; } } if (nearestEnemy) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; var dx = nearestEnemy.x - self.x; var dy = nearestEnemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); bullet.velocityX = dx / distance * 8; bullet.velocityY = dy / distance * 8; bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); } }; self.takeDamage = function (damage) { self.health -= damage * 0.5; // Take 50% less damage (health decreases 50% slower) // Visual damage effect - flash red tween(playerGraphics, { tint: 0xFF0000 }, { duration: 150, onFinish: function onFinish() { tween(playerGraphics, { tint: 0xFFFFFF }, { duration: 150 }); } }); if (self.health <= 0) { self.health = 0; LK.showGameOver(); } healthBar.updateDisplay(); }; self.gainExperience = function (amount) { self.experience += amount; experienceBar.updateDisplay(); if (self.experience >= self.experienceToNext) { self.levelUp(); } }; self.levelUp = function () { if (self.level >= 50) { // At max level, just reset experience but don't level up self.experience = 0; experienceBar.updateDisplay(); return; } self.level++; self.experience = 0; self.experienceToNext = Math.floor(self.experienceToNext * 1.3); // Reduced from 1.5 to 1.3 (20% easier) // Increase maximum health by 10% self.maxHealth = Math.floor(self.maxHealth * 1.1); experienceBar.updateDisplay(); levelText.setText('Level: ' + self.level); // Check for boss fight every 8 levels (8, 16, 24, etc.) if (self.level % 8 === 0 && !isBossFight) { if (self.level === 8 || self.level === 16 || self.level === 24) { spawnBoss(); } } else { // Increase enemy speed based on player level (only if not boss fight) for (var i = 0; i < enemies.length; i++) { var levelFactor = 1 + (self.level - 1) * 0.1; enemies[i].speed = enemies[i].baseSpeed * levelFactor; } } LK.getSound('levelUp').play(); showUpgradeOptions(); }; return self; }); var SubMachineGunItem = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('subMachineGunItem', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF6600 }); self.lifeTime = 0; self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer) self.update = function () { self.lifeTime++; // Fade out and remove after lifetime expires if (self.lifeTime >= self.maxLifeTime) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { self.removeSelf(); } }); return; } // Check for player collection var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { self.applyEffect(); self.removeSelf(); } }; self.applyEffect = function () { // Activate sub machine gun mode for 10 seconds player.subMachineGunActive = true; player.subMachineGunDuration = 600; // 10 seconds at 60fps player.originalFireRate = player.fireRate; player.fireRate = Math.floor(player.fireRate * 0.5); // 50% faster fire rate (50% of original duration) // Visual effect tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut }); LK.getSound('pickup').play(); }; self.removeSelf = function () { var index = subMachineGunItems.indexOf(self); if (index !== -1) { subMachineGunItems.splice(index, 1); } self.destroy(); }; return self; }); var XPOrb = Container.expand(function () { var self = Container.call(this); var xpGraphics = self.attachAsset('xp', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1; self.lifeTime = 0; self.maxLifeTime = 900; // 15 seconds at 60fps self.update = function () { // Increment lifetime self.lifeTime++; // Check if XP orb has expired if (self.lifeTime >= self.maxLifeTime) { // Create fade out effect before removing tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { self.removeSelf(); } }); return; // Don't process movement if fading out } var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // If magnet is active, attract ALL XP orbs regardless of distance // Otherwise use normal collection range var attractionRange = player.magnetRange > 0 ? Infinity : 100; if (distance < attractionRange) { var speed = player.magnetRange > 0 ? 8 : 4; self.x += dx / distance * speed; self.y += dy / distance * speed; } if (distance < 25) { // Create collection effect tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, easing: tween.easeOut }); player.gainExperience(self.value); LK.getSound('pickup').play(); self.removeSelf(); } }; self.removeSelf = function () { var index = xpOrbs.indexOf(self); if (index !== -1) { xpOrbs.splice(index, 1); } self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2D5016 }); /**** * Game Code ****/ // Create jungle background with trees for (var i = 0; i < 15; i++) { var tree = LK.getAsset('tankEnemy', { width: 60 + Math.random() * 30, height: 100 + Math.random() * 50, anchorX: 0.5, anchorY: 1, tint: 0x006400 }); tree.x = Math.random() * 2048; tree.y = Math.random() * 2732; game.addChild(tree); } // Add grass patches for (var i = 0; i < 25; i++) { var grass = LK.getAsset('xp', { width: 60 + Math.random() * 40, height: 20 + Math.random() * 15, anchorX: 0.5, anchorY: 0.5, tint: 0x32CD32 }); grass.x = Math.random() * 2048; grass.y = Math.random() * 2732; game.addChild(grass); } // Add some bushes for (var i = 0; i < 10; i++) { var bush = LK.getAsset('enemy', { width: 40 + Math.random() * 30, height: 30 + Math.random() * 20, anchorX: 0.5, anchorY: 0.5, tint: 0x228B22 }); bush.x = Math.random() * 2048; bush.y = Math.random() * 2732; game.addChild(bush); } var player; var enemies = []; var enemyHealthBarSizes = { 'enemy': { width: 40, height: 6 }, // BasicEnemy 'fastEnemy': { width: 30, height: 5 }, // FastEnemy 'shooterEnemy': { width: 35, height: 6 }, // ShooterEnemy 'summonerEnemy': { width: 40, height: 7 }, // SummonerEnemy 'tankEnemy': { width: 50, height: 8 } }; var bullets = []; var enemyBullets = []; var xpOrbs = []; var healthItems = []; var magnetItems = []; var fireRateItems = []; var fireRangeItems = []; var subMachineGunItems = []; var damageBoostItems = []; var enemySpawnTimer = 0; var itemSpawnTimer = 0; var waveLevel = 1; var upgradePanel = null; var healthBar; var experienceBar; var levelText; var hordeSpawnTimer = 0; var isBossFight = false; var currentBoss = null; var bossHealthBar = null; var firstBossDefeated = false; var backgroundThemes = { desert: { backgroundColor: 0xDEB887, name: 'Desert' }, jungle: { backgroundColor: 0x2D5016, name: 'Jungle' }, castle: { backgroundColor: 0x696969, name: 'Castle' }, city: { backgroundColor: 0x1E1E1E, name: 'City' } }; var themeOrder = ['desert', 'jungle', 'castle', 'city']; var currentThemeIndex = 1; // Initialize player player = game.addChild(new Player()); player.x = 1024; player.y = 1366; // Initialize UI healthBar = new HealthBar(); healthBar.x = 50; healthBar.y = 50; LK.gui.topLeft.addChild(healthBar); experienceBar = new ExperienceBar(); experienceBar.x = 50; experienceBar.y = 80; LK.gui.topLeft.addChild(experienceBar); levelText = new Text2('Level: 1', { size: 40, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); levelText.x = 50; levelText.y = 110; LK.gui.topLeft.addChild(levelText); // Movement variables var dragNode = null; function showUpgradeOptions() { if (upgradePanel) return; upgradePanel = LK.getAsset('enemy', { width: 800, height: 600, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); upgradePanel.x = 1024; upgradePanel.y = 1366; LK.gui.center.addChild(upgradePanel); var upgrades = [{ name: 'Extra Health', effect: function effect() { player.maxHealth += 25; player.health += 25; healthBar.updateDisplay(); } }, { name: 'Faster Fire', effect: function effect() { player.fireRate = Math.max(10, player.fireRate - 5); } }, { name: 'XP Magnet', effect: function effect() { player.magnetRange = 200; player.magnetDuration = 600; } }, { name: 'Bigger Bullets', effect: function effect() {/* Visual upgrade */} }, { name: 'More Damage', effect: function effect() {/* Would need bullet damage tracking */} }]; var selectedUpgrades = []; for (var i = 0; i < 3; i++) { var randomIndex = Math.floor(Math.random() * upgrades.length); selectedUpgrades.push(upgrades[randomIndex]); } for (var i = 0; i < 3; i++) { var button = LK.getAsset('player', { width: 200, height: 80, anchorX: 0.5, anchorY: 0.5, tint: 0x4CAF50 }); button.x = -250 + i * 250; button.y = 0; button.upgradeIndex = i; button.upgrade = selectedUpgrades[i]; button.down = function (x, y, obj) { obj.upgrade.effect(); hideUpgradeOptions(); }; upgradePanel.addChild(button); var buttonText = new Text2(selectedUpgrades[i].name, { size: 24, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.x = button.x; buttonText.y = button.y; upgradePanel.addChild(buttonText); } } function hideUpgradeOptions() { if (upgradePanel) { upgradePanel.destroy(); upgradePanel = null; } } function spawnEnemy() { var enemy; var levelFactor = 1 + (player.level - 1) * 0.1; // Choose enemy type based on player level - different enemies every 5 levels var rand = Math.random(); if (player.level < 3) { enemy = new BasicEnemy(); } else if (player.level < 5) { if (rand < 0.8) enemy = new BasicEnemy();else enemy = new SummonerEnemy(); } else if (player.level < 10) { if (rand < 0.45) enemy = new BasicEnemy();else if (rand < 0.7) enemy = new FastEnemy();else if (rand < 0.85) enemy = new ExplodingEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy(); } else if (player.level < 15) { if (rand < 0.22) enemy = new BasicEnemy();else if (rand < 0.37) enemy = new FastEnemy();else if (rand < 0.55) enemy = new ExplodingEnemy();else if (rand < 0.7) enemy = new ShooterEnemy();else if (rand < 0.85) enemy = new StealthEnemy();else if (rand < 0.94) enemy = new SummonerEnemy();else enemy = new TankEnemy(); } else if (player.level < 20) { if (rand < 0.18) enemy = new BasicEnemy();else if (rand < 0.32) enemy = new FastEnemy();else if (rand < 0.46) enemy = new ExplodingEnemy();else if (rand < 0.6) enemy = new ShooterEnemy();else if (rand < 0.75) enemy = new StealthEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy(); } else if (player.level < 25) { if (rand < 0.13) enemy = new BasicEnemy();else if (rand < 0.27) enemy = new FastEnemy();else if (rand < 0.41) enemy = new ExplodingEnemy();else if (rand < 0.55) enemy = new ShooterEnemy();else if (rand < 0.7) enemy = new StealthEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy(); } else { if (rand < 0.08) enemy = new BasicEnemy();else if (rand < 0.25) enemy = new FastEnemy();else if (rand < 0.42) enemy = new ExplodingEnemy();else if (rand < 0.6) enemy = new ShooterEnemy();else if (rand < 0.75) enemy = new StealthEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy(); } // Scale enemy stats with player level - reduced speed scaling enemy.speed = enemy.baseSpeed * (levelFactor * 1.2); enemy.health = Math.floor(enemy.maxHealth * levelFactor); enemy.maxHealth = enemy.health; 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; } enemies.push(enemy); game.addChild(enemy); } function spawnHorde() { var hordeSize = Math.min(25, 5 + Math.floor(player.level / 2)); // Hordes grow much faster and larger // Limit horde size to not exceed maximum enemy count hordeSize = Math.min(hordeSize, 30 - enemies.length); if (hordeSize <= 0) return; // Don't spawn if already at limit var rand = Math.random(); var enemyType; if (player.level < 10) { enemyType = rand < 0.7 ? BasicEnemy : FastEnemy; } else if (player.level < 20) { if (rand < 0.4) enemyType = BasicEnemy;else if (rand < 0.7) enemyType = FastEnemy;else enemyType = ExplodingEnemy; } else { if (rand < 0.3) enemyType = BasicEnemy;else if (rand < 0.5) enemyType = FastEnemy;else if (rand < 0.7) enemyType = ExplodingEnemy;else enemyType = StealthEnemy; } for (var i = 0; i < hordeSize; i++) { var enemy = new enemyType(); var levelFactor = 1 + (player.level - 1) * 0.1; enemy.speed = enemy.baseSpeed * (levelFactor * 1.2); enemy.health = Math.floor(enemy.maxHealth * levelFactor); enemy.maxHealth = enemy.health; // Spawn all enemies from the same side var side = Math.floor(Math.random() * 4); var offset = i * 80; switch (side) { case 0: enemy.x = (Math.random() * 1000 + 500 + offset) % 2048; enemy.y = -50; break; case 1: enemy.x = 2098; enemy.y = (Math.random() * 1000 + 500 + offset) % 2732; break; case 2: enemy.x = (Math.random() * 1000 + 500 + offset) % 2048; enemy.y = 2782; break; case 3: enemy.x = -50; enemy.y = (Math.random() * 1000 + 500 + offset) % 2732; break; } enemies.push(enemy); game.addChild(enemy); } } function spawnBoss() { // Clear all existing enemies when boss appears for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); enemies.splice(i, 1); } // Clear all enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); enemyBullets.splice(i, 1); } isBossFight = true; currentBoss = new Boss(); currentBoss.x = 1024; // Center X currentBoss.y = 400; // Top area enemies.push(currentBoss); game.addChild(currentBoss); // Create boss health bar bossHealthBar = new BossHealthBar(currentBoss); LK.gui.top.addChild(bossHealthBar); } function spawnBoss2() { // Clear all existing enemies when boss appears for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); enemies.splice(i, 1); } // Clear all enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); enemyBullets.splice(i, 1); } isBossFight = true; currentBoss = new Boss2(); currentBoss.x = 1024; // Center X currentBoss.y = 400; // Top area enemies.push(currentBoss); game.addChild(currentBoss); // Create boss health bar bossHealthBar = new BossHealthBar(currentBoss); LK.gui.top.addChild(bossHealthBar); } function spawnHealthItem() { var item = new HealthItem(); item.x = Math.random() * 1800 + 100; item.y = Math.random() * 2400 + 100; healthItems.push(item); game.addChild(item); } function spawnMagnetItem() { var item = new MagnetItem(); item.x = Math.random() * 1800 + 100; item.y = Math.random() * 2400 + 100; magnetItems.push(item); game.addChild(item); } function spawnFireRateItem() { var item = new FireRateItem(); item.x = Math.random() * 1800 + 100; item.y = Math.random() * 2400 + 100; fireRateItems.push(item); game.addChild(item); } function spawnFireRangeItem() { var item = new FireRangeItem(); item.x = Math.random() * 1800 + 100; item.y = Math.random() * 2400 + 100; fireRangeItems.push(item); game.addChild(item); } function spawnSubMachineGunItem() { var item = new SubMachineGunItem(); item.x = Math.random() * 1800 + 100; item.y = Math.random() * 2400 + 100; subMachineGunItems.push(item); game.addChild(item); } function spawnDamageBoostItem() { var item = new DamageBoostItem(); item.x = Math.random() * 1800 + 100; item.y = Math.random() * 2400 + 100; damageBoostItems.push(item); game.addChild(item); } game.move = function (x, y, obj) { if (dragNode) { // Calculate target position with bounds checking var targetX = Math.max(30, Math.min(2018, x)); var targetY = Math.max(30, Math.min(2702, y)); // Move character slower towards target position using interpolation var moveSpeed = 0.1; // Lower value = slower movement (0.1 = 10% of distance per frame) var dx = targetX - dragNode.x; var dy = targetY - dragNode.y; dragNode.x += dx * moveSpeed; dragNode.y += dy * moveSpeed; } }; game.down = function (x, y, obj) { dragNode = player; }; game.up = function (x, y, obj) { dragNode = null; }; // Override the game restart functionality to change background var originalShowGameOver = LK.showGameOver; LK.showGameOver = function () { // Change to next theme when game over is shown currentThemeIndex = (currentThemeIndex + 1) % themeOrder.length; var newTheme = backgroundThemes[themeOrder[currentThemeIndex]]; game.setBackgroundColor(newTheme.backgroundColor); // Call original game over function originalShowGameOver(); }; game.update = function () { // Spawn enemies continuously (even during boss fights but at reduced rate) enemySpawnTimer++; var baseSpawnRate = Math.max(33, 198 - waveLevel * 11); // 10% higher spawn intervals = 10% fewer enemies var levelSpawnBonus = Math.floor(player.level / 4); var spawnRate = Math.max(17, baseSpawnRate - levelSpawnBonus * 5); // 10% higher minimum spawn rate // Reduce spawn rate by 40% after first boss is defeated if (firstBossDefeated) { spawnRate = Math.floor(spawnRate * 1.67); // 40% fewer enemies after first boss defeat (1/0.6 = 1.67) } // Reduce spawn rate during boss fights but don't stop completely if (isBossFight) { spawnRate = Math.floor(spawnRate * 8.7); // Spawn enemies 15% more frequently during boss fights (87% of original rate instead of 1000%) } if (enemySpawnTimer >= spawnRate && enemies.length < 30) { // Enemies multiply significantly as player levels up var spawnCount = 1; // Base spawn count increases with level var baseMultiplier = Math.floor(player.level / 5) + 1; // +1 enemy every 5 levels spawnCount = baseMultiplier; // Additional spawns with high probability at higher levels if (!isBossFight && player.level > 5) spawnCount += Math.random() < 0.8 ? 1 : 0; if (!isBossFight && player.level > 10) spawnCount += Math.random() < 0.7 ? 2 : 0; if (!isBossFight && player.level > 15) spawnCount += Math.random() < 0.6 ? 3 : 0; if (!isBossFight && player.level > 20) spawnCount += Math.random() < 0.5 ? 4 : 0; if (!isBossFight && player.level > 25) spawnCount += Math.random() < 0.4 ? 5 : 0; // Cap maximum spawn count to prevent performance issues and respect enemy limit spawnCount = Math.min(spawnCount, 15); spawnCount = Math.min(spawnCount, 30 - enemies.length); // Don't exceed 30 total enemies for (var s = 0; s < spawnCount; s++) { spawnEnemy(); } enemySpawnTimer = 0; } // Spawn hordes periodically when player gets stronger (not during boss fights) if (!isBossFight) { hordeSpawnTimer++; var hordeRate = Math.max(800, 2400 - player.level * 20); if (hordeSpawnTimer >= hordeRate && player.level >= 3 && enemies.length < 20) { spawnHorde(); hordeSpawnTimer = 0; } } // Spawn health items (less frequently) itemSpawnTimer++; if (itemSpawnTimer >= 900) { spawnHealthItem(); itemSpawnTimer = 0; } // Spawn magnet items (more frequently) if (LK.ticks % 600 === 0 && Math.random() < 0.8) { spawnMagnetItem(); } // Spawn fire rate items (much less frequently) if (LK.ticks % 1500 === 0 && Math.random() < 0.6) { // Every 25 seconds with 60% chance (20% increase from 50%) spawnFireRateItem(); } // Spawn fire range items (more frequently) if (LK.ticks % 1200 === 0 && Math.random() < 0.78) { // Every 20 seconds with 78% chance (30% increase from 60%) spawnFireRangeItem(); } // Spawn sub machine gun items (rarely) if (LK.ticks % 1800 === 0 && Math.random() < 0.3) { // Every 30 seconds with 30% chance spawnSubMachineGunItem(); } // Spawn damage boost items during boss fights if (isBossFight && LK.ticks % 1200 === 0 && Math.random() < 0.52) { // Every 20 seconds with 52% chance during boss fights (30% more frequent) spawnDamageBoostItem(); } // Increase difficulty over time if (LK.ticks % 1800 === 0) { waveLevel++; } // Update all game objects for (var i = enemies.length - 1; i >= 0; i--) { // Continuously increase enemy speed based on current player level var currentLevelFactor = 1 + (player.level - 1) * 0.08; // Reduced scaling enemies[i].speed = enemies[i].baseSpeed * currentLevelFactor; enemies[i].update(); } for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].update(); } for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].update(); } for (var i = xpOrbs.length - 1; i >= 0; i--) { xpOrbs[i].update(); } for (var i = healthItems.length - 1; i >= 0; i--) { healthItems[i].update(); } for (var i = magnetItems.length - 1; i >= 0; i--) { magnetItems[i].update(); } for (var i = fireRateItems.length - 1; i >= 0; i--) { fireRateItems[i].update(); } for (var i = fireRangeItems.length - 1; i >= 0; i--) { fireRangeItems[i].update(); } for (var i = subMachineGunItems.length - 1; i >= 0; i--) { subMachineGunItems[i].update(); } for (var i = damageBoostItems.length - 1; i >= 0; i--) { damageBoostItems[i].update(); } // Update boss health bar if (bossHealthBar) { bossHealthBar.update(); } player.update(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossHealthBar = Container.expand(function (boss) {
var self = Container.call(this);
self.boss = boss;
self.barWidth = 600;
self.barHeight = 30;
// Background bar
self.background = LK.getAsset('enemy', {
width: self.barWidth,
height: self.barHeight,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333
});
// Health bar
self.foreground = LK.getAsset('boss', {
width: self.barWidth,
height: self.barHeight,
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
// Boss name text
self.nameText = new Text2('BOSS', {
size: 32,
fill: 0xFFFFFF
});
self.nameText.anchor.set(0.5, 0.5);
self.nameText.x = 0;
self.nameText.y = -50;
// Health text
self.healthText = new Text2('', {
size: 24,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.healthText.x = 0;
self.healthText.y = 50;
self.addChild(self.background);
self.addChild(self.foreground);
self.addChild(self.nameText);
self.addChild(self.healthText);
self.update = function () {
if (!self.boss || self.boss.health <= 0) {
self.removeSelf();
return;
}
// Update health display
var healthPercent = self.boss.health / self.boss.maxHealth;
self.foreground.width = self.barWidth * healthPercent;
// Update health text
self.healthText.setText(self.boss.health + ' / ' + self.boss.maxHealth);
// Position at top center of screen
self.x = 1024;
self.y = 150;
};
self.removeSelf = function () {
self.destroy();
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
var baseDamage = player ? player.damage || 25 : 25;
self.damage = baseDamage;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
self.removeSelf();
}
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (self.intersects(enemy)) {
enemy.takeDamage(self.damage);
self.removeSelf();
break;
}
}
};
self.removeSelf = function () {
var index = bullets.indexOf(self);
if (index !== -1) {
bullets.splice(index, 1);
}
self.destroy();
};
return self;
});
var DamageBoostItem = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('damageBoostItem', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF2222
});
self.lifeTime = 0;
self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer than normal)
self.update = function () {
self.lifeTime++;
// Fade out and remove after lifetime expires
if (self.lifeTime >= self.maxLifeTime) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
self.removeSelf();
}
});
return;
}
// Check for player collection
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
self.applyEffect();
self.removeSelf();
}
};
self.applyEffect = function () {
// Activate damage boost for 15 seconds
player.damageBoostActive = true;
player.damageBoostDuration = 900; // 15 seconds at 60fps
player.originalDamage = player.damage || 25;
player.damage = Math.floor(player.originalDamage * 1.3); // 30% more damage
// Visual effect
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
LK.getSound('pickup').play();
};
self.removeSelf = function () {
var index = damageBoostItems.indexOf(self);
if (index !== -1) {
damageBoostItems.splice(index, 1);
}
self.destroy();
};
return self;
});
var EnemyBase = Container.expand(function (assetType, health, speed, damage, xpValue) {
var self = Container.call(this);
var enemyGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = health || 20;
self.maxHealth = self.health;
self.speed = speed || 1;
self.damage = damage || 10;
self.xpValue = xpValue || 3;
self.lastDamageTime = 0;
self.baseSpeed = self.speed;
self.assetType = assetType;
self.healthBar = null;
self.needsHealthBar = health > 50; // Big enemies (TankEnemy, ShooterEnemy) get health bars
self.update = function () {
self.updateMovement();
self.checkPlayerCollision();
if (self.healthBar) {
self.healthBar.update();
}
};
self.updateMovement = function () {
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 * self.speed;
self.y += dy / distance * self.speed;
}
};
self.checkPlayerCollision = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50 && LK.ticks - self.lastDamageTime > 30) {
player.takeDamage(self.damage);
self.lastDamageTime = LK.ticks;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
// Create health bar if this enemy needs one and doesn't have one yet
if (self.needsHealthBar && !self.healthBar) {
var barSize = enemyHealthBarSizes[self.assetType] || {
width: 40,
height: 6
};
self.healthBar = new EnemyHealthBar(self, barSize.width, barSize.height);
game.addChild(self.healthBar);
}
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Death effect animation
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0,
tint: 0xff4444,
rotation: Math.PI * 0.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clean up health bar if it exists
if (self.healthBar) {
self.healthBar.removeSelf();
self.healthBar = null;
}
for (var i = 0; i < self.xpValue; i++) {
var xpOrb = new XPOrb();
xpOrb.x = self.x + (Math.random() - 0.5) * 50;
xpOrb.y = self.y + (Math.random() - 0.5) * 50;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
var index = enemies.indexOf(self);
if (index !== -1) {
enemies.splice(index, 1);
}
self.destroy();
}
});
};
return self;
});
var TankEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'tankEnemy', 250, 0.5, 20, 8);
// High health (10 hits), slow speed, high damage
self.needsHealthBar = true; // Tank enemies get health bars due to high health
return self;
});
var SummonerEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'summonerEnemy', 60, 0.5, 10, 4);
self.summonTimer = 0;
self.summonRate = 180; // 3 seconds
self.maxSummons = 3;
self.currentSummons = 0;
self.shootTimer = 0;
self.updateMovement = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Keep far distance from player and shoot
if (distance > 400) {
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 300) {
// Move away if too close
if (distance > 0) {
self.x -= dx / distance * self.speed;
self.y -= dy / distance * self.speed;
}
} else {
// In optimal range - shoot at player
self.shootTimer++;
if (self.shootTimer >= 90) {
// Shoot every 1.5 seconds
self.shootAtPlayer();
self.shootTimer = 0;
}
}
// Summon minions
self.summonTimer++;
if (self.summonTimer >= self.summonRate && self.currentSummons < self.maxSummons) {
self.summonMinion();
self.summonTimer = 0;
}
};
self.summonMinion = function () {
var minion = new BasicEnemy();
minion.x = self.x + (Math.random() - 0.5) * 100;
minion.y = self.y + (Math.random() - 0.5) * 100;
minion.summoner = self; // Reference to summoner
enemies.push(minion);
game.addChild(minion);
self.currentSummons++;
// Visual summoning effect
tween(minion, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 0
});
tween(minion, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500,
easing: tween.bounceOut
});
};
self.shootAtPlayer = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.velocityX = dx / distance * 5;
bullet.velocityY = dy / distance * 5;
enemyBullets.push(bullet);
game.addChild(bullet);
}
// Visual shooting effect
tween(self, {
tint: 0xff6600
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 200
});
}
});
};
self.die = function () {
// Kill all summoned minions first
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i].summoner === self) {
enemies[i].die();
}
}
// Death effect animation
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0,
tint: 0xff4444,
rotation: Math.PI * 0.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clean up health bar if it exists
if (self.healthBar) {
self.healthBar.removeSelf();
self.healthBar = null;
}
for (var i = 0; i < self.xpValue; i++) {
var xpOrb = new XPOrb();
xpOrb.x = self.x + (Math.random() - 0.5) * 50;
xpOrb.y = self.y + (Math.random() - 0.5) * 50;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
var index = enemies.indexOf(self);
if (index !== -1) {
enemies.splice(index, 1);
}
self.destroy();
}
});
};
return self;
});
var StealthEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'enemy', 25, 2, 15, 1);
self.stealthTimer = 0;
self.stealthDuration = 120; // 2 seconds invisible
self.visibleDuration = 180; // 3 seconds visible
self.isStealthed = false;
self.update = function () {
self.updateMovement();
self.checkPlayerCollision();
self.updateStealth();
if (self.healthBar) {
self.healthBar.update();
}
};
self.updateStealth = function () {
self.stealthTimer++;
if (self.isStealthed) {
if (self.stealthTimer >= self.stealthDuration) {
self.becomeVisible();
self.stealthTimer = 0;
}
} else {
if (self.stealthTimer >= self.visibleDuration) {
self.becomeStealth();
self.stealthTimer = 0;
}
}
};
self.becomeStealth = function () {
self.isStealthed = true;
tween(self, {
alpha: 0.2
}, {
duration: 300
});
// Increase speed while stealthed
self.speed = self.baseSpeed * 1.5;
};
self.becomeVisible = function () {
self.isStealthed = false;
tween(self, {
alpha: 1
}, {
duration: 300
});
// Reset speed
self.speed = self.baseSpeed;
};
self.takeDamage = function (damage) {
// Take less damage while stealthed
var actualDamage = self.isStealthed ? damage * 0.5 : damage;
self.health -= actualDamage;
// Become visible when hit
if (self.isStealthed) {
self.becomeVisible();
self.stealthTimer = 0;
}
if (self.needsHealthBar && !self.healthBar) {
var barSize = enemyHealthBarSizes[self.assetType] || {
width: 40,
height: 6
};
self.healthBar = new EnemyHealthBar(self, barSize.width, barSize.height);
game.addChild(self.healthBar);
}
if (self.health <= 0) {
self.die();
}
};
return self;
});
var ShooterEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'shooterEnemy', 75, 0.8, 12, 5);
// Increased health to 75 (3 hits to kill)
self.shootTimer = 0;
self.shootRate = 120;
self.updateMovement = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Attack from long range instead of close contact
if (distance > 400) {
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 300) {
// Move away if too close
if (distance > 0) {
self.x -= dx / distance * self.speed * 0.5;
self.y -= dy / distance * self.speed * 0.5;
}
} else {
// In optimal range - shoot at player
self.shootTimer++;
if (self.shootTimer >= self.shootRate) {
self.shootAtPlayer();
self.shootTimer = 0;
}
}
};
self.shootAtPlayer = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.damage = 0.91; // Reduced damage by 35% from 1.4 to 0.91 (1.4 * 0.65 = 0.91)
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.velocityX = dx / distance * 6;
bullet.velocityY = dy / distance * 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var FastEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'fastEnemy', 10, 2.5, 8, 1);
return self;
});
var ExplodingEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'fastEnemy', 30, 1.5, 25, 1);
self.explosionRange = 120;
self.hasExploded = false;
self.checkPlayerCollision = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.explosionRange && !self.hasExploded) {
self.explode();
} else if (distance < 50 && LK.ticks - self.lastDamageTime > 30) {
player.takeDamage(self.damage);
self.lastDamageTime = LK.ticks;
}
};
self.explode = function () {
self.hasExploded = true;
// Visual explosion effect
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0,
tint: 0xff4400
}, {
duration: 400,
easing: tween.easeOut
});
// Damage player if in range
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.explosionRange) {
player.takeDamage(self.damage * 2);
}
// Remove after explosion
LK.setTimeout(function () {
self.die();
}, 400);
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.needsHealthBar && !self.healthBar) {
var barSize = enemyHealthBarSizes[self.assetType] || {
width: 40,
height: 6
};
self.healthBar = new EnemyHealthBar(self, barSize.width, barSize.height);
game.addChild(self.healthBar);
}
if (self.health <= 0) {
self.explode(); // Explode when killed
}
};
return self;
});
var Boss2 = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'boss2', 6000, 1.0, 30, 60);
// Increased damage from 25 to 30 (20% increase)
// Boss 2 has more health and damage than Boss 1
self.maxHealth = 6000 + Math.floor((player.level - 1) / 10) * 2400;
self.health = self.maxHealth;
self.needsHealthBar = true;
self.attackTimer = 0;
self.attackPhase = 0;
self.isCharging = false;
self.chargeTarget = {
x: 0,
y: 0
};
self.teleportTimer = 0;
self.isTeleporting = false;
// Boss entrance animation
self.alpha = 0;
tween(self, {
alpha: 1
}, {
duration: 2000,
easing: tween.easeOut
});
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 500
});
}
});
self.updateMovement = function () {
if (self.isCharging || self.isTeleporting) return;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// More aggressive movement than Boss 1
if (distance > 250) {
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 150) {
if (distance > 0) {
self.x -= dx / distance * self.speed * 0.7;
self.y -= dy / distance * self.speed * 0.7;
}
}
};
self.update = function () {
self.updateMovement();
self.checkPlayerCollision();
self.updateAttacks();
self.updateTeleport();
if (self.healthBar) {
self.healthBar.update();
}
};
self.updateTeleport = function () {
// Teleport every 8 seconds
self.teleportTimer++;
if (self.teleportTimer >= 480 && !self.isTeleporting) {
self.performTeleport();
self.teleportTimer = 0;
}
};
self.performTeleport = function () {
self.isTeleporting = true;
// Fade out
tween(self, {
alpha: 0.2,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
// Teleport to random position
self.x = 300 + Math.random() * 1448;
self.y = 300 + Math.random() * 1732;
// Fade back in
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
onFinish: function onFinish() {
self.isTeleporting = false;
}
});
}
});
};
self.updateAttacks = function () {
self.attackTimer++;
// Attack every 1.5 seconds
if (self.attackTimer >= 90) {
self.attackPhase = (self.attackPhase + 1) % 4;
self.performAttack();
self.attackTimer = 0;
}
};
self.performAttack = function () {
switch (self.attackPhase) {
case 0:
self.crossAttack();
break;
case 1:
self.chargeAttack();
break;
case 2:
self.circularAttack();
break;
case 3:
self.rapidFireAttack();
break;
}
};
self.crossAttack = function () {
// Fire bullets in cross pattern
var directions = [{
x: 1,
y: 0
}, {
x: -1,
y: 0
}, {
x: 0,
y: 1
}, {
x: 0,
y: -1
}, {
x: 0.7,
y: 0.7
}, {
x: -0.7,
y: 0.7
}, {
x: 0.7,
y: -0.7
}, {
x: -0.7,
y: -0.7
}];
for (var i = 0; i < directions.length; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = directions[i].x * 6;
bullet.velocityY = directions[i].y * 6;
bullet.damage = 10;
enemyBullets.push(bullet);
game.addChild(bullet);
}
// Visual effect
tween(self, {
tint: 0x4444ff
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 200
});
}
});
};
self.chargeAttack = function () {
// Similar to Boss 1 but faster
self.isCharging = true;
self.chargeTarget.x = player.x;
self.chargeTarget.y = player.y;
tween(self, {
tint: 0xff00ff,
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 150,
onFinish: function onFinish() {
tween(self, {
x: self.chargeTarget.x,
y: self.chargeTarget.y
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isCharging = false;
tween(self, {
tint: 0xffffff,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
});
};
self.circularAttack = function () {
// Fire bullets in expanding circle
for (var i = 0; i < 16; i++) {
var angle = i / 16 * Math.PI * 2;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = Math.cos(angle) * 5;
bullet.velocityY = Math.sin(angle) * 5;
bullet.damage = 8;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.rapidFireAttack = function () {
// Fire multiple bullets rapidly at player
for (var i = 0; i < 5; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.damage = 6;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var spread = (i - 2) * 0.2;
if (distance > 0) {
var angle = Math.atan2(dy, dx) + spread;
bullet.velocityX = Math.cos(angle) * 9;
bullet.velocityY = Math.sin(angle) * 9;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
};
self.die = function () {
// Boss death animation
tween(self, {
alpha: 0,
scaleX: 2.5,
scaleY: 2.5,
rotation: Math.PI * 1.5
}, {
duration: 2500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clean up health bar if it exists
if (self.healthBar) {
self.healthBar.removeSelf();
self.healthBar = null;
}
// Drop reduced XP (88% less total)
for (var i = 0; i < Math.floor(self.xpValue * 0.12); i++) {
var xpOrb = new XPOrb();
xpOrb.x = self.x + (Math.random() - 0.5) * 150;
xpOrb.y = self.y + (Math.random() - 0.5) * 150;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
// Drop even fewer items - 0.2 chance for range item
if (Math.random() < 0.2) {
var fireRangeItem = new FireRangeItem();
fireRangeItem.x = self.x + (Math.random() - 0.5) * 150;
fireRangeItem.y = self.y + (Math.random() - 0.5) * 150;
fireRangeItems.push(fireRangeItem);
game.addChild(fireRangeItem);
}
// Drop 40% more fire rate items - 0.28 chance for fire rate item (0.2 * 1.4)
if (Math.random() < 0.28) {
var fireRateItem = new FireRateItem();
fireRateItem.x = self.x + (Math.random() - 0.5) * 150;
fireRateItem.y = self.y + (Math.random() - 0.5) * 150;
fireRateItems.push(fireRateItem);
game.addChild(fireRateItem);
}
// Drop even fewer items - 0.2 chance for health item
if (Math.random() < 0.2) {
var healthItem = new HealthItem();
healthItem.x = self.x + (Math.random() - 0.5) * 150;
healthItem.y = self.y + (Math.random() - 0.5) * 150;
healthItems.push(healthItem);
game.addChild(healthItem);
}
var index = enemies.indexOf(self);
if (index !== -1) {
enemies.splice(index, 1);
}
// Clean up boss health bar
if (bossHealthBar) {
bossHealthBar.removeSelf();
bossHealthBar = null;
}
// End boss fight
isBossFight = false;
// Make player 40% stronger after boss defeat
player.damage = (player.damage || 25) * 1.4; // 40% more damage
player.fireRate = Math.max(5, Math.floor(player.fireRate * 0.7)); // 30% faster fire rate (multiplicative with 40% boost)
player.speed = player.speed * 1.4; // 40% faster movement
self.destroy();
}
});
};
return self;
});
var Boss = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'boss', 2800, 0.8, 24, 50);
// Increased damage from 20 to 24 (20% increase)
// Reduced health by 68% total (20% + 40% + 8%) and damage by 20%
self.maxHealth = 2800 + Math.floor((player.level - 1) / 10) * 1120; // Reduced scaling by 68% total
self.health = self.maxHealth;
self.needsHealthBar = true;
self.attackTimer = 0;
self.attackPhase = 0;
self.isCharging = false;
self.chargeTarget = {
x: 0,
y: 0
};
// Boss entrance animation
self.alpha = 0;
tween(self, {
alpha: 1
}, {
duration: 2000,
easing: tween.easeOut
});
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 500
});
}
});
self.updateMovement = function () {
if (self.isCharging) return; // Don't move normally when charging
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Keep distance from player but still move towards them slowly
if (distance > 300) {
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 200) {
// Move away if too close
if (distance > 0) {
self.x -= dx / distance * self.speed * 0.5;
self.y -= dy / distance * self.speed * 0.5;
}
}
};
self.update = function () {
self.updateMovement();
self.checkPlayerCollision();
self.updateAttacks();
if (self.healthBar) {
self.healthBar.update();
}
};
self.updateAttacks = function () {
self.attackTimer++;
// Reduced attack frequency by 50% total - every 1.67 seconds instead of 1.07 seconds
if (self.attackTimer >= 100) {
// 1.67 seconds (83 * 1.2 = 100 for 20% additional reduction)
self.attackPhase = (self.attackPhase + 1) % 3;
self.performAttack();
self.attackTimer = 0;
}
};
self.performAttack = function () {
switch (self.attackPhase) {
case 0:
self.spiralAttack();
break;
case 1:
self.chargeAttack();
break;
case 2:
self.burstAttack();
break;
}
};
self.spiralAttack = function () {
// Fire 30% fewer bullets in a spiral pattern (30% less than 11 = 8 bullets)
for (var i = 0; i < 8; i++) {
var angle = i / 8 * Math.PI * 2 + LK.ticks * 0.15;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.velocityX = Math.cos(angle) * 7;
bullet.velocityY = Math.sin(angle) * 7;
enemyBullets.push(bullet);
game.addChild(bullet);
}
// Visual effect
tween(self, {
tint: 0xff4444
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 200
});
}
});
};
self.chargeAttack = function () {
// Charge towards player
self.isCharging = true;
self.chargeTarget.x = player.x;
self.chargeTarget.y = player.y;
// Shorter warning time, faster charge
tween(self, {
tint: 0xff0000,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
// Perform the charge much faster
tween(self, {
x: self.chargeTarget.x,
y: self.chargeTarget.y
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isCharging = false;
tween(self, {
tint: 0xffffff,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
});
};
self.burstAttack = function () {
// Fire 30% fewer bullets towards player in multiple bursts (30% less than 17 = 12 bullets)
for (var i = 0; i < 12; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.damage = 12; // Reduced damage by 50% (from 25 to 12)
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var spread = (i - 6) * 0.15; // Adjusted spread center for 12 bullets
if (distance > 0) {
var angle = Math.atan2(dy, dx) + spread;
bullet.velocityX = Math.cos(angle) * 8;
bullet.velocityY = Math.sin(angle) * 8;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
};
self.die = function () {
// Boss death animation
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2,
rotation: Math.PI
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clean up health bar if it exists
if (self.healthBar) {
self.healthBar.removeSelf();
self.healthBar = null;
}
// Drop reduced XP (88% less total)
for (var i = 0; i < Math.floor(self.xpValue * 0.12); i++) {
var xpOrb = new XPOrb();
xpOrb.x = self.x + (Math.random() - 0.5) * 100;
xpOrb.y = self.y + (Math.random() - 0.5) * 100;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
// Drop even fewer items - 0.2 chance for range item
if (Math.random() < 0.2) {
var fireRangeItem = new FireRangeItem();
fireRangeItem.x = self.x + (Math.random() - 0.5) * 150;
fireRangeItem.y = self.y + (Math.random() - 0.5) * 150;
fireRangeItems.push(fireRangeItem);
game.addChild(fireRangeItem);
}
// Drop 40% more fire rate items - 0.28 chance for fire rate item (0.2 * 1.4)
if (Math.random() < 0.28) {
var fireRateItem = new FireRateItem();
fireRateItem.x = self.x + (Math.random() - 0.5) * 150;
fireRateItem.y = self.y + (Math.random() - 0.5) * 150;
fireRateItems.push(fireRateItem);
game.addChild(fireRateItem);
}
// Drop even fewer items - 0.2 chance for health item
if (Math.random() < 0.2) {
var healthItem = new HealthItem();
healthItem.x = self.x + (Math.random() - 0.5) * 150;
healthItem.y = self.y + (Math.random() - 0.5) * 150;
healthItems.push(healthItem);
game.addChild(healthItem);
}
var index = enemies.indexOf(self);
if (index !== -1) {
enemies.splice(index, 1);
}
// Clean up boss health bar
if (bossHealthBar) {
bossHealthBar.removeSelf();
bossHealthBar = null;
}
// End boss fight
isBossFight = false;
// Mark first boss as defeated for enemy spawn rate reduction
if (!firstBossDefeated) {
firstBossDefeated = true;
// Make player 40% stronger after first boss defeat
player.damage = (player.damage || 25) * 1.4; // 40% more damage
player.fireRate = Math.max(5, Math.floor(player.fireRate * 0.7)); // 30% faster fire rate (multiplicative with 40% boost)
player.speed = player.speed * 1.4; // 40% faster movement
}
self.destroy();
}
});
};
return self;
});
var BasicEnemy = EnemyBase.expand(function () {
var self = EnemyBase.call(this, 'enemy', 20, 1, 10, 1);
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff0000
});
self.velocityX = 0;
self.velocityY = 0;
self.damage = 7;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
self.removeSelf();
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 30) {
player.takeDamage(self.damage);
self.removeSelf();
}
};
self.removeSelf = function () {
var index = enemyBullets.indexOf(self);
if (index !== -1) {
enemyBullets.splice(index, 1);
}
self.destroy();
};
return self;
});
var EnemyHealthBar = Container.expand(function (enemy, barWidth, barHeight) {
var self = Container.call(this);
self.enemy = enemy;
self.barWidth = barWidth || 40;
self.barHeight = barHeight || 6;
self.background = LK.getAsset('enemy', {
width: self.barWidth,
height: self.barHeight,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x666666
});
self.foreground = LK.getAsset('healthItem', {
width: self.barWidth,
height: self.barHeight,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4CAF50
});
self.addChild(self.background);
self.addChild(self.foreground);
self.update = function () {
// Position above enemy
self.x = self.enemy.x;
self.y = self.enemy.y - 30;
// Update health display
var healthPercent = self.enemy.health / self.enemy.maxHealth;
self.foreground.width = self.barWidth * healthPercent;
// Hide if enemy is at full health
self.visible = healthPercent < 1.0;
};
self.removeSelf = function () {
self.destroy();
};
return self;
});
var ExperienceBar = Container.expand(function () {
var self = Container.call(this);
self.background = LK.getAsset('enemy', {
width: 300,
height: 15,
anchorX: 0,
anchorY: 0,
tint: 0x333333
});
self.foreground = LK.getAsset('xp', {
width: 300,
height: 15,
anchorX: 0,
anchorY: 0,
tint: 0x9C27B0
});
self.addChild(self.background);
self.addChild(self.foreground);
self.updateDisplay = function () {
var xpPercent = player.experience / player.experienceToNext;
self.foreground.width = 300 * xpPercent;
};
return self;
});
var FireRangeItem = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('fireRangeItem', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00AAFF
});
self.lifeTime = 0;
self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer)
self.update = function () {
self.lifeTime++;
// Fade out and remove after lifetime expires
if (self.lifeTime >= self.maxLifeTime) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
self.removeSelf();
}
});
return;
}
// Check for player collection
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
self.applyEffect();
self.removeSelf();
}
};
self.applyEffect = function () {
// Increase fire range by 10%
player.fireRange = player.fireRange * 1.1;
// Visual effect
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
LK.getSound('pickup').play();
};
self.removeSelf = function () {
var index = fireRangeItems.indexOf(self);
if (index !== -1) {
fireRangeItems.splice(index, 1);
}
self.destroy();
};
return self;
});
var FireRateItem = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('fireRateItem', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFAA00
});
self.lifeTime = 0;
self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer)
self.update = function () {
self.lifeTime++;
// Fade out and remove after lifetime expires
if (self.lifeTime >= self.maxLifeTime) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
self.removeSelf();
}
});
return;
}
// Check for player collection
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
self.applyEffect();
self.removeSelf();
}
};
self.applyEffect = function () {
// Increase fire rate (lower fireRate value means faster shooting)
player.fireRate = Math.max(5, player.fireRate - 8);
// Visual effect
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
LK.getSound('pickup').play();
};
self.removeSelf = function () {
var index = fireRateItems.indexOf(self);
if (index !== -1) {
fireRateItems.splice(index, 1);
}
self.destroy();
};
return self;
});
var HealthBar = Container.expand(function () {
var self = Container.call(this);
self.background = LK.getAsset('enemy', {
width: 200,
height: 20,
anchorX: 0,
anchorY: 0,
tint: 0x333333
});
self.foreground = LK.getAsset('player', {
width: 200,
height: 20,
anchorX: 0,
anchorY: 0,
tint: 0x4CAF50
});
self.addChild(self.background);
self.addChild(self.foreground);
self.updateDisplay = function () {
var healthPercent = player.health / player.maxHealth;
self.foreground.width = 200 * healthPercent;
};
return self;
});
var HealthItem = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('healthItem', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 0;
self.update = function () {
self.lifeTime++;
if (self.lifeTime > 1800) {
self.removeSelf();
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
self.applyEffect();
self.removeSelf();
}
};
self.applyEffect = function () {
player.health = Math.min(player.maxHealth, player.health + 25);
healthBar.updateDisplay();
LK.getSound('pickup').play();
};
self.removeSelf = function () {
var index = healthItems.indexOf(self);
if (index !== -1) {
healthItems.splice(index, 1);
}
self.destroy();
};
return self;
});
var MagnetItem = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('magnetItem', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x9C27B0
});
self.lifeTime = 0;
self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer)
self.update = function () {
self.lifeTime++;
if (self.lifeTime >= self.maxLifeTime) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
self.removeSelf();
}
});
return;
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
self.applyEffect();
self.removeSelf();
}
};
self.applyEffect = function () {
player.magnetRange = 200;
player.magnetDuration = 1200; // 20 seconds (10 seconds longer)
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
LK.getSound('pickup').play();
};
self.removeSelf = function () {
var index = magnetItems.indexOf(self);
if (index !== -1) {
magnetItems.splice(index, 1);
}
self.destroy();
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 60;
self.maxHealth = 60;
self.speed = 2;
self.fireRate = 75;
self.fireTimer = 0;
self.experience = 0;
self.level = 1;
self.experienceToNext = 5;
self.magnetRange = 0;
self.magnetDuration = 0;
self.fireRange = 1000; // Default fire range set to 1000
self.subMachineGunActive = false;
self.subMachineGunDuration = 0;
self.originalFireRate = 75;
self.damageBoostActive = false;
self.damageBoostDuration = 0;
self.originalDamage = 25;
self.damage = 25;
self.update = function () {
self.fireTimer++;
if (self.fireTimer >= self.fireRate) {
self.fireAtNearestEnemy();
self.fireTimer = 0;
}
// Update magnet duration
if (self.magnetDuration > 0) {
self.magnetDuration--;
if (self.magnetDuration <= 0) {
self.magnetRange = 0;
}
}
// Update sub machine gun duration
if (self.subMachineGunDuration > 0) {
self.subMachineGunDuration--;
if (self.subMachineGunDuration <= 0) {
self.subMachineGunActive = false;
self.fireRate = self.originalFireRate;
}
}
// Update damage boost duration
if (self.damageBoostDuration > 0) {
self.damageBoostDuration--;
if (self.damageBoostDuration <= 0) {
self.damageBoostActive = false;
self.damage = self.originalDamage;
}
}
};
self.fireAtNearestEnemy = function () {
var nearestEnemy = 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 < nearestDistance && distance < self.fireRange) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
if (nearestEnemy) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
var dx = nearestEnemy.x - self.x;
var dy = nearestEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
bullet.velocityX = dx / distance * 8;
bullet.velocityY = dy / distance * 8;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
};
self.takeDamage = function (damage) {
self.health -= damage * 0.5; // Take 50% less damage (health decreases 50% slower)
// Visual damage effect - flash red
tween(playerGraphics, {
tint: 0xFF0000
}, {
duration: 150,
onFinish: function onFinish() {
tween(playerGraphics, {
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
if (self.health <= 0) {
self.health = 0;
LK.showGameOver();
}
healthBar.updateDisplay();
};
self.gainExperience = function (amount) {
self.experience += amount;
experienceBar.updateDisplay();
if (self.experience >= self.experienceToNext) {
self.levelUp();
}
};
self.levelUp = function () {
if (self.level >= 50) {
// At max level, just reset experience but don't level up
self.experience = 0;
experienceBar.updateDisplay();
return;
}
self.level++;
self.experience = 0;
self.experienceToNext = Math.floor(self.experienceToNext * 1.3); // Reduced from 1.5 to 1.3 (20% easier)
// Increase maximum health by 10%
self.maxHealth = Math.floor(self.maxHealth * 1.1);
experienceBar.updateDisplay();
levelText.setText('Level: ' + self.level);
// Check for boss fight every 8 levels (8, 16, 24, etc.)
if (self.level % 8 === 0 && !isBossFight) {
if (self.level === 8 || self.level === 16 || self.level === 24) {
spawnBoss();
}
} else {
// Increase enemy speed based on player level (only if not boss fight)
for (var i = 0; i < enemies.length; i++) {
var levelFactor = 1 + (self.level - 1) * 0.1;
enemies[i].speed = enemies[i].baseSpeed * levelFactor;
}
}
LK.getSound('levelUp').play();
showUpgradeOptions();
};
return self;
});
var SubMachineGunItem = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('subMachineGunItem', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF6600
});
self.lifeTime = 0;
self.maxLifeTime = 960; // 16 seconds at 60fps (6 seconds longer)
self.update = function () {
self.lifeTime++;
// Fade out and remove after lifetime expires
if (self.lifeTime >= self.maxLifeTime) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
self.removeSelf();
}
});
return;
}
// Check for player collection
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
self.applyEffect();
self.removeSelf();
}
};
self.applyEffect = function () {
// Activate sub machine gun mode for 10 seconds
player.subMachineGunActive = true;
player.subMachineGunDuration = 600; // 10 seconds at 60fps
player.originalFireRate = player.fireRate;
player.fireRate = Math.floor(player.fireRate * 0.5); // 50% faster fire rate (50% of original duration)
// Visual effect
tween(self, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
LK.getSound('pickup').play();
};
self.removeSelf = function () {
var index = subMachineGunItems.indexOf(self);
if (index !== -1) {
subMachineGunItems.splice(index, 1);
}
self.destroy();
};
return self;
});
var XPOrb = Container.expand(function () {
var self = Container.call(this);
var xpGraphics = self.attachAsset('xp', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1;
self.lifeTime = 0;
self.maxLifeTime = 900; // 15 seconds at 60fps
self.update = function () {
// Increment lifetime
self.lifeTime++;
// Check if XP orb has expired
if (self.lifeTime >= self.maxLifeTime) {
// Create fade out effect before removing
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
self.removeSelf();
}
});
return; // Don't process movement if fading out
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If magnet is active, attract ALL XP orbs regardless of distance
// Otherwise use normal collection range
var attractionRange = player.magnetRange > 0 ? Infinity : 100;
if (distance < attractionRange) {
var speed = player.magnetRange > 0 ? 8 : 4;
self.x += dx / distance * speed;
self.y += dy / distance * speed;
}
if (distance < 25) {
// Create collection effect
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
player.gainExperience(self.value);
LK.getSound('pickup').play();
self.removeSelf();
}
};
self.removeSelf = function () {
var index = xpOrbs.indexOf(self);
if (index !== -1) {
xpOrbs.splice(index, 1);
}
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2D5016
});
/****
* Game Code
****/
// Create jungle background with trees
for (var i = 0; i < 15; i++) {
var tree = LK.getAsset('tankEnemy', {
width: 60 + Math.random() * 30,
height: 100 + Math.random() * 50,
anchorX: 0.5,
anchorY: 1,
tint: 0x006400
});
tree.x = Math.random() * 2048;
tree.y = Math.random() * 2732;
game.addChild(tree);
}
// Add grass patches
for (var i = 0; i < 25; i++) {
var grass = LK.getAsset('xp', {
width: 60 + Math.random() * 40,
height: 20 + Math.random() * 15,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x32CD32
});
grass.x = Math.random() * 2048;
grass.y = Math.random() * 2732;
game.addChild(grass);
}
// Add some bushes
for (var i = 0; i < 10; i++) {
var bush = LK.getAsset('enemy', {
width: 40 + Math.random() * 30,
height: 30 + Math.random() * 20,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x228B22
});
bush.x = Math.random() * 2048;
bush.y = Math.random() * 2732;
game.addChild(bush);
}
var player;
var enemies = [];
var enemyHealthBarSizes = {
'enemy': {
width: 40,
height: 6
},
// BasicEnemy
'fastEnemy': {
width: 30,
height: 5
},
// FastEnemy
'shooterEnemy': {
width: 35,
height: 6
},
// ShooterEnemy
'summonerEnemy': {
width: 40,
height: 7
},
// SummonerEnemy
'tankEnemy': {
width: 50,
height: 8
}
};
var bullets = [];
var enemyBullets = [];
var xpOrbs = [];
var healthItems = [];
var magnetItems = [];
var fireRateItems = [];
var fireRangeItems = [];
var subMachineGunItems = [];
var damageBoostItems = [];
var enemySpawnTimer = 0;
var itemSpawnTimer = 0;
var waveLevel = 1;
var upgradePanel = null;
var healthBar;
var experienceBar;
var levelText;
var hordeSpawnTimer = 0;
var isBossFight = false;
var currentBoss = null;
var bossHealthBar = null;
var firstBossDefeated = false;
var backgroundThemes = {
desert: {
backgroundColor: 0xDEB887,
name: 'Desert'
},
jungle: {
backgroundColor: 0x2D5016,
name: 'Jungle'
},
castle: {
backgroundColor: 0x696969,
name: 'Castle'
},
city: {
backgroundColor: 0x1E1E1E,
name: 'City'
}
};
var themeOrder = ['desert', 'jungle', 'castle', 'city'];
var currentThemeIndex = 1;
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Initialize UI
healthBar = new HealthBar();
healthBar.x = 50;
healthBar.y = 50;
LK.gui.topLeft.addChild(healthBar);
experienceBar = new ExperienceBar();
experienceBar.x = 50;
experienceBar.y = 80;
LK.gui.topLeft.addChild(experienceBar);
levelText = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 50;
levelText.y = 110;
LK.gui.topLeft.addChild(levelText);
// Movement variables
var dragNode = null;
function showUpgradeOptions() {
if (upgradePanel) return;
upgradePanel = LK.getAsset('enemy', {
width: 800,
height: 600,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333
});
upgradePanel.x = 1024;
upgradePanel.y = 1366;
LK.gui.center.addChild(upgradePanel);
var upgrades = [{
name: 'Extra Health',
effect: function effect() {
player.maxHealth += 25;
player.health += 25;
healthBar.updateDisplay();
}
}, {
name: 'Faster Fire',
effect: function effect() {
player.fireRate = Math.max(10, player.fireRate - 5);
}
}, {
name: 'XP Magnet',
effect: function effect() {
player.magnetRange = 200;
player.magnetDuration = 600;
}
}, {
name: 'Bigger Bullets',
effect: function effect() {/* Visual upgrade */}
}, {
name: 'More Damage',
effect: function effect() {/* Would need bullet damage tracking */}
}];
var selectedUpgrades = [];
for (var i = 0; i < 3; i++) {
var randomIndex = Math.floor(Math.random() * upgrades.length);
selectedUpgrades.push(upgrades[randomIndex]);
}
for (var i = 0; i < 3; i++) {
var button = LK.getAsset('player', {
width: 200,
height: 80,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4CAF50
});
button.x = -250 + i * 250;
button.y = 0;
button.upgradeIndex = i;
button.upgrade = selectedUpgrades[i];
button.down = function (x, y, obj) {
obj.upgrade.effect();
hideUpgradeOptions();
};
upgradePanel.addChild(button);
var buttonText = new Text2(selectedUpgrades[i].name, {
size: 24,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = button.x;
buttonText.y = button.y;
upgradePanel.addChild(buttonText);
}
}
function hideUpgradeOptions() {
if (upgradePanel) {
upgradePanel.destroy();
upgradePanel = null;
}
}
function spawnEnemy() {
var enemy;
var levelFactor = 1 + (player.level - 1) * 0.1;
// Choose enemy type based on player level - different enemies every 5 levels
var rand = Math.random();
if (player.level < 3) {
enemy = new BasicEnemy();
} else if (player.level < 5) {
if (rand < 0.8) enemy = new BasicEnemy();else enemy = new SummonerEnemy();
} else if (player.level < 10) {
if (rand < 0.45) enemy = new BasicEnemy();else if (rand < 0.7) enemy = new FastEnemy();else if (rand < 0.85) enemy = new ExplodingEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy();
} else if (player.level < 15) {
if (rand < 0.22) enemy = new BasicEnemy();else if (rand < 0.37) enemy = new FastEnemy();else if (rand < 0.55) enemy = new ExplodingEnemy();else if (rand < 0.7) enemy = new ShooterEnemy();else if (rand < 0.85) enemy = new StealthEnemy();else if (rand < 0.94) enemy = new SummonerEnemy();else enemy = new TankEnemy();
} else if (player.level < 20) {
if (rand < 0.18) enemy = new BasicEnemy();else if (rand < 0.32) enemy = new FastEnemy();else if (rand < 0.46) enemy = new ExplodingEnemy();else if (rand < 0.6) enemy = new ShooterEnemy();else if (rand < 0.75) enemy = new StealthEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy();
} else if (player.level < 25) {
if (rand < 0.13) enemy = new BasicEnemy();else if (rand < 0.27) enemy = new FastEnemy();else if (rand < 0.41) enemy = new ExplodingEnemy();else if (rand < 0.55) enemy = new ShooterEnemy();else if (rand < 0.7) enemy = new StealthEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy();
} else {
if (rand < 0.08) enemy = new BasicEnemy();else if (rand < 0.25) enemy = new FastEnemy();else if (rand < 0.42) enemy = new ExplodingEnemy();else if (rand < 0.6) enemy = new ShooterEnemy();else if (rand < 0.75) enemy = new StealthEnemy();else if (rand < 0.92) enemy = new SummonerEnemy();else enemy = new TankEnemy();
}
// Scale enemy stats with player level - reduced speed scaling
enemy.speed = enemy.baseSpeed * (levelFactor * 1.2);
enemy.health = Math.floor(enemy.maxHealth * levelFactor);
enemy.maxHealth = enemy.health;
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;
}
enemies.push(enemy);
game.addChild(enemy);
}
function spawnHorde() {
var hordeSize = Math.min(25, 5 + Math.floor(player.level / 2)); // Hordes grow much faster and larger
// Limit horde size to not exceed maximum enemy count
hordeSize = Math.min(hordeSize, 30 - enemies.length);
if (hordeSize <= 0) return; // Don't spawn if already at limit
var rand = Math.random();
var enemyType;
if (player.level < 10) {
enemyType = rand < 0.7 ? BasicEnemy : FastEnemy;
} else if (player.level < 20) {
if (rand < 0.4) enemyType = BasicEnemy;else if (rand < 0.7) enemyType = FastEnemy;else enemyType = ExplodingEnemy;
} else {
if (rand < 0.3) enemyType = BasicEnemy;else if (rand < 0.5) enemyType = FastEnemy;else if (rand < 0.7) enemyType = ExplodingEnemy;else enemyType = StealthEnemy;
}
for (var i = 0; i < hordeSize; i++) {
var enemy = new enemyType();
var levelFactor = 1 + (player.level - 1) * 0.1;
enemy.speed = enemy.baseSpeed * (levelFactor * 1.2);
enemy.health = Math.floor(enemy.maxHealth * levelFactor);
enemy.maxHealth = enemy.health;
// Spawn all enemies from the same side
var side = Math.floor(Math.random() * 4);
var offset = i * 80;
switch (side) {
case 0:
enemy.x = (Math.random() * 1000 + 500 + offset) % 2048;
enemy.y = -50;
break;
case 1:
enemy.x = 2098;
enemy.y = (Math.random() * 1000 + 500 + offset) % 2732;
break;
case 2:
enemy.x = (Math.random() * 1000 + 500 + offset) % 2048;
enemy.y = 2782;
break;
case 3:
enemy.x = -50;
enemy.y = (Math.random() * 1000 + 500 + offset) % 2732;
break;
}
enemies.push(enemy);
game.addChild(enemy);
}
}
function spawnBoss() {
// Clear all existing enemies when boss appears
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
// Clear all enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
enemyBullets.splice(i, 1);
}
isBossFight = true;
currentBoss = new Boss();
currentBoss.x = 1024; // Center X
currentBoss.y = 400; // Top area
enemies.push(currentBoss);
game.addChild(currentBoss);
// Create boss health bar
bossHealthBar = new BossHealthBar(currentBoss);
LK.gui.top.addChild(bossHealthBar);
}
function spawnBoss2() {
// Clear all existing enemies when boss appears
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
// Clear all enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
enemyBullets.splice(i, 1);
}
isBossFight = true;
currentBoss = new Boss2();
currentBoss.x = 1024; // Center X
currentBoss.y = 400; // Top area
enemies.push(currentBoss);
game.addChild(currentBoss);
// Create boss health bar
bossHealthBar = new BossHealthBar(currentBoss);
LK.gui.top.addChild(bossHealthBar);
}
function spawnHealthItem() {
var item = new HealthItem();
item.x = Math.random() * 1800 + 100;
item.y = Math.random() * 2400 + 100;
healthItems.push(item);
game.addChild(item);
}
function spawnMagnetItem() {
var item = new MagnetItem();
item.x = Math.random() * 1800 + 100;
item.y = Math.random() * 2400 + 100;
magnetItems.push(item);
game.addChild(item);
}
function spawnFireRateItem() {
var item = new FireRateItem();
item.x = Math.random() * 1800 + 100;
item.y = Math.random() * 2400 + 100;
fireRateItems.push(item);
game.addChild(item);
}
function spawnFireRangeItem() {
var item = new FireRangeItem();
item.x = Math.random() * 1800 + 100;
item.y = Math.random() * 2400 + 100;
fireRangeItems.push(item);
game.addChild(item);
}
function spawnSubMachineGunItem() {
var item = new SubMachineGunItem();
item.x = Math.random() * 1800 + 100;
item.y = Math.random() * 2400 + 100;
subMachineGunItems.push(item);
game.addChild(item);
}
function spawnDamageBoostItem() {
var item = new DamageBoostItem();
item.x = Math.random() * 1800 + 100;
item.y = Math.random() * 2400 + 100;
damageBoostItems.push(item);
game.addChild(item);
}
game.move = function (x, y, obj) {
if (dragNode) {
// Calculate target position with bounds checking
var targetX = Math.max(30, Math.min(2018, x));
var targetY = Math.max(30, Math.min(2702, y));
// Move character slower towards target position using interpolation
var moveSpeed = 0.1; // Lower value = slower movement (0.1 = 10% of distance per frame)
var dx = targetX - dragNode.x;
var dy = targetY - dragNode.y;
dragNode.x += dx * moveSpeed;
dragNode.y += dy * moveSpeed;
}
};
game.down = function (x, y, obj) {
dragNode = player;
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Override the game restart functionality to change background
var originalShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
// Change to next theme when game over is shown
currentThemeIndex = (currentThemeIndex + 1) % themeOrder.length;
var newTheme = backgroundThemes[themeOrder[currentThemeIndex]];
game.setBackgroundColor(newTheme.backgroundColor);
// Call original game over function
originalShowGameOver();
};
game.update = function () {
// Spawn enemies continuously (even during boss fights but at reduced rate)
enemySpawnTimer++;
var baseSpawnRate = Math.max(33, 198 - waveLevel * 11); // 10% higher spawn intervals = 10% fewer enemies
var levelSpawnBonus = Math.floor(player.level / 4);
var spawnRate = Math.max(17, baseSpawnRate - levelSpawnBonus * 5); // 10% higher minimum spawn rate
// Reduce spawn rate by 40% after first boss is defeated
if (firstBossDefeated) {
spawnRate = Math.floor(spawnRate * 1.67); // 40% fewer enemies after first boss defeat (1/0.6 = 1.67)
}
// Reduce spawn rate during boss fights but don't stop completely
if (isBossFight) {
spawnRate = Math.floor(spawnRate * 8.7); // Spawn enemies 15% more frequently during boss fights (87% of original rate instead of 1000%)
}
if (enemySpawnTimer >= spawnRate && enemies.length < 30) {
// Enemies multiply significantly as player levels up
var spawnCount = 1;
// Base spawn count increases with level
var baseMultiplier = Math.floor(player.level / 5) + 1; // +1 enemy every 5 levels
spawnCount = baseMultiplier;
// Additional spawns with high probability at higher levels
if (!isBossFight && player.level > 5) spawnCount += Math.random() < 0.8 ? 1 : 0;
if (!isBossFight && player.level > 10) spawnCount += Math.random() < 0.7 ? 2 : 0;
if (!isBossFight && player.level > 15) spawnCount += Math.random() < 0.6 ? 3 : 0;
if (!isBossFight && player.level > 20) spawnCount += Math.random() < 0.5 ? 4 : 0;
if (!isBossFight && player.level > 25) spawnCount += Math.random() < 0.4 ? 5 : 0;
// Cap maximum spawn count to prevent performance issues and respect enemy limit
spawnCount = Math.min(spawnCount, 15);
spawnCount = Math.min(spawnCount, 30 - enemies.length); // Don't exceed 30 total enemies
for (var s = 0; s < spawnCount; s++) {
spawnEnemy();
}
enemySpawnTimer = 0;
}
// Spawn hordes periodically when player gets stronger (not during boss fights)
if (!isBossFight) {
hordeSpawnTimer++;
var hordeRate = Math.max(800, 2400 - player.level * 20);
if (hordeSpawnTimer >= hordeRate && player.level >= 3 && enemies.length < 20) {
spawnHorde();
hordeSpawnTimer = 0;
}
}
// Spawn health items (less frequently)
itemSpawnTimer++;
if (itemSpawnTimer >= 900) {
spawnHealthItem();
itemSpawnTimer = 0;
}
// Spawn magnet items (more frequently)
if (LK.ticks % 600 === 0 && Math.random() < 0.8) {
spawnMagnetItem();
}
// Spawn fire rate items (much less frequently)
if (LK.ticks % 1500 === 0 && Math.random() < 0.6) {
// Every 25 seconds with 60% chance (20% increase from 50%)
spawnFireRateItem();
}
// Spawn fire range items (more frequently)
if (LK.ticks % 1200 === 0 && Math.random() < 0.78) {
// Every 20 seconds with 78% chance (30% increase from 60%)
spawnFireRangeItem();
}
// Spawn sub machine gun items (rarely)
if (LK.ticks % 1800 === 0 && Math.random() < 0.3) {
// Every 30 seconds with 30% chance
spawnSubMachineGunItem();
}
// Spawn damage boost items during boss fights
if (isBossFight && LK.ticks % 1200 === 0 && Math.random() < 0.52) {
// Every 20 seconds with 52% chance during boss fights (30% more frequent)
spawnDamageBoostItem();
}
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
waveLevel++;
}
// Update all game objects
for (var i = enemies.length - 1; i >= 0; i--) {
// Continuously increase enemy speed based on current player level
var currentLevelFactor = 1 + (player.level - 1) * 0.08; // Reduced scaling
enemies[i].speed = enemies[i].baseSpeed * currentLevelFactor;
enemies[i].update();
}
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].update();
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].update();
}
for (var i = xpOrbs.length - 1; i >= 0; i--) {
xpOrbs[i].update();
}
for (var i = healthItems.length - 1; i >= 0; i--) {
healthItems[i].update();
}
for (var i = magnetItems.length - 1; i >= 0; i--) {
magnetItems[i].update();
}
for (var i = fireRateItems.length - 1; i >= 0; i--) {
fireRateItems[i].update();
}
for (var i = fireRangeItems.length - 1; i >= 0; i--) {
fireRangeItems[i].update();
}
for (var i = subMachineGunItems.length - 1; i >= 0; i--) {
subMachineGunItems[i].update();
}
for (var i = damageBoostItems.length - 1; i >= 0; i--) {
damageBoostItems[i].update();
}
// Update boss health bar
if (bossHealthBar) {
bossHealthBar.update();
}
player.update();
};
yuvarlak mermi. In-Game asset. 2d. High contrast. No shadows
boss creature. In-Game asset. 2d. High contrast. No shadows
Tank enemy big creature. In-Game asset. 2d. High contrast. No shadows
XP point only round, no writing on and around it
creature enemy. In-Game asset. 2d. High contrast. No shadows
shooter enemy. In-Game asset. 2d. High contrast. No shadows
healty. In-Game asset. 2d. High contrast. No shadows
fire rate. In-Game asset. 2d. High contrast. No shadows
magnet. In-Game asset. 2d. High contrast. No shadows
hedef tahtası. In-Game asset. 2d. High contrast. No shadows
Give pistol
submachine gun. In-Game asset. 2d. High contrast. No shadows
Stronge. In-Game asset. 2d. High contrast. No shadows