/**** * 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