User prompt
When the player is so close to the portal, generate the next level and next level should start
User prompt
When the player enters the portal, generate the next level
User prompt
Now, I wanna update something. In the levels, there can be spawned Skin Color Tanks between 5 and 10, there can be spawned Red Tanks between 10 and 15, there can be spawned Green Tanks between 7 and 14 in a level.
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
Please fix the bug: 'keyboard is not defined' in or related to this line: 'keyboard.onKeyDown(function (key) {' Line Number: 442
User prompt
playerTank movements = WASD
User prompt
Player Movements = WASD
User prompt
Please fix the bug: 'window.addEventListener is not a function' in or related to this line: 'window.addEventListener('keydown', function (e) {' Line Number: 444
User prompt
Player shall move with "W/A/S/D" or arrow keys.
Code edit (1 edits merged)
Please save this source code
User prompt
Tank Battle
Initial prompt
Make a game for me. First, this game shall be 2D. The name is Tank Battle. Player has 100 HP (this means the health). There is a health bar in the left down corner. This game is pixel art. This game has levels. The player is a tank. The player shoots normal shells. The player has infinite shells. Every one of shells hit the skin color tank 3 HP. Every one of shells hit the red tank 10 HP. Every one of shells hit the green tank 25 HP. There are the tank enemies: Skin Color Tank: This tank has 50 shells (After finished all the shells, doesn't shoot anymore and destroys itself with explode {It explodes in a circular area, the radius of the circle is 2 meters. {1 meter = 16 pixels, 1 block [ground] = Sixteen by sixteen pixels} Depending on the distance, if the player is directly next to the center of the circle, the player takes 95 HP damage. If the player is less than 1 meter and more than 0.5 meters from the center of the circle, the player takes 65 HP damage. If the player is less than 1.5 meters and more than 1 meter away, the player takes 40 HP damage. If the player is less than 2 meters and more than 1.5 meters away, they take 20 HP damage. }). This tank is skin color. This tank has 50 HP. And shoots armor-piercing and explosive shells. Every one of shells damage 5 HP when they touch the player. Red Tank: This tank has 75 dynamites (After finished all the dynamites, doesn't shoot anymore, gets faster, when catches the player, explodes itself {It damages 75 HP}). This tank is red. This tank has 80 HP. If this tank is so close to player, it exploses and damages the player 50 HP. Every one of dynamites damage 15 HP when they touch the player. Green Tank: This tank has 150 asid bombs (After finished all the asid bombs, doesn't shoot anymore, gets faster, when catches the player, explodes itself {It damages 75 HP}). When an asid bomb hit the player, it damages 45 HP and posions for 3 seconds. Every one second, it hits player 1 HP and stops after three seconds. In the levels, there is a portal. If player enters that portal, the level finishes and the player passes to the next level. There is a labyrinth created with walls. But there are random counted tank enemies random places. There can be spawned Skin Color Tanks between 5 and 20, there can be spawned Red Tanks between 10 and 30, there can be spawned Green Tanks between 20 and 25 in a level.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AcidBomb = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('acidBomb', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.directionX = 0; self.directionY = 0; self.damage = 5; self.poisonDamage = 2; self.poisonDuration = 180; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var BearTrap = Container.expand(function () { var self = Container.call(this); var trapGraphics = self.attachAsset('bearTrap', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 20; self.isArmed = true; return self; }); var BlackBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('blackBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var BlackHole = Container.expand(function () { var self = Container.call(this); var holeGraphics = self.attachAsset('blackHole', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); self.radius = 64; // 1 block radius self.duration = 300; // 5 seconds at 60fps self.timer = 0; self.damageTimer = 0; self.pullStrength = 1.5; self.update = function () { if (gamePaused) { return; } self.timer++; self.damageTimer++; // Pull and damage effects var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius * 2) { // Pull player toward center var pullX = dx > 0 ? -self.pullStrength : self.pullStrength; var pullY = dy > 0 ? -self.pullStrength : self.pullStrength; if (!checkWallCollision(playerTank.x + pullX, playerTank.y)) { playerTank.x += pullX; } if (!checkWallCollision(playerTank.x, playerTank.y + pullY)) { playerTank.y += pullY; } // Damage at center every second if (distance <= 32 && self.damageTimer >= 60) { playerTank.health -= 8; hasBeenHurt = true; LK.getSound('hit').play(); if (playerTank.health <= 0) { LK.showGameOver(); } } } // Pull and damage enemies for (var i = skinTanks.length - 1; i >= 0; i--) { var dx = skinTanks[i].x - self.x; var dy = skinTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius * 2) { var pullX = dx > 0 ? -self.pullStrength : self.pullStrength; var pullY = dy > 0 ? -self.pullStrength : self.pullStrength; if (!checkWallCollision(skinTanks[i].x + pullX, skinTanks[i].y)) { skinTanks[i].x += pullX; } if (!checkWallCollision(skinTanks[i].x, skinTanks[i].y + pullY)) { skinTanks[i].y += pullY; } } } // Damage enemies every second if (self.damageTimer >= 60) { self.damageTimer = 0; for (var i = skinTanks.length - 1; i >= 0; i--) { var dx = skinTanks[i].x - self.x; var dy = skinTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { skinTanks[i].health -= 2; } } for (var i = redTanks.length - 1; i >= 0; i--) { var dx = redTanks[i].x - self.x; var dy = redTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { redTanks[i].health -= 4; } } for (var i = greenTanks.length - 1; i >= 0; i--) { var dx = greenTanks[i].x - self.x; var dy = greenTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { greenTanks[i].health -= 15; } } // White tanks die instantly for (var i = whiteTanks.length - 1; i >= 0; i--) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { whiteTanks[i].destroy(); whiteTanks.splice(i, 1); LK.setScore(LK.getScore() + 40); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; } } } if (self.timer >= self.duration) { self.destroy(); var index = blackHoles.indexOf(self); if (index > -1) { blackHoles.splice(index, 1); } } }; return self; }); var BlackTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('blackTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 225; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead (only if not in hard mode) if (!hardModeEnabled) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase target if close if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var blackBullet = new BlackBullet(); blackBullet.x = self.x; blackBullet.y = self.y; blackBullet.directionX = dirX; blackBullet.directionY = dirY; blackBullets.push(blackBullet); game.addChild(blackBullet); self.shootCooldown = 120; LK.getSound('shoot').play(); } }; return self; }); var BlueTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('blueTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 375; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase player if close if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing player if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var waterball = new Waterball(); waterball.x = self.x; waterball.y = self.y; waterball.directionX = dirX; waterball.directionY = dirY; waterballs.push(waterball); game.addChild(waterball); self.shootCooldown = 90; LK.getSound('shoot').play(); } }; return self; }); var Dynamite = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('dynamite', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.directionX = 0; self.directionY = 0; self.damage = 25; self.explosionRadius = 80; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var ElectricField = Container.expand(function () { var self = Container.call(this); var fieldGraphics = self.attachAsset('electricField', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.radius = 160; // 2 blocks radius self.duration = 300; // 5 seconds at 60fps self.timer = 0; self.damageTimer = 0; self.update = function () { if (gamePaused) { return; } self.timer++; self.damageTimer++; // Damage every 60 frames (1 second) if (self.damageTimer >= 60) { self.damageTimer = 0; // Check player damage var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { playerTank.health -= 2; hasBeenHurt = true; LK.getSound('hit').play(); if (playerTank.health <= 0) { LK.showGameOver(); } } // Check enemy damage and change targets for (var i = skinTanks.length - 1; i >= 0; i--) { var dx = skinTanks[i].x - self.x; var dy = skinTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { skinTanks[i].health -= 0.5; skinTanks[i].targetWhiteTank = true; } } for (var i = redTanks.length - 1; i >= 0; i--) { var dx = redTanks[i].x - self.x; var dy = redTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { redTanks[i].health -= 2; redTanks[i].targetWhiteTank = true; } } for (var i = greenTanks.length - 1; i >= 0; i--) { var dx = greenTanks[i].x - self.x; var dy = greenTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { greenTanks[i].health -= 10; greenTanks[i].targetWhiteTank = true; } } } if (self.timer >= self.duration) { self.destroy(); var index = electricFields.indexOf(self); if (index > -1) { electricFields.splice(index, 1); } } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var FallingFireball = Container.expand(function () { var self = Container.call(this); var fireballGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.targetX = 0; self.targetY = 0; self.warningTimer = 120; // 2 seconds warning self.warningCircle = null; self.hasWarned = false; self.update = function () { if (gamePaused) { return; } if (self.warningTimer > 0) { self.warningTimer--; if (!self.hasWarned) { // Create warning circle self.warningCircle = LK.getAsset('ground', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF0000, alpha: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.warningCircle.x = self.targetX; self.warningCircle.y = self.targetY; game.addChild(self.warningCircle); self.hasWarned = true; } } else { // Remove warning circle and drop fireball if (self.warningCircle) { self.warningCircle.destroy(); self.warningCircle = null; } self.x = self.targetX; self.y = self.targetY; // Create fire sign var fireSign = new FireSign(); fireSign.x = self.x; fireSign.y = self.y; fireSigns.push(fireSign); game.addChild(fireSign); // Remove self self.destroy(); var index = fallingFireballs.indexOf(self); if (index > -1) { fallingFireballs.splice(index, 1); } } }; return self; }); var FireSign = Container.expand(function () { var self = Container.call(this); var fireGraphics = self.attachAsset('fireSign', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.damage = 2; self.damageTimer = 0; self.lifetime = 300; // 5 seconds self.timer = 0; self.update = function () { if (gamePaused) { return; } self.timer++; self.damageTimer++; if (self.timer >= self.lifetime) { self.destroy(); var index = fireSigns.indexOf(self); if (index > -1) { fireSigns.splice(index, 1); } } }; return self; }); var Fireball = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 15; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var GreenTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('greenTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 40; self.speed = 0.8; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead due to electric field if (self.targetWhiteTank) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase target if close if (distance < 300) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Calculate target angle for rotation var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(self, { rotation: true }); // Smoothly rotate the tank to face the movement direction tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 200 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var acidBomb = new AcidBomb(); acidBomb.x = self.x; acidBomb.y = self.y; acidBomb.directionX = dirX; acidBomb.directionY = dirY; acidBombs.push(acidBomb); game.addChild(acidBomb); self.shootCooldown = 150; LK.getSound('shoot').play(); } }; return self; }); var IceBlock = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('iceBlock', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 4; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var IceTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('iceTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase player if close if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing player if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var iceBlock = new IceBlock(); iceBlock.x = self.x; iceBlock.y = self.y; iceBlock.directionX = dirX; iceBlock.directionY = dirY; iceBlocks.push(iceBlock); game.addChild(iceBlock); self.shootCooldown = 80; LK.getSound('shoot').play(); } }; return self; }); var Medkit = Container.expand(function () { var self = Container.call(this); var medkitGraphics = self.attachAsset('medkit', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var OrangeTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('orangeTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 450; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase player if close if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing player if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var fireball = new Fireball(); fireball.x = self.x; fireball.y = self.y; fireball.directionX = dirX; fireball.directionY = dirY; fireballs.push(fireball); game.addChild(fireball); self.shootCooldown = 100; LK.getSound('shoot').play(); } }; return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var PlayerTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('playerTank', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 100; self.health = 100; self.speed = 3; self.shootCooldown = 0; self.poisonTimer = 0; self.poisonDamage = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.poisonTimer > 0) { self.poisonTimer--; if (LK.ticks % 30 === 0) { self.health -= self.poisonDamage; if (self.health <= 0) { LK.showGameOver(); } } } }; return self; }); var Portal = Container.expand(function () { var self = Container.call(this); var portalGraphics = self.attachAsset('portal', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Portal no longer rotates }; return self; }); var RedTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('redTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 80; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead due to electric field if (self.targetWhiteTank) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase target if close if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Calculate target angle for rotation var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(self, { rotation: true }); // Smoothly rotate the tank to face the movement direction tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 250 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var dynamite = new Dynamite(); dynamite.x = self.x; dynamite.y = self.y; dynamite.directionX = dirX; dynamite.directionY = dirY; dynamites.push(dynamite); game.addChild(dynamite); self.shootCooldown = 120; LK.getSound('shoot').play(); } }; return self; }); var SkinTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('skinTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 50; self.speed = 1.5; self.shootCooldown = 0; self.explosionRadius = 100; self.lastPlayerX = 0; self.lastPlayerY = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; var targetWhiteTank = false; // Check if should target white tank instead due to electric field if (self.targetWhiteTank) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; targetWhiteTank = true; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase target if close if (distance < 150) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Calculate target angle for rotation var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(self, { rotation: true }); // Smoothly rotate the tank to face the movement direction tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.directionX = dirX; bullet.directionY = dirY; bullet.damage = 3; enemyBullets.push(bullet); game.addChild(bullet); self.shootCooldown = 90; LK.getSound('shoot').play(); } }; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Waterball = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('waterball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 5; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var WhiteBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('whiteBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var WhiteTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('whiteTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 275; self.speed = 1; self.shootCooldown = 0; self.targetWhiteTank = false; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; var targetBlackTank = false; // Check if should target black tank instead (only if not in hard mode) if (!hardModeEnabled) { for (var i = 0; i < blackTanks.length; i++) { var dx = blackTanks[i].x - self.x; var dy = blackTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = blackTanks[i]; targetBlackTank = true; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase target if close if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var whiteBullet = new WhiteBullet(); whiteBullet.x = self.x; whiteBullet.y = self.y; whiteBullet.directionX = dirX; whiteBullet.directionY = dirY; whiteBullets.push(whiteBullet); game.addChild(whiteBullet); self.shootCooldown = 120; LK.getSound('shoot').play(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F2F }); /**** * Game Code ****/ var gridWidth = 32; var gridHeight = 42; var cellSize = 64; var walls = []; var skinTanks = []; var redTanks = []; var greenTanks = []; var playerBullets = []; var enemyBullets = []; var dynamites = []; var acidBombs = []; var explosions = []; var medkits = []; var whiteTanks = []; var blackTanks = []; var whiteBullets = []; var blackBullets = []; var electricFields = []; var blackHoles = []; var bearTraps = []; var orangeTanks = []; var blueTanks = []; var iceTanks = []; var fireballs = []; var waterballs = []; var iceBlocks = []; var fireSigns = []; var fallingFireballs = []; var playerTank; var portal; var currentLevel = 1; var gameStarted = false; var isDragging = false; var gamePaused = false; var showingMainMenu = true; var disarmButton = null; var currentNearbyTrap = null; var firstPortalUsed = false; var previousPortalX = 0; var previousPortalY = 0; // Main menu container var mainMenu = new Container(); mainMenu.visible = true; LK.gui.center.addChild(mainMenu); // Main menu background image var menuBackground = LK.getAsset('darkGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 43, alpha: 0.8 }); mainMenu.addChild(menuBackground); // Play button var playButton = new Text2('PLAY', { size: 120, fill: 0xFFFFFF, font: "monospace" }); playButton.anchor.set(0.5, 0.5); playButton.x = 0; playButton.y = 0; mainMenu.addChild(playButton); // Version text var versionText = new Text2('v.0.1.4', { size: 80, fill: 0xFFFF00, font: "monospace" }); versionText.anchor.set(1, 1); versionText.x = 950; // Adjusted position to ensure visibility versionText.y = 1300; // Adjusted position to ensure visibility mainMenu.addChild(versionText); // Experiments screen container var experimentsScreen = new Container(); experimentsScreen.visible = false; LK.gui.center.addChild(experimentsScreen); // Experiments screen background var experimentsBackground = LK.getAsset('darkGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 43, alpha: 0.8 }); experimentsScreen.addChild(experimentsBackground); // Experiments title var experimentsTitle = new Text2('Do You Wanna Activate Experiments', { size: 80, fill: 0xFFFFFF, font: "monospace" }); experimentsTitle.anchor.set(0.5, 0.5); experimentsTitle.x = 0; experimentsTitle.y = -200; experimentsScreen.addChild(experimentsTitle); // Initialize hard mode setting from storage var hardModeEnabled = storage.hardModeEnabled || false; // Hard mode toggle button var hardModeButton = new Text2(hardModeEnabled ? 'Hard Mode - On' : 'Hard Mode - Off', { size: 60, fill: hardModeEnabled ? 0x00FF00 : 0xFF0000, font: "monospace" }); hardModeButton.anchor.set(0.5, 0.5); hardModeButton.x = 0; hardModeButton.y = 0; experimentsScreen.addChild(hardModeButton); // Hard mode button click handler hardModeButton.down = function (x, y, obj) { hardModeEnabled = !hardModeEnabled; storage.hardModeEnabled = hardModeEnabled; hardModeButton.setText(hardModeEnabled ? 'Hard Mode - On' : 'Hard Mode - Off'); hardModeButton.fill = hardModeEnabled ? 0x00FF00 : 0xFF0000; hardModeButton.tint = hardModeEnabled ? 0x00FF00 : 0xFF0000; }; // Continue button to start game after experiments screen var continueButton = new Text2('CONTINUE', { size: 80, fill: 0xFFFFFF, font: "monospace" }); continueButton.anchor.set(0.5, 0.5); continueButton.x = 0; continueButton.y = 200; experimentsScreen.addChild(continueButton); // Continue button click handler continueButton.down = function (x, y, obj) { experimentsScreen.visible = false; showingMainMenu = false; gameStarted = true; startLevel(); }; // Style selection screen container var styleSelectionScreen = new Container(); styleSelectionScreen.visible = false; LK.gui.center.addChild(styleSelectionScreen); // Style selection screen background var styleSelectionBackground = LK.getAsset('darkGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 43, alpha: 0.8 }); styleSelectionScreen.addChild(styleSelectionBackground); // Style selection title var styleTitle = new Text2('CHOOSE A STYLE', { size: 100, fill: 0xFFFFFF, font: "monospace" }); styleTitle.anchor.set(0.5, 0.5); styleTitle.x = 0; styleTitle.y = -300; styleSelectionScreen.addChild(styleTitle); // Normal style button var normalStyleButton = new Text2('NORMAL', { size: 80, fill: 0x00FF00, font: "monospace" }); normalStyleButton.anchor.set(0.5, 0.5); normalStyleButton.x = -300; normalStyleButton.y = 0; styleSelectionScreen.addChild(normalStyleButton); // Lava style button var lavaStyleButton = new Text2('LAVA', { size: 80, fill: 0xFF4500, font: "monospace" }); lavaStyleButton.anchor.set(0.5, 0.5); lavaStyleButton.x = 0; lavaStyleButton.y = 0; styleSelectionScreen.addChild(lavaStyleButton); // Ice style button var iceStyleButton = new Text2('ICE', { size: 80, fill: 0x00BFFF, font: "monospace" }); iceStyleButton.anchor.set(0.5, 0.5); iceStyleButton.x = 300; iceStyleButton.y = 0; styleSelectionScreen.addChild(iceStyleButton); // Map style variable var mapStyle = 'normal'; // Normal style click handler normalStyleButton.down = function (x, y, obj) { mapStyle = 'normal'; styleSelectionScreen.visible = false; experimentsScreen.visible = true; }; // Lava style click handler lavaStyleButton.down = function (x, y, obj) { mapStyle = 'lava'; styleSelectionScreen.visible = false; experimentsScreen.visible = true; }; // Ice style click handler iceStyleButton.down = function (x, y, obj) { mapStyle = 'ice'; styleSelectionScreen.visible = false; experimentsScreen.visible = true; }; // Play button click handler playButton.down = function (x, y, obj) { mainMenu.visible = false; styleSelectionScreen.visible = true; }; var nextLevelScreen = new Container(); nextLevelScreen.visible = false; LK.gui.center.addChild(nextLevelScreen); // Next level screen background var nextLevelBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 12, scaleY: 8, tint: 0x000000, alpha: 0.9 }); nextLevelScreen.addChild(nextLevelBackground); // Next level button var nextLevelButton = new Text2('NEXT LEVEL', { size: 80, fill: 0xFFFFFF, font: "monospace" }); nextLevelButton.anchor.set(0.5, 0.5); nextLevelButton.x = 0; nextLevelButton.y = 0; nextLevelScreen.addChild(nextLevelButton); // Next level button click handler nextLevelButton.down = function (x, y, obj) { nextLevelScreen.visible = false; gamePaused = false; // Generate new level startLevel(); }; // Return to main menu button var returnToMenuButton = new Text2('RETURN TO MAIN MENU', { size: 60, fill: 0xFFFFFF, font: "monospace" }); returnToMenuButton.anchor.set(0.5, 0.5); returnToMenuButton.x = 0; returnToMenuButton.y = 100; nextLevelScreen.addChild(returnToMenuButton); // Return to main menu button click handler returnToMenuButton.down = function (x, y, obj) { // Clear all game objects for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); } walls = []; for (var i = skinTanks.length - 1; i >= 0; i--) { skinTanks[i].destroy(); } skinTanks = []; for (var i = redTanks.length - 1; i >= 0; i--) { redTanks[i].destroy(); } redTanks = []; for (var i = greenTanks.length - 1; i >= 0; i--) { greenTanks[i].destroy(); } greenTanks = []; for (var i = medkits.length - 1; i >= 0; i--) { medkits[i].destroy(); } medkits = []; for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = dynamites.length - 1; i >= 0; i--) { dynamites[i].destroy(); } dynamites = []; for (var i = acidBombs.length - 1; i >= 0; i--) { acidBombs[i].destroy(); } acidBombs = []; for (var i = explosions.length - 1; i >= 0; i--) { explosions[i].destroy(); } explosions = []; for (var i = whiteTanks.length - 1; i >= 0; i--) { whiteTanks[i].destroy(); } whiteTanks = []; for (var i = blackTanks.length - 1; i >= 0; i--) { blackTanks[i].destroy(); } blackTanks = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; for (var i = orangeTanks.length - 1; i >= 0; i--) { orangeTanks[i].destroy(); } orangeTanks = []; for (var i = blueTanks.length - 1; i >= 0; i--) { blueTanks[i].destroy(); } blueTanks = []; for (var i = iceTanks.length - 1; i >= 0; i--) { iceTanks[i].destroy(); } iceTanks = []; for (var i = fireballs.length - 1; i >= 0; i--) { fireballs[i].destroy(); } fireballs = []; for (var i = waterballs.length - 1; i >= 0; i--) { waterballs[i].destroy(); } waterballs = []; for (var i = iceBlocks.length - 1; i >= 0; i--) { iceBlocks[i].destroy(); } iceBlocks = []; for (var i = fireSigns.length - 1; i >= 0; i--) { fireSigns[i].destroy(); } fireSigns = []; for (var i = fallingFireballs.length - 1; i >= 0; i--) { if (fallingFireballs[i].warningCircle) { fallingFireballs[i].warningCircle.destroy(); } fallingFireballs[i].destroy(); } fallingFireballs = []; // Destroy player tank and portal if they exist if (playerTank) { playerTank.destroy(); playerTank = null; } if (portal) { portal.destroy(); portal = null; } // Reset game state currentLevel = 1; gameStarted = false; isDragging = false; gamePaused = false; showingMainMenu = true; levelsWithoutDying = 0; storage.levelsWithoutDying = levelsWithoutDying; firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; LK.setScore(0); // Hide next level screen and show main menu nextLevelScreen.visible = false; mainMenu.visible = true; }; var healthBarBackground = LK.getAsset('wall', { anchorX: 0, anchorY: 1, scaleX: 4, scaleY: 0.8, tint: 0x333333 }); LK.gui.bottomLeft.addChild(healthBarBackground); var healthBarFill = LK.getAsset('wall', { anchorX: 0, anchorY: 1, scaleX: 4, scaleY: 0.8, tint: 0x00ff00 }); LK.gui.bottomLeft.addChild(healthBarFill); var levelText = new Text2('Level: 1', { size: 50, fill: 0xFFFFFF, font: "monospace" }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); var scoreText = new Text2('Score: 0', { size: 40, fill: 0xFFFFFF, font: "monospace" }); scoreText.anchor.set(0.5, 0); scoreText.x = 0; scoreText.y = 80; LK.gui.top.addChild(scoreText); var bestScoreText = new Text2('Best: ' + (storage.bestScore || 0), { size: 35, fill: 0xFFFF00, font: "monospace" }); bestScoreText.anchor.set(0.5, 0); bestScoreText.x = 0; bestScoreText.y = 130; LK.gui.top.addChild(bestScoreText); // Achievement button var achievementButton = new Text2('ACHIEVEMENTS', { size: 30, fill: 0xFFFFFF, font: "monospace" }); achievementButton.anchor.set(1, 0); LK.gui.topRight.addChild(achievementButton); // Achievement menu (initially hidden) var achievementMenu = new Container(); achievementMenu.visible = false; LK.gui.center.addChild(achievementMenu); // Achievement menu background var menuBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20, tint: 0x000000, alpha: 0.8 }); achievementMenu.addChild(menuBackground); // Achievement title background var titleBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 1.5, tint: 0x000000, alpha: 0.9 }); titleBackground.x = 0; titleBackground.y = -400; achievementMenu.addChild(titleBackground); // Achievement title var achievementTitle = new Text2('ACHIEVEMENTS', { size: 60, fill: 0xFFFF00, font: "monospace" }); achievementTitle.anchor.set(0.5, 0.5); achievementTitle.x = 0; achievementTitle.y = -400; achievementMenu.addChild(achievementTitle); // Initialize achievements in storage if they don't exist var achievements = storage.achievements || { killAllEnemies: false, useFirstMedkit: false, killFirstEnemy: false, finishWithoutDying: false, get150Score: false, beatPreviousBest: false, arriveAtLevel3: false, kill50EnemiesTotal: false, killWhiteTank: false, killBlackTank: false, have1000Score: false, pass5LevelsWithoutDying: false }; storage.achievements = achievements; // Achievement tracking variables var totalEnemiesAtStart = 0; var hasUsedMedkit = false; var hasKilledEnemy = false; var hasBeenHurt = false; var totalEnemiesKilled = storage.totalEnemiesKilled || 0; var hasKilledWhiteTank = storage.hasKilledWhiteTank || false; var hasKilledBlackTank = storage.hasKilledBlackTank || false; var levelsWithoutDying = storage.levelsWithoutDying || 0; var hasReachedScore1000 = storage.hasReachedScore1000 || false; // Keyboard movement variables var keys = { w: false, a: false, s: false, d: false }; // Keyboard controls are not supported in LK sandbox environment // Movement is handled via touch/drag controls only // Create disarm button (initially hidden) disarmButton = new Text2('DISARM', { size: 40, fill: 0xFFFFFF, font: "monospace" }); disarmButton.anchor.set(0, 1); disarmButton.x = 20; disarmButton.y = -20; disarmButton.visible = false; LK.gui.bottomLeft.addChild(disarmButton); // Disarm button background var disarmButtonBg = LK.getAsset('wall', { anchorX: 0, anchorY: 1, scaleX: 2.5, scaleY: 0.8, tint: 0x333333, alpha: 0.8 }); disarmButtonBg.x = 10; disarmButtonBg.y = -10; disarmButtonBg.visible = false; LK.gui.bottomLeft.addChild(disarmButtonBg); // Disarm button click handler disarmButton.down = function (x, y, obj) { if (currentNearbyTrap && currentNearbyTrap.isArmed) { currentNearbyTrap.destroy(); var index = bearTraps.indexOf(currentNearbyTrap); if (index > -1) { bearTraps.splice(index, 1); } disarmButton.visible = false; disarmButtonBg.visible = false; currentNearbyTrap = null; LK.getSound('hit').play(); } }; // Achievement text elements var achievement1Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement1Text.anchor.set(0, 0.5); achievement1Text.x = -300; achievement1Text.y = -200; achievementMenu.addChild(achievement1Text); var achievement2Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement2Text.anchor.set(0, 0.5); achievement2Text.x = -300; achievement2Text.y = -100; achievementMenu.addChild(achievement2Text); var achievement3Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement3Text.anchor.set(0, 0.5); achievement3Text.x = -300; achievement3Text.y = 0; achievementMenu.addChild(achievement3Text); var achievement4Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement4Text.anchor.set(0, 0.5); achievement4Text.x = -300; achievement4Text.y = 100; achievementMenu.addChild(achievement4Text); var achievement5Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement5Text.anchor.set(0, 0.5); achievement5Text.x = -300; achievement5Text.y = 200; achievementMenu.addChild(achievement5Text); var achievement6Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement6Text.anchor.set(0, 0.5); achievement6Text.x = -300; achievement6Text.y = 300; achievementMenu.addChild(achievement6Text); var achievement7Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement7Text.anchor.set(0, 0.5); achievement7Text.x = -300; achievement7Text.y = 400; achievementMenu.addChild(achievement7Text); var achievement8Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement8Text.anchor.set(0, 0.5); achievement8Text.x = -300; achievement8Text.y = 500; achievementMenu.addChild(achievement8Text); function updateAchievementTexts() { achievement1Text.setText('Kill A White Tank - ' + (achievements.killWhiteTank ? 'DONE' : 'NOT DONE')); achievement2Text.setText('Kill A Black Tank - ' + (achievements.killBlackTank ? 'DONE' : 'NOT DONE')); achievement3Text.setText('Have 1000 Score - ' + (achievements.have1000Score ? 'DONE' : 'NOT DONE')); achievement4Text.setText('Pass 5 Levels Without Dying - ' + (achievements.pass5LevelsWithoutDying ? 'DONE' : 'NOT DONE')); achievement5Text.setText('Kill all enemies in map - ' + (achievements.killAllEnemies ? 'DONE' : 'NOT DONE')); achievement6Text.setText('Use your first MedKit - ' + (achievements.useFirstMedkit ? 'DONE' : 'NOT DONE')); achievement7Text.setText('Kill your first enemy - ' + (achievements.killFirstEnemy ? 'DONE' : 'NOT DONE')); achievement8Text.setText('Finish a level without dying - ' + (achievements.finishWithoutDying ? 'DONE' : 'NOT DONE')); // Set colors for achievement text - green for DONE, red for NOT DONE if (achievements.killWhiteTank) { achievement1Text.fill = 0x00FF00; achievement1Text.tint = 0x00FF00; } else { achievement1Text.fill = 0xFF0000; achievement1Text.tint = 0xFF0000; } if (achievements.killBlackTank) { achievement2Text.fill = 0x00FF00; achievement2Text.tint = 0x00FF00; } else { achievement2Text.fill = 0xFF0000; achievement2Text.tint = 0xFF0000; } if (achievements.have1000Score) { achievement3Text.fill = 0x00FF00; achievement3Text.tint = 0x00FF00; } else { achievement3Text.fill = 0xFF0000; achievement3Text.tint = 0xFF0000; } if (achievements.pass5LevelsWithoutDying) { achievement4Text.fill = 0x00FF00; achievement4Text.tint = 0x00FF00; } else { achievement4Text.fill = 0xFF0000; achievement4Text.tint = 0xFF0000; } if (achievements.killAllEnemies) { achievement5Text.fill = 0x00FF00; achievement5Text.tint = 0x00FF00; } else { achievement5Text.fill = 0xFF0000; achievement5Text.tint = 0xFF0000; } if (achievements.useFirstMedkit) { achievement6Text.fill = 0x00FF00; achievement6Text.tint = 0x00FF00; } else { achievement6Text.fill = 0xFF0000; achievement6Text.tint = 0xFF0000; } if (achievements.killFirstEnemy) { achievement7Text.fill = 0x00FF00; achievement7Text.tint = 0x00FF00; } else { achievement7Text.fill = 0xFF0000; achievement7Text.tint = 0xFF0000; } if (achievements.finishWithoutDying) { achievement8Text.fill = 0x00FF00; achievement8Text.tint = 0x00FF00; } else { achievement8Text.fill = 0xFF0000; achievement8Text.tint = 0xFF0000; } } // Initial text update updateAchievementTexts(); // Achievement button click handler achievementButton.down = function (x, y, obj) { achievementMenu.visible = !achievementMenu.visible; gamePaused = achievementMenu.visible; updateAchievementTexts(); }; // Close menu when clicking background menuBackground.down = function (x, y, obj) { achievementMenu.visible = false; gamePaused = false; }; function generateMaze() { walls = []; var playerTankX = 1024; var playerTankY = 1366; // Set background color based on map style if (mapStyle === 'lava') { game.setBackgroundColor(0xFF4500); // Orange background } else if (mapStyle === 'ice') { game.setBackgroundColor(0x0000FF); // Blue background } else { game.setBackgroundColor(0x2F4F2F); // Green background } for (var x = 0; x < gridWidth; x++) { for (var y = 0; y < gridHeight; y++) { var wallX = x * cellSize + cellSize / 2; var wallY = y * cellSize + cellSize / 2; // Check if this wall position would be too close to player tank position var dx = Math.abs(wallX - playerTankX); var dy = Math.abs(wallY - playerTankY); var isNearPlayerTank = dx < 64 && dy < 64; // Within one cell distance if (x === 0 || x === gridWidth - 1 || y === 0 || y === gridHeight - 1) { if (!isNearPlayerTank) { var wall = new Wall(); // Change wall appearance based on map style if (mapStyle === 'lava') { wall.attachAsset('lavaWall', { anchorX: 0.5, anchorY: 0.5 }); } else if (mapStyle === 'ice') { wall.attachAsset('iceWall', { anchorX: 0.5, anchorY: 0.5 }); } wall.x = wallX; wall.y = wallY; walls.push(wall); game.addChild(wall); } } else if (Math.random() < 0.3 && !isNearPlayerTank) { var wall = new Wall(); // Change wall appearance based on map style if (mapStyle === 'lava') { wall.attachAsset('lavaWall', { anchorX: 0.5, anchorY: 0.5 }); } else if (mapStyle === 'ice') { wall.attachAsset('iceWall', { anchorX: 0.5, anchorY: 0.5 }); } wall.x = wallX; wall.y = wallY; walls.push(wall); game.addChild(wall); } } } } function spawnEnemies() { if (mapStyle === 'normal') { var skinCount = Math.floor(Math.random() * 6) + 10; // 10-15 skin tanks var redCount = Math.floor(Math.random() * 6) + 5; // 5-10 red tanks var greenCount = Math.floor(Math.random() * 6) + 7; // 7-12 green tanks for (var i = 0; i < skinCount; i++) { var tank = new SkinTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); skinTanks.push(tank); game.addChild(tank); } for (var i = 0; i < redCount; i++) { var tank = new RedTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); redTanks.push(tank); game.addChild(tank); } for (var i = 0; i < greenCount; i++) { var tank = new GreenTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); greenTanks.push(tank); game.addChild(tank); } } else if (mapStyle === 'lava') { var whiteCount = Math.floor(Math.random() * 3) + 2; // 2-4 white tanks var blackCount = Math.floor(Math.random() * 3) + 1; // 1-3 black tanks var orangeCount = Math.floor(Math.random() * 4) + 3; // 3-6 orange tanks for (var i = 0; i < whiteCount; i++) { var tank = new WhiteTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); whiteTanks.push(tank); game.addChild(tank); } for (var i = 0; i < blackCount; i++) { var tank = new BlackTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); blackTanks.push(tank); game.addChild(tank); } for (var i = 0; i < orangeCount; i++) { var tank = new OrangeTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); orangeTanks.push(tank); game.addChild(tank); } } else if (mapStyle === 'ice') { var blueCount = Math.floor(Math.random() * 4) + 3; // 3-6 blue tanks var iceCount = Math.floor(Math.random() * 5) + 5; // 5-9 ice tanks for (var i = 0; i < blueCount; i++) { var tank = new BlueTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); blueTanks.push(tank); game.addChild(tank); } for (var i = 0; i < iceCount; i++) { var tank = new IceTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); iceTanks.push(tank); game.addChild(tank); } } } function checkWallCollision(x, y) { for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var dx = Math.abs(x - wall.x); var dy = Math.abs(y - wall.y); if (dx < 32 && dy < 32) { return true; } } return false; } function getDistanceToPlayer(x, y) { if (!playerTank) { return 1000; } var dx = x - playerTank.x; var dy = y - playerTank.y; return Math.sqrt(dx * dx + dy * dy); } function canReachPosition(startX, startY, targetX, targetY) { // Create a grid to track visited positions var visited = {}; var queue = [{ x: startX, y: startY }]; var gridSize = 32; // Step size for pathfinding var maxDistance = 100; // Maximum distance to consider reachable // Simple flood-fill algorithm to check connectivity while (queue.length > 0) { var current = queue.shift(); var key = Math.floor(current.x / gridSize) + ',' + Math.floor(current.y / gridSize); if (visited[key]) continue; visited[key] = true; // Check if we've reached the target var dx = current.x - targetX; var dy = current.y - targetY; if (Math.abs(dx) < maxDistance && Math.abs(dy) < maxDistance) { return true; } // Add neighboring positions to queue if they're not blocked var directions = [{ x: gridSize, y: 0 }, { x: -gridSize, y: 0 }, { x: 0, y: gridSize }, { x: 0, y: -gridSize }]; for (var i = 0; i < directions.length; i++) { var newX = current.x + directions[i].x; var newY = current.y + directions[i].y; // Check bounds if (newX < 100 || newX > 1948 || newY < 100 || newY > 2632) continue; // Check if position is blocked by walls if (!checkWallCollision(newX, newY)) { queue.push({ x: newX, y: newY }); } } // Limit search to prevent infinite loops if (Object.keys(visited).length > 500) break; } return false; } function spawnMedkits() { var medkitCount = Math.floor(Math.random() * 4) + 3; // 3-6 medkits per level for (var i = 0; i < medkitCount; i++) { var medkit = new Medkit(); do { medkit.x = Math.random() * (2048 - 200) + 100; medkit.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(medkit.x, medkit.y) || getDistanceToPlayer(medkit.x, medkit.y) < 150); medkits.push(medkit); game.addChild(medkit); } } function spawnBearTraps() { var trapCount = Math.floor(Math.random() * 3) + 2; // 2-4 bear traps per level for (var i = 0; i < trapCount; i++) { var bearTrap = new BearTrap(); do { bearTrap.x = Math.random() * (2048 - 200) + 100; bearTrap.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(bearTrap.x, bearTrap.y) || getDistanceToPlayer(bearTrap.x, bearTrap.y) < 200); bearTraps.push(bearTrap); game.addChild(bearTrap); } } function createExplosion(x, y, radius, damage) { var explosion = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5, x: x, y: y, scaleX: radius / 60, scaleY: radius / 60, alpha: 0.8 }); game.addChild(explosion); explosions.push(explosion); tween(explosion, { alpha: 0, scaleX: explosion.scaleX * 1.5, scaleY: explosion.scaleY * 1.5 }, { duration: 500, onFinish: function onFinish() { explosion.destroy(); var index = explosions.indexOf(explosion); if (index > -1) { explosions.splice(index, 1); } } }); var dx = playerTank.x - x; var dy = playerTank.y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < radius) { playerTank.health -= damage; LK.getSound('hit').play(); // Track that player has been hurt hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } } LK.getSound('explosion').play(); } function startLevel() { for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); } walls = []; for (var i = skinTanks.length - 1; i >= 0; i--) { skinTanks[i].destroy(); } skinTanks = []; for (var i = redTanks.length - 1; i >= 0; i--) { redTanks[i].destroy(); } redTanks = []; for (var i = greenTanks.length - 1; i >= 0; i--) { greenTanks[i].destroy(); } greenTanks = []; for (var i = medkits.length - 1; i >= 0; i--) { medkits[i].destroy(); } medkits = []; for (var i = whiteTanks.length - 1; i >= 0; i--) { whiteTanks[i].destroy(); } whiteTanks = []; for (var i = blackTanks.length - 1; i >= 0; i--) { blackTanks[i].destroy(); } blackTanks = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; generateMaze(); spawnEnemies(); spawnMedkits(); spawnBearTraps(); // Hide disarm button when starting new level disarmButton.visible = false; disarmButtonBg.visible = false; currentNearbyTrap = null; // Track total enemies for achievement totalEnemiesAtStart = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length + orangeTanks.length + blueTanks.length + iceTanks.length; // Reset achievement tracking variables hasUsedMedkit = false; hasKilledEnemy = false; hasBeenHurt = false; // Reset hard mode portal tracking firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; // Only create player tank if it doesn't exist (first level) if (!playerTank) { playerTank = new PlayerTank(); playerTank.x = 1024; playerTank.y = 1366; playerTank.health = 100; game.addChild(playerTank); } else { // Just reset position and health for existing player tank playerTank.x = 1024; playerTank.y = 1366; playerTank.health = 100; } portal = new Portal(); var attempts = 0; var maxAttempts = 50; do { portal.x = Math.random() * (2048 - 200) + 100; portal.y = Math.random() * (2732 - 200) + 100; attempts++; // If we can't find a reachable position after many attempts, reduce wall density if (attempts > maxAttempts) { // Remove some random walls to create more open paths for (var i = walls.length - 1; i >= 0 && walls.length > 20; i--) { if (Math.random() < 0.1) { walls[i].destroy(); walls.splice(i, 1); } } attempts = 0; } } while ((checkWallCollision(portal.x, portal.y) || getDistanceToPlayer(portal.x, portal.y) < 300 || !canReachPosition(playerTank.x, playerTank.y, portal.x, portal.y)) && attempts < maxAttempts); game.addChild(portal); levelText.setText('Level: ' + currentLevel); gameStarted = true; // Achievement: Arrive at level 3 if (currentLevel >= 3 && !achievements.arriveAtLevel3) { achievements.arriveAtLevel3 = true; storage.achievements = achievements; } } // Mouse functionality - player tank follows mouse position game.down = function (x, y, obj) { // Only start dragging if mouse is pressed on the player tank and achievements menu is not visible and next level screen is not visible if (playerTank && playerTank.x && playerTank.y && !achievementMenu.visible && !nextLevelScreen.visible) { var dx = x - playerTank.x; var dy = y - playerTank.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= 60) { // Within tank radius (tank is 120px wide, so radius ~60) isDragging = true; } } }; game.move = function (x, y, obj) { if (!gameStarted || !playerTank || !isDragging || achievementMenu.visible || nextLevelScreen.visible) { return; } // Only allow dragging if mouse is not on a wall if (checkWallCollision(x, y)) { isDragging = false; // Stop dragging when mouse is on wall return; } // Calculate direction from tank to mouse for rotation var dx = x - playerTank.x; var dy = y - playerTank.y; var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(playerTank, { rotation: true }); // Smoothly rotate the tank to face the mouse direction tween(playerTank, { rotation: targetAngle }, { duration: 200, easing: tween.easeOut }); // Move player tank directly to mouse position if no wall collision playerTank.x = x; playerTank.y = y; }; game.up = function (x, y, obj) { isDragging = false; if (!gameStarted || !playerTank || achievementMenu.visible || nextLevelScreen.visible) { return; } if (playerTank.shootCooldown <= 0) { var dx = x - playerTank.x; var dy = y - playerTank.y; var length = Math.sqrt(dx * dx + dy * dy); if (length > 0) { // Calculate the angle to face the shooting direction var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(playerTank, { rotation: true }); // Rotate the tank to face the shooting direction tween(playerTank, { rotation: targetAngle }, { duration: 200, easing: tween.easeOut }); var dirX = dx / length; var dirY = dy / length; var bullet = new PlayerBullet(); bullet.x = playerTank.x; bullet.y = playerTank.y; bullet.directionX = dirX; bullet.directionY = dirY; playerBullets.push(bullet); game.addChild(bullet); playerTank.shootCooldown = 15; LK.getSound('shoot').play(); } } }; // Game Over screen setup var gameOverHandled = false; // Override LK.showGameOver to add custom functionality var originalShowGameOver = LK.showGameOver; LK.showGameOver = function () { if (!gameOverHandled) { gameOverHandled = true; // Create game over screen with return to main menu button var gameOverScreen = new Container(); gameOverScreen.visible = true; LK.gui.center.addChild(gameOverScreen); // Game over background var gameOverBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 12, scaleY: 8, tint: 0x000000, alpha: 0.9 }); gameOverScreen.addChild(gameOverBackground); // Game Over text var gameOverText = new Text2('GAME OVER', { size: 80, fill: 0xFF0000, font: "monospace" }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 0; gameOverText.y = -50; gameOverScreen.addChild(gameOverText); // Return to main menu button for game over var gameOverReturnButton = new Text2('RETURN TO MAIN MENU', { size: 60, fill: 0xFFFFFF, font: "monospace" }); gameOverReturnButton.anchor.set(0.5, 0.5); gameOverReturnButton.x = 0; gameOverReturnButton.y = 50; gameOverScreen.addChild(gameOverReturnButton); // Return to main menu button click handler for game over gameOverReturnButton.down = function (x, y, obj) { // Clear all game objects for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); } walls = []; for (var i = skinTanks.length - 1; i >= 0; i--) { skinTanks[i].destroy(); } skinTanks = []; for (var i = redTanks.length - 1; i >= 0; i--) { redTanks[i].destroy(); } redTanks = []; for (var i = greenTanks.length - 1; i >= 0; i--) { greenTanks[i].destroy(); } greenTanks = []; for (var i = medkits.length - 1; i >= 0; i--) { medkits[i].destroy(); } medkits = []; for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = dynamites.length - 1; i >= 0; i--) { dynamites[i].destroy(); } dynamites = []; for (var i = acidBombs.length - 1; i >= 0; i--) { acidBombs[i].destroy(); } acidBombs = []; for (var i = explosions.length - 1; i >= 0; i--) { explosions[i].destroy(); } explosions = []; for (var i = whiteTanks.length - 1; i >= 0; i--) { whiteTanks[i].destroy(); } whiteTanks = []; for (var i = blackTanks.length - 1; i >= 0; i--) { blackTanks[i].destroy(); } blackTanks = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; // Destroy player tank and portal if they exist if (playerTank) { playerTank.destroy(); playerTank = null; } if (portal) { portal.destroy(); portal = null; } // Reset game state currentLevel = 1; gameStarted = false; isDragging = false; gamePaused = false; showingMainMenu = true; gameOverHandled = false; levelsWithoutDying = 0; storage.levelsWithoutDying = levelsWithoutDying; firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; LK.setScore(0); // Hide game over screen and show main menu gameOverScreen.destroy(); mainMenu.visible = true; }; // Auto-hide after 3 seconds and call original game over LK.setTimeout(function () { gameOverScreen.destroy(); originalShowGameOver(); }, 3000); } else { originalShowGameOver(); } }; game.update = function () { if (showingMainMenu) { return; } if (!gameStarted) { return; } if (gamePaused) { return; } // Movement is handled via touch/drag in game.move method only // Keyboard controls are not supported in LK sandbox environment // Movement is handled via touch/drag in game.move method and WASD keys for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); playerBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); playerBullets.splice(i, 1); continue; } for (var j = skinTanks.length - 1; j >= 0; j--) { if (bullet.intersects(skinTanks[j])) { skinTanks[j].health -= 3; bullet.destroy(); playerBullets.splice(i, 1); if (skinTanks[j].health <= 0) { createExplosion(skinTanks[j].x, skinTanks[j].y, 100, 15); skinTanks[j].destroy(); skinTanks.splice(j, 1); LK.setScore(LK.getScore() + 10); // Track total enemies killed totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; // Achievement: Kill first enemy if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } // Achievement: Kill 50 enemies total if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } } break; } } for (var j = redTanks.length - 1; j >= 0; j--) { if (bullet.intersects(redTanks[j])) { redTanks[j].health -= 10; bullet.destroy(); playerBullets.splice(i, 1); if (redTanks[j].health <= 0) { redTanks[j].destroy(); redTanks.splice(j, 1); LK.setScore(LK.getScore() + 20); // Track total enemies killed totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; // Achievement: Kill first enemy if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } // Achievement: Kill 50 enemies total if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } } break; } } for (var j = greenTanks.length - 1; j >= 0; j--) { if (bullet.intersects(greenTanks[j])) { greenTanks[j].health -= 25; bullet.destroy(); playerBullets.splice(i, 1); if (greenTanks[j].health <= 0) { greenTanks[j].destroy(); greenTanks.splice(j, 1); LK.setScore(LK.getScore() + 30); // Track total enemies killed totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; // Achievement: Kill first enemy if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } // Achievement: Kill 50 enemies total if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } } break; } } for (var j = whiteTanks.length - 1; j >= 0; j--) { if (bullet.intersects(whiteTanks[j])) { whiteTanks[j].health -= 25; bullet.destroy(); playerBullets.splice(i, 1); if (whiteTanks[j].health <= 0) { whiteTanks[j].destroy(); whiteTanks.splice(j, 1); LK.setScore(LK.getScore() + 40); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } // Achievement: Kill a white tank if (!hasKilledWhiteTank) { hasKilledWhiteTank = true; storage.hasKilledWhiteTank = hasKilledWhiteTank; achievements.killWhiteTank = true; storage.achievements = achievements; } } break; } } for (var j = blackTanks.length - 1; j >= 0; j--) { if (bullet.intersects(blackTanks[j])) { blackTanks[j].health -= 25; bullet.destroy(); playerBullets.splice(i, 1); if (blackTanks[j].health <= 0) { blackTanks[j].destroy(); blackTanks.splice(j, 1); LK.setScore(LK.getScore() + 50); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } // Achievement: Kill a black tank if (!hasKilledBlackTank) { hasKilledBlackTank = true; storage.hasKilledBlackTank = hasKilledBlackTank; achievements.killBlackTank = true; storage.achievements = achievements; } } break; } } } for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } if (bullet.intersects(playerTank)) { var damage = hardModeEnabled ? bullet.damage * 2 : bullet.damage; playerTank.health -= damage; bullet.destroy(); enemyBullets.splice(i, 1); LK.getSound('hit').play(); // Track that player has been hurt hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } for (var i = dynamites.length - 1; i >= 0; i--) { var dynamite = dynamites[i]; if (dynamite.x < 0 || dynamite.x > 2048 || dynamite.y < 0 || dynamite.y > 2732) { createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage); dynamite.destroy(); dynamites.splice(i, 1); continue; } if (checkWallCollision(dynamite.x, dynamite.y)) { createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage); dynamite.destroy(); dynamites.splice(i, 1); continue; } if (dynamite.intersects(playerTank)) { createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage); dynamite.destroy(); dynamites.splice(i, 1); continue; } } for (var i = acidBombs.length - 1; i >= 0; i--) { var acidBomb = acidBombs[i]; if (acidBomb.x < 0 || acidBomb.x > 2048 || acidBomb.y < 0 || acidBomb.y > 2732) { acidBomb.destroy(); acidBombs.splice(i, 1); continue; } if (checkWallCollision(acidBomb.x, acidBomb.y)) { acidBomb.destroy(); acidBombs.splice(i, 1); continue; } if (acidBomb.intersects(playerTank)) { var damage = hardModeEnabled ? acidBomb.damage * 2 : acidBomb.damage; var poisonDamage = hardModeEnabled ? acidBomb.poisonDamage * 2 : acidBomb.poisonDamage; playerTank.health -= damage; playerTank.poisonTimer = acidBomb.poisonDuration; playerTank.poisonDamage = poisonDamage; acidBomb.destroy(); acidBombs.splice(i, 1); LK.getSound('hit').play(); // Track that player has been hurt hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } // Handle white bullets for (var i = whiteBullets.length - 1; i >= 0; i--) { var bullet = whiteBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); whiteBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); whiteBullets.splice(i, 1); continue; } if (bullet.intersects(playerTank)) { // Create electric field var electricField = new ElectricField(); electricField.x = bullet.x; electricField.y = bullet.y; electricFields.push(electricField); game.addChild(electricField); bullet.destroy(); whiteBullets.splice(i, 1); LK.getSound('explosion').play(); continue; } } // Handle black bullets for (var i = blackBullets.length - 1; i >= 0; i--) { var bullet = blackBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); blackBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); blackBullets.splice(i, 1); continue; } if (bullet.intersects(playerTank)) { // Create black hole var blackHole = new BlackHole(); blackHole.x = bullet.x; blackHole.y = bullet.y; blackHoles.push(blackHole); game.addChild(blackHole); bullet.destroy(); blackBullets.splice(i, 1); LK.getSound('explosion').play(); continue; } // Check collision with white bullets for (var j = whiteBullets.length - 1; j >= 0; j--) { if (bullet.intersects(whiteBullets[j])) { // Create black hole from black bullet var blackHole = new BlackHole(); blackHole.x = bullet.x; blackHole.y = bullet.y; blackHoles.push(blackHole); game.addChild(blackHole); // Create electric field from white bullet var electricField = new ElectricField(); electricField.x = whiteBullets[j].x; electricField.y = whiteBullets[j].y; electricFields.push(electricField); game.addChild(electricField); // Destroy both bullets bullet.destroy(); blackBullets.splice(i, 1); whiteBullets[j].destroy(); whiteBullets.splice(j, 1); LK.getSound('explosion').play(); break; } } } for (var i = skinTanks.length - 1; i >= 0; i--) { if (skinTanks[i].intersects(playerTank)) { createExplosion(skinTanks[i].x, skinTanks[i].y, skinTanks[i].explosionRadius, 20); skinTanks[i].destroy(); skinTanks.splice(i, 1); } } for (var i = redTanks.length - 1; i >= 0; i--) { if (redTanks[i].intersects(playerTank)) { // Check if any part of player is within circular explosion area (radius 100) // Player tank is 120px wide, so radius is 60px var dx = playerTank.x - redTanks[i].x; var dy = playerTank.y - redTanks[i].y; var distance = Math.sqrt(dx * dx + dy * dy); var playerRadius = 60; // Half of player tank width (120px) var explosionRadius = 100; // Check if there's a clear path from explosion center to player (no walls blocking) var canDamagePlayer = true; var stepSize = 32; // Check every 32 pixels along the path var steps = Math.ceil(distance / stepSize); for (var step = 1; step <= steps; step++) { var checkX = redTanks[i].x + dx * step / steps; var checkY = redTanks[i].y + dy * step / steps; if (checkWallCollision(checkX, checkY)) { canDamagePlayer = false; break; } } if (distance <= explosionRadius + playerRadius && canDamagePlayer) { // Any part of player is within explosion radius and no walls block - deal 70 damage playerTank.health -= 70; LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } } createExplosion(redTanks[i].x, redTanks[i].y, 100, 0); // No additional damage from explosion redTanks[i].destroy(); redTanks.splice(i, 1); } } // Check medkit collision for healing for (var i = medkits.length - 1; i >= 0; i--) { var medkit = medkits[i]; var dx = playerTank.x - medkit.x; var dy = playerTank.y - medkit.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50 && playerTank.health < playerTank.maxHealth) { // Close enough to collect medkit and player needs healing playerTank.health = playerTank.maxHealth; // Restore to full health medkit.destroy(); medkits.splice(i, 1); LK.getSound('hit').play(); // Use existing sound for medkit pickup // Achievement: Use first medkit if (!hasUsedMedkit) { hasUsedMedkit = true; achievements.useFirstMedkit = true; storage.achievements = achievements; } } } // Check bear trap collision and proximity var nearbyTrap = null; for (var i = bearTraps.length - 1; i >= 0; i--) { var bearTrap = bearTraps[i]; if (!bearTrap.isArmed) continue; var dx = playerTank.x - bearTrap.x; var dy = playerTank.y - bearTrap.y; var distance = Math.sqrt(dx * dx + dy * dy); // Direct collision - damage player and destroy trap if (distance < 40) { var damage = hardModeEnabled ? bearTrap.damage * 2 : bearTrap.damage; playerTank.health -= damage; hasBeenHurt = true; LK.getSound('hit').play(); bearTrap.destroy(); bearTraps.splice(i, 1); if (playerTank.health <= 0) { LK.showGameOver(); } continue; } // Near but not touching - show disarm button if (distance < 100 && distance >= 40) { nearbyTrap = bearTrap; } } // Update disarm button visibility if (nearbyTrap && nearbyTrap !== currentNearbyTrap) { currentNearbyTrap = nearbyTrap; disarmButton.visible = true; disarmButtonBg.visible = true; } else if (!nearbyTrap && currentNearbyTrap) { currentNearbyTrap = null; disarmButton.visible = false; disarmButtonBg.visible = false; } // Check if player is close to portal (within 100 pixels) var dx = playerTank.x - portal.x; var dy = playerTank.y - portal.y; var distanceToPortal = Math.sqrt(dx * dx + dy * dy); if (distanceToPortal < 100) { if (hardModeEnabled && !firstPortalUsed) { // In hard mode, first portal disappears and creates a new one firstPortalUsed = true; previousPortalX = portal.x; previousPortalY = portal.y; portal.destroy(); // Create new portal in a different location var newPortal = new Portal(); var attempts = 0; var maxAttempts = 50; do { newPortal.x = Math.random() * (2048 - 200) + 100; newPortal.y = Math.random() * (2732 - 200) + 100; attempts++; // If we can't find a reachable position after many attempts, reduce wall density if (attempts > maxAttempts) { // Remove some random walls to create more open paths for (var i = walls.length - 1; i >= 0 && walls.length > 20; i--) { if (Math.random() < 0.1) { walls[i].destroy(); walls.splice(i, 1); } } attempts = 0; } } while ((checkWallCollision(newPortal.x, newPortal.y) || getDistanceToPlayer(newPortal.x, newPortal.y) < 300 || Math.abs(newPortal.x - previousPortalX) < 200 && Math.abs(newPortal.y - previousPortalY) < 200 || !canReachPosition(playerTank.x, playerTank.y, newPortal.x, newPortal.y)) && attempts < maxAttempts); portal = newPortal; game.addChild(portal); return; } // Achievement: Kill all enemies in map var totalEnemiesRemaining = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length + orangeTanks.length + blueTanks.length + iceTanks.length; if (totalEnemiesRemaining === 0) { achievements.killAllEnemies = true; storage.achievements = achievements; } // Achievement: Finish without dying if (!hasBeenHurt) { achievements.finishWithoutDying = true; storage.achievements = achievements; // Track consecutive levels without dying levelsWithoutDying++; storage.levelsWithoutDying = levelsWithoutDying; // Achievement: Pass 5 levels without dying if (levelsWithoutDying >= 5 && !achievements.pass5LevelsWithoutDying) { achievements.pass5LevelsWithoutDying = true; storage.achievements = achievements; } } else { // Reset consecutive levels counter if player was hurt levelsWithoutDying = 0; storage.levelsWithoutDying = levelsWithoutDying; } LK.getSound('win').play(); // Clear current level enemies and bullets for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = dynamites.length - 1; i >= 0; i--) { dynamites[i].destroy(); } dynamites = []; for (var i = acidBombs.length - 1; i >= 0; i--) { acidBombs[i].destroy(); } acidBombs = []; for (var i = explosions.length - 1; i >= 0; i--) { explosions[i].destroy(); } explosions = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; // Hide disarm button when completing level disarmButton.visible = false; disarmButtonBg.visible = false; currentNearbyTrap = null; // Remove current portal portal.destroy(); // Reset portal tracking for next level firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; // Advance to next level currentLevel++; // Show next level screen nextLevelScreen.visible = true; gamePaused = true; } // Spawn falling fireballs in lava map style if (mapStyle === 'lava' && Math.random() < 0.001) { // Very rare spawn var fallingFireball = new FallingFireball(); fallingFireball.targetX = playerTank.x + (Math.random() - 0.5) * 200; // Around player position fallingFireball.targetY = playerTank.y + (Math.random() - 0.5) * 200; fallingFireballs.push(fallingFireball); game.addChild(fallingFireball); } // Handle fire signs damage for (var i = fireSigns.length - 1; i >= 0; i--) { var fireSign = fireSigns[i]; var dx = playerTank.x - fireSign.x; var dy = playerTank.y - fireSign.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 32 && fireSign.damageTimer >= 60) { // Every second var damage = hardModeEnabled ? fireSign.damage * 2 : fireSign.damage; playerTank.health -= damage; fireSign.damageTimer = 0; hasBeenHurt = true; LK.getSound('hit').play(); if (playerTank.health <= 0) { LK.showGameOver(); } } } // Handle fireballs for (var i = fireballs.length - 1; i >= 0; i--) { var fireball = fireballs[i]; if (fireball.x < 0 || fireball.x > 2048 || fireball.y < 0 || fireball.y > 2732) { fireball.destroy(); fireballs.splice(i, 1); continue; } if (checkWallCollision(fireball.x, fireball.y)) { fireball.destroy(); fireballs.splice(i, 1); continue; } if (fireball.intersects(playerTank)) { var damage = hardModeEnabled ? fireball.damage * 2 : fireball.damage; playerTank.health -= damage; fireball.destroy(); fireballs.splice(i, 1); LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } // Handle waterballs for (var i = waterballs.length - 1; i >= 0; i--) { var waterball = waterballs[i]; if (waterball.x < 0 || waterball.x > 2048 || waterball.y < 0 || waterball.y > 2732) { waterball.destroy(); waterballs.splice(i, 1); continue; } if (checkWallCollision(waterball.x, waterball.y)) { waterball.destroy(); waterballs.splice(i, 1); continue; } if (waterball.intersects(playerTank)) { var damage = hardModeEnabled ? waterball.damage * 2 : waterball.damage; playerTank.health -= damage; // Create 8 smaller waterballs for (var j = 0; j < 8; j++) { var smallWaterball = new Waterball(); smallWaterball.x = waterball.x; smallWaterball.y = waterball.y; var angle = j / 8 * Math.PI * 2; smallWaterball.directionX = Math.cos(angle); smallWaterball.directionY = Math.sin(angle); smallWaterball.speed = 2; smallWaterball.damage = hardModeEnabled ? 2 : 1; waterballs.push(smallWaterball); game.addChild(smallWaterball); } waterball.destroy(); waterballs.splice(i, 1); LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } // Check if small waterballs hit other tanks for (var j = orangeTanks.length - 1; j >= 0; j--) { if (waterball.intersects(orangeTanks[j])) { orangeTanks[j].targetPlayer = false; // Stop attacking player waterball.destroy(); waterballs.splice(i, 1); break; } } } // Handle ice blocks for (var i = iceBlocks.length - 1; i >= 0; i--) { var iceBlock = iceBlocks[i]; if (iceBlock.x < 0 || iceBlock.x > 2048 || iceBlock.y < 0 || iceBlock.y > 2732) { iceBlock.destroy(); iceBlocks.splice(i, 1); continue; } if (checkWallCollision(iceBlock.x, iceBlock.y)) { iceBlock.destroy(); iceBlocks.splice(i, 1); continue; } if (iceBlock.intersects(playerTank)) { var damage = hardModeEnabled ? iceBlock.damage * 2 : iceBlock.damage; playerTank.health -= damage; iceBlock.destroy(); iceBlocks.splice(i, 1); LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } // Handle orange tank collisions with player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; for (var j = orangeTanks.length - 1; j >= 0; j--) { if (bullet.intersects(orangeTanks[j])) { orangeTanks[j].health -= 5; bullet.destroy(); playerBullets.splice(i, 1); if (orangeTanks[j].health <= 0) { orangeTanks[j].destroy(); orangeTanks.splice(j, 1); LK.setScore(LK.getScore() + 35); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } } break; } } for (var j = blueTanks.length - 1; j >= 0; j--) { if (bullet.intersects(blueTanks[j])) { blueTanks[j].health -= 3; bullet.destroy(); playerBullets.splice(i, 1); if (blueTanks[j].health <= 0) { blueTanks[j].destroy(); blueTanks.splice(j, 1); LK.setScore(LK.getScore() + 25); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } } break; } } for (var j = iceTanks.length - 1; j >= 0; j--) { if (bullet.intersects(iceTanks[j])) { iceTanks[j].health -= 25; // Show breaking animation tween(iceTanks[j], { alpha: 0.5, scaleX: 0.8, scaleY: 0.8 }, { duration: 200, onFinish: function onFinish() { tween(iceTanks[j], { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); bullet.destroy(); playerBullets.splice(i, 1); if (iceTanks[j].health <= 0) { iceTanks[j].destroy(); iceTanks.splice(j, 1); LK.setScore(LK.getScore() + 15); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } } break; } } } // Update score display scoreText.setText('Score: ' + LK.getScore()); // Update best score if current score is higher var currentScore = LK.getScore(); var bestScore = storage.bestScore || 0; if (currentScore > bestScore) { storage.bestScore = currentScore; bestScoreText.setText('Best: ' + currentScore); // Achievement: Beat previous best score if (bestScore > 0) { achievements.beatPreviousBest = true; storage.achievements = achievements; } } // Achievement: Get 150 Score if (currentScore >= 150 && !achievements.get150Score) { achievements.get150Score = true; storage.achievements = achievements; } // Achievement: Have 1000 Score if (currentScore >= 1000 && !hasReachedScore1000) { hasReachedScore1000 = true; storage.hasReachedScore1000 = hasReachedScore1000; achievements.have1000Score = true; storage.achievements = achievements; } var healthPercentage = Math.max(0, playerTank.health) / 100; healthBarFill.scaleX = 4 * healthPercentage; if (healthPercentage > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercentage > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AcidBomb = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('acidBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.directionX = 0;
self.directionY = 0;
self.damage = 5;
self.poisonDamage = 2;
self.poisonDuration = 180;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var BearTrap = Container.expand(function () {
var self = Container.call(this);
var trapGraphics = self.attachAsset('bearTrap', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 20;
self.isArmed = true;
return self;
});
var BlackBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('blackBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var BlackHole = Container.expand(function () {
var self = Container.call(this);
var holeGraphics = self.attachAsset('blackHole', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.radius = 64; // 1 block radius
self.duration = 300; // 5 seconds at 60fps
self.timer = 0;
self.damageTimer = 0;
self.pullStrength = 1.5;
self.update = function () {
if (gamePaused) {
return;
}
self.timer++;
self.damageTimer++;
// Pull and damage effects
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius * 2) {
// Pull player toward center
var pullX = dx > 0 ? -self.pullStrength : self.pullStrength;
var pullY = dy > 0 ? -self.pullStrength : self.pullStrength;
if (!checkWallCollision(playerTank.x + pullX, playerTank.y)) {
playerTank.x += pullX;
}
if (!checkWallCollision(playerTank.x, playerTank.y + pullY)) {
playerTank.y += pullY;
}
// Damage at center every second
if (distance <= 32 && self.damageTimer >= 60) {
playerTank.health -= 8;
hasBeenHurt = true;
LK.getSound('hit').play();
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
}
// Pull and damage enemies
for (var i = skinTanks.length - 1; i >= 0; i--) {
var dx = skinTanks[i].x - self.x;
var dy = skinTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius * 2) {
var pullX = dx > 0 ? -self.pullStrength : self.pullStrength;
var pullY = dy > 0 ? -self.pullStrength : self.pullStrength;
if (!checkWallCollision(skinTanks[i].x + pullX, skinTanks[i].y)) {
skinTanks[i].x += pullX;
}
if (!checkWallCollision(skinTanks[i].x, skinTanks[i].y + pullY)) {
skinTanks[i].y += pullY;
}
}
}
// Damage enemies every second
if (self.damageTimer >= 60) {
self.damageTimer = 0;
for (var i = skinTanks.length - 1; i >= 0; i--) {
var dx = skinTanks[i].x - self.x;
var dy = skinTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
skinTanks[i].health -= 2;
}
}
for (var i = redTanks.length - 1; i >= 0; i--) {
var dx = redTanks[i].x - self.x;
var dy = redTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
redTanks[i].health -= 4;
}
}
for (var i = greenTanks.length - 1; i >= 0; i--) {
var dx = greenTanks[i].x - self.x;
var dy = greenTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
greenTanks[i].health -= 15;
}
}
// White tanks die instantly
for (var i = whiteTanks.length - 1; i >= 0; i--) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
whiteTanks[i].destroy();
whiteTanks.splice(i, 1);
LK.setScore(LK.getScore() + 40);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
}
}
}
if (self.timer >= self.duration) {
self.destroy();
var index = blackHoles.indexOf(self);
if (index > -1) {
blackHoles.splice(index, 1);
}
}
};
return self;
});
var BlackTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('blackTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 225;
self.speed = 1;
self.shootCooldown = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
// Check if should target white tank instead (only if not in hard mode)
if (!hardModeEnabled) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase target if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing target
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var blackBullet = new BlackBullet();
blackBullet.x = self.x;
blackBullet.y = self.y;
blackBullet.directionX = dirX;
blackBullet.directionY = dirY;
blackBullets.push(blackBullet);
game.addChild(blackBullet);
self.shootCooldown = 120;
LK.getSound('shoot').play();
}
};
return self;
});
var BlueTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('blueTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 375;
self.speed = 1;
self.shootCooldown = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase player if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing player
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var waterball = new Waterball();
waterball.x = self.x;
waterball.y = self.y;
waterball.directionX = dirX;
waterball.directionY = dirY;
waterballs.push(waterball);
game.addChild(waterball);
self.shootCooldown = 90;
LK.getSound('shoot').play();
}
};
return self;
});
var Dynamite = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('dynamite', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.directionX = 0;
self.directionY = 0;
self.damage = 25;
self.explosionRadius = 80;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var ElectricField = Container.expand(function () {
var self = Container.call(this);
var fieldGraphics = self.attachAsset('electricField', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.radius = 160; // 2 blocks radius
self.duration = 300; // 5 seconds at 60fps
self.timer = 0;
self.damageTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
self.timer++;
self.damageTimer++;
// Damage every 60 frames (1 second)
if (self.damageTimer >= 60) {
self.damageTimer = 0;
// Check player damage
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
playerTank.health -= 2;
hasBeenHurt = true;
LK.getSound('hit').play();
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
// Check enemy damage and change targets
for (var i = skinTanks.length - 1; i >= 0; i--) {
var dx = skinTanks[i].x - self.x;
var dy = skinTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
skinTanks[i].health -= 0.5;
skinTanks[i].targetWhiteTank = true;
}
}
for (var i = redTanks.length - 1; i >= 0; i--) {
var dx = redTanks[i].x - self.x;
var dy = redTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
redTanks[i].health -= 2;
redTanks[i].targetWhiteTank = true;
}
}
for (var i = greenTanks.length - 1; i >= 0; i--) {
var dx = greenTanks[i].x - self.x;
var dy = greenTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
greenTanks[i].health -= 10;
greenTanks[i].targetWhiteTank = true;
}
}
}
if (self.timer >= self.duration) {
self.destroy();
var index = electricFields.indexOf(self);
if (index > -1) {
electricFields.splice(index, 1);
}
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var FallingFireball = Container.expand(function () {
var self = Container.call(this);
var fireballGraphics = self.attachAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = 0;
self.targetY = 0;
self.warningTimer = 120; // 2 seconds warning
self.warningCircle = null;
self.hasWarned = false;
self.update = function () {
if (gamePaused) {
return;
}
if (self.warningTimer > 0) {
self.warningTimer--;
if (!self.hasWarned) {
// Create warning circle
self.warningCircle = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF0000,
alpha: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.warningCircle.x = self.targetX;
self.warningCircle.y = self.targetY;
game.addChild(self.warningCircle);
self.hasWarned = true;
}
} else {
// Remove warning circle and drop fireball
if (self.warningCircle) {
self.warningCircle.destroy();
self.warningCircle = null;
}
self.x = self.targetX;
self.y = self.targetY;
// Create fire sign
var fireSign = new FireSign();
fireSign.x = self.x;
fireSign.y = self.y;
fireSigns.push(fireSign);
game.addChild(fireSign);
// Remove self
self.destroy();
var index = fallingFireballs.indexOf(self);
if (index > -1) {
fallingFireballs.splice(index, 1);
}
}
};
return self;
});
var FireSign = Container.expand(function () {
var self = Container.call(this);
var fireGraphics = self.attachAsset('fireSign', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.damage = 2;
self.damageTimer = 0;
self.lifetime = 300; // 5 seconds
self.timer = 0;
self.update = function () {
if (gamePaused) {
return;
}
self.timer++;
self.damageTimer++;
if (self.timer >= self.lifetime) {
self.destroy();
var index = fireSigns.indexOf(self);
if (index > -1) {
fireSigns.splice(index, 1);
}
}
};
return self;
});
var Fireball = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 15;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var GreenTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('greenTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 40;
self.speed = 0.8;
self.shootCooldown = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
// Check if should target white tank instead due to electric field
if (self.targetWhiteTank) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase target if close
if (distance < 300) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Calculate target angle for rotation
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(self, {
rotation: true
});
// Smoothly rotate the tank to face the movement direction
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing target
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 200 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var acidBomb = new AcidBomb();
acidBomb.x = self.x;
acidBomb.y = self.y;
acidBomb.directionX = dirX;
acidBomb.directionY = dirY;
acidBombs.push(acidBomb);
game.addChild(acidBomb);
self.shootCooldown = 150;
LK.getSound('shoot').play();
}
};
return self;
});
var IceBlock = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('iceBlock', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 4;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var IceTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('iceTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.speed = 1;
self.shootCooldown = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase player if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing player
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var iceBlock = new IceBlock();
iceBlock.x = self.x;
iceBlock.y = self.y;
iceBlock.directionX = dirX;
iceBlock.directionY = dirY;
iceBlocks.push(iceBlock);
game.addChild(iceBlock);
self.shootCooldown = 80;
LK.getSound('shoot').play();
}
};
return self;
});
var Medkit = Container.expand(function () {
var self = Container.call(this);
var medkitGraphics = self.attachAsset('medkit', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var OrangeTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('orangeTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 450;
self.speed = 1;
self.shootCooldown = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase player if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing player
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var fireball = new Fireball();
fireball.x = self.x;
fireball.y = self.y;
fireball.directionX = dirX;
fireball.directionY = dirY;
fireballs.push(fireball);
game.addChild(fireball);
self.shootCooldown = 100;
LK.getSound('shoot').play();
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var PlayerTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('playerTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = 100;
self.speed = 3;
self.shootCooldown = 0;
self.poisonTimer = 0;
self.poisonDamage = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.poisonTimer > 0) {
self.poisonTimer--;
if (LK.ticks % 30 === 0) {
self.health -= self.poisonDamage;
if (self.health <= 0) {
LK.showGameOver();
}
}
}
};
return self;
});
var Portal = Container.expand(function () {
var self = Container.call(this);
var portalGraphics = self.attachAsset('portal', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Portal no longer rotates
};
return self;
});
var RedTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('redTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 80;
self.speed = 1;
self.shootCooldown = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
// Check if should target white tank instead due to electric field
if (self.targetWhiteTank) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase target if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Calculate target angle for rotation
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(self, {
rotation: true
});
// Smoothly rotate the tank to face the movement direction
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing target
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 250 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var dynamite = new Dynamite();
dynamite.x = self.x;
dynamite.y = self.y;
dynamite.directionX = dirX;
dynamite.directionY = dirY;
dynamites.push(dynamite);
game.addChild(dynamite);
self.shootCooldown = 120;
LK.getSound('shoot').play();
}
};
return self;
});
var SkinTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('skinTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 50;
self.speed = 1.5;
self.shootCooldown = 0;
self.explosionRadius = 100;
self.lastPlayerX = 0;
self.lastPlayerY = 0;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
var targetWhiteTank = false;
// Check if should target white tank instead due to electric field
if (self.targetWhiteTank) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
targetWhiteTank = true;
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase target if close
if (distance < 150) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Calculate target angle for rotation
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(self, {
rotation: true
});
// Smoothly rotate the tank to face the movement direction
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing target
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.directionX = dirX;
bullet.directionY = dirY;
bullet.damage = 3;
enemyBullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 90;
LK.getSound('shoot').play();
}
};
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Waterball = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('waterball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 5;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var WhiteBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('whiteBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) {
return;
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var WhiteTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('whiteTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 275;
self.speed = 1;
self.shootCooldown = 0;
self.targetWhiteTank = false;
self.randomMoveTimer = 0;
self.randomMoveDirection = {
x: 0,
y: 0
};
self.isMovingRandomly = false;
self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
var targetBlackTank = false;
// Check if should target black tank instead (only if not in hard mode)
if (!hardModeEnabled) {
for (var i = 0; i < blackTanks.length; i++) {
var dx = blackTanks[i].x - self.x;
var dy = blackTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = blackTanks[i];
targetBlackTank = true;
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Priority movement: chase target if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
self.isMovingRandomly = false;
self.randomMoveTimer = 0;
} else {
// Random movement when not chasing target
if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
// Start moving in random direction
self.isMovingRandomly = true;
self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
var angle = Math.random() * Math.PI * 2;
self.randomMoveDirection.x = Math.cos(angle);
self.randomMoveDirection.y = Math.sin(angle);
// Rotate to face random direction
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: angle
}, {
duration: 300,
easing: tween.easeOut
});
} else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
// Continue random movement
self.randomMoveTimer--;
var moveX = self.randomMoveDirection.x * self.speed * 0.7;
var moveY = self.randomMoveDirection.y * self.speed * 0.7;
var newX = self.x + moveX;
var newY = self.y + moveY;
if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
self.y = newY;
}
} else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
// Stop moving and wait
self.isMovingRandomly = false;
self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
} else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
// Continue waiting
self.randomStopTimer--;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var whiteBullet = new WhiteBullet();
whiteBullet.x = self.x;
whiteBullet.y = self.y;
whiteBullet.directionX = dirX;
whiteBullet.directionY = dirY;
whiteBullets.push(whiteBullet);
game.addChild(whiteBullet);
self.shootCooldown = 120;
LK.getSound('shoot').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
var gridWidth = 32;
var gridHeight = 42;
var cellSize = 64;
var walls = [];
var skinTanks = [];
var redTanks = [];
var greenTanks = [];
var playerBullets = [];
var enemyBullets = [];
var dynamites = [];
var acidBombs = [];
var explosions = [];
var medkits = [];
var whiteTanks = [];
var blackTanks = [];
var whiteBullets = [];
var blackBullets = [];
var electricFields = [];
var blackHoles = [];
var bearTraps = [];
var orangeTanks = [];
var blueTanks = [];
var iceTanks = [];
var fireballs = [];
var waterballs = [];
var iceBlocks = [];
var fireSigns = [];
var fallingFireballs = [];
var playerTank;
var portal;
var currentLevel = 1;
var gameStarted = false;
var isDragging = false;
var gamePaused = false;
var showingMainMenu = true;
var disarmButton = null;
var currentNearbyTrap = null;
var firstPortalUsed = false;
var previousPortalX = 0;
var previousPortalY = 0;
// Main menu container
var mainMenu = new Container();
mainMenu.visible = true;
LK.gui.center.addChild(mainMenu);
// Main menu background image
var menuBackground = LK.getAsset('darkGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 43,
alpha: 0.8
});
mainMenu.addChild(menuBackground);
// Play button
var playButton = new Text2('PLAY', {
size: 120,
fill: 0xFFFFFF,
font: "monospace"
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 0;
playButton.y = 0;
mainMenu.addChild(playButton);
// Version text
var versionText = new Text2('v.0.1.4', {
size: 80,
fill: 0xFFFF00,
font: "monospace"
});
versionText.anchor.set(1, 1);
versionText.x = 950; // Adjusted position to ensure visibility
versionText.y = 1300; // Adjusted position to ensure visibility
mainMenu.addChild(versionText);
// Experiments screen container
var experimentsScreen = new Container();
experimentsScreen.visible = false;
LK.gui.center.addChild(experimentsScreen);
// Experiments screen background
var experimentsBackground = LK.getAsset('darkGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 43,
alpha: 0.8
});
experimentsScreen.addChild(experimentsBackground);
// Experiments title
var experimentsTitle = new Text2('Do You Wanna Activate Experiments', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
experimentsTitle.anchor.set(0.5, 0.5);
experimentsTitle.x = 0;
experimentsTitle.y = -200;
experimentsScreen.addChild(experimentsTitle);
// Initialize hard mode setting from storage
var hardModeEnabled = storage.hardModeEnabled || false;
// Hard mode toggle button
var hardModeButton = new Text2(hardModeEnabled ? 'Hard Mode - On' : 'Hard Mode - Off', {
size: 60,
fill: hardModeEnabled ? 0x00FF00 : 0xFF0000,
font: "monospace"
});
hardModeButton.anchor.set(0.5, 0.5);
hardModeButton.x = 0;
hardModeButton.y = 0;
experimentsScreen.addChild(hardModeButton);
// Hard mode button click handler
hardModeButton.down = function (x, y, obj) {
hardModeEnabled = !hardModeEnabled;
storage.hardModeEnabled = hardModeEnabled;
hardModeButton.setText(hardModeEnabled ? 'Hard Mode - On' : 'Hard Mode - Off');
hardModeButton.fill = hardModeEnabled ? 0x00FF00 : 0xFF0000;
hardModeButton.tint = hardModeEnabled ? 0x00FF00 : 0xFF0000;
};
// Continue button to start game after experiments screen
var continueButton = new Text2('CONTINUE', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
continueButton.anchor.set(0.5, 0.5);
continueButton.x = 0;
continueButton.y = 200;
experimentsScreen.addChild(continueButton);
// Continue button click handler
continueButton.down = function (x, y, obj) {
experimentsScreen.visible = false;
showingMainMenu = false;
gameStarted = true;
startLevel();
};
// Style selection screen container
var styleSelectionScreen = new Container();
styleSelectionScreen.visible = false;
LK.gui.center.addChild(styleSelectionScreen);
// Style selection screen background
var styleSelectionBackground = LK.getAsset('darkGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 43,
alpha: 0.8
});
styleSelectionScreen.addChild(styleSelectionBackground);
// Style selection title
var styleTitle = new Text2('CHOOSE A STYLE', {
size: 100,
fill: 0xFFFFFF,
font: "monospace"
});
styleTitle.anchor.set(0.5, 0.5);
styleTitle.x = 0;
styleTitle.y = -300;
styleSelectionScreen.addChild(styleTitle);
// Normal style button
var normalStyleButton = new Text2('NORMAL', {
size: 80,
fill: 0x00FF00,
font: "monospace"
});
normalStyleButton.anchor.set(0.5, 0.5);
normalStyleButton.x = -300;
normalStyleButton.y = 0;
styleSelectionScreen.addChild(normalStyleButton);
// Lava style button
var lavaStyleButton = new Text2('LAVA', {
size: 80,
fill: 0xFF4500,
font: "monospace"
});
lavaStyleButton.anchor.set(0.5, 0.5);
lavaStyleButton.x = 0;
lavaStyleButton.y = 0;
styleSelectionScreen.addChild(lavaStyleButton);
// Ice style button
var iceStyleButton = new Text2('ICE', {
size: 80,
fill: 0x00BFFF,
font: "monospace"
});
iceStyleButton.anchor.set(0.5, 0.5);
iceStyleButton.x = 300;
iceStyleButton.y = 0;
styleSelectionScreen.addChild(iceStyleButton);
// Map style variable
var mapStyle = 'normal';
// Normal style click handler
normalStyleButton.down = function (x, y, obj) {
mapStyle = 'normal';
styleSelectionScreen.visible = false;
experimentsScreen.visible = true;
};
// Lava style click handler
lavaStyleButton.down = function (x, y, obj) {
mapStyle = 'lava';
styleSelectionScreen.visible = false;
experimentsScreen.visible = true;
};
// Ice style click handler
iceStyleButton.down = function (x, y, obj) {
mapStyle = 'ice';
styleSelectionScreen.visible = false;
experimentsScreen.visible = true;
};
// Play button click handler
playButton.down = function (x, y, obj) {
mainMenu.visible = false;
styleSelectionScreen.visible = true;
};
var nextLevelScreen = new Container();
nextLevelScreen.visible = false;
LK.gui.center.addChild(nextLevelScreen);
// Next level screen background
var nextLevelBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 12,
scaleY: 8,
tint: 0x000000,
alpha: 0.9
});
nextLevelScreen.addChild(nextLevelBackground);
// Next level button
var nextLevelButton = new Text2('NEXT LEVEL', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
nextLevelButton.anchor.set(0.5, 0.5);
nextLevelButton.x = 0;
nextLevelButton.y = 0;
nextLevelScreen.addChild(nextLevelButton);
// Next level button click handler
nextLevelButton.down = function (x, y, obj) {
nextLevelScreen.visible = false;
gamePaused = false;
// Generate new level
startLevel();
};
// Return to main menu button
var returnToMenuButton = new Text2('RETURN TO MAIN MENU', {
size: 60,
fill: 0xFFFFFF,
font: "monospace"
});
returnToMenuButton.anchor.set(0.5, 0.5);
returnToMenuButton.x = 0;
returnToMenuButton.y = 100;
nextLevelScreen.addChild(returnToMenuButton);
// Return to main menu button click handler
returnToMenuButton.down = function (x, y, obj) {
// Clear all game objects
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
for (var i = skinTanks.length - 1; i >= 0; i--) {
skinTanks[i].destroy();
}
skinTanks = [];
for (var i = redTanks.length - 1; i >= 0; i--) {
redTanks[i].destroy();
}
redTanks = [];
for (var i = greenTanks.length - 1; i >= 0; i--) {
greenTanks[i].destroy();
}
greenTanks = [];
for (var i = medkits.length - 1; i >= 0; i--) {
medkits[i].destroy();
}
medkits = [];
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
for (var i = dynamites.length - 1; i >= 0; i--) {
dynamites[i].destroy();
}
dynamites = [];
for (var i = acidBombs.length - 1; i >= 0; i--) {
acidBombs[i].destroy();
}
acidBombs = [];
for (var i = explosions.length - 1; i >= 0; i--) {
explosions[i].destroy();
}
explosions = [];
for (var i = whiteTanks.length - 1; i >= 0; i--) {
whiteTanks[i].destroy();
}
whiteTanks = [];
for (var i = blackTanks.length - 1; i >= 0; i--) {
blackTanks[i].destroy();
}
blackTanks = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
for (var i = bearTraps.length - 1; i >= 0; i--) {
bearTraps[i].destroy();
}
bearTraps = [];
for (var i = orangeTanks.length - 1; i >= 0; i--) {
orangeTanks[i].destroy();
}
orangeTanks = [];
for (var i = blueTanks.length - 1; i >= 0; i--) {
blueTanks[i].destroy();
}
blueTanks = [];
for (var i = iceTanks.length - 1; i >= 0; i--) {
iceTanks[i].destroy();
}
iceTanks = [];
for (var i = fireballs.length - 1; i >= 0; i--) {
fireballs[i].destroy();
}
fireballs = [];
for (var i = waterballs.length - 1; i >= 0; i--) {
waterballs[i].destroy();
}
waterballs = [];
for (var i = iceBlocks.length - 1; i >= 0; i--) {
iceBlocks[i].destroy();
}
iceBlocks = [];
for (var i = fireSigns.length - 1; i >= 0; i--) {
fireSigns[i].destroy();
}
fireSigns = [];
for (var i = fallingFireballs.length - 1; i >= 0; i--) {
if (fallingFireballs[i].warningCircle) {
fallingFireballs[i].warningCircle.destroy();
}
fallingFireballs[i].destroy();
}
fallingFireballs = [];
// Destroy player tank and portal if they exist
if (playerTank) {
playerTank.destroy();
playerTank = null;
}
if (portal) {
portal.destroy();
portal = null;
}
// Reset game state
currentLevel = 1;
gameStarted = false;
isDragging = false;
gamePaused = false;
showingMainMenu = true;
levelsWithoutDying = 0;
storage.levelsWithoutDying = levelsWithoutDying;
firstPortalUsed = false;
previousPortalX = 0;
previousPortalY = 0;
LK.setScore(0);
// Hide next level screen and show main menu
nextLevelScreen.visible = false;
mainMenu.visible = true;
};
var healthBarBackground = LK.getAsset('wall', {
anchorX: 0,
anchorY: 1,
scaleX: 4,
scaleY: 0.8,
tint: 0x333333
});
LK.gui.bottomLeft.addChild(healthBarBackground);
var healthBarFill = LK.getAsset('wall', {
anchorX: 0,
anchorY: 1,
scaleX: 4,
scaleY: 0.8,
tint: 0x00ff00
});
LK.gui.bottomLeft.addChild(healthBarFill);
var levelText = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF,
font: "monospace"
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
var scoreText = new Text2('Score: 0', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = 80;
LK.gui.top.addChild(scoreText);
var bestScoreText = new Text2('Best: ' + (storage.bestScore || 0), {
size: 35,
fill: 0xFFFF00,
font: "monospace"
});
bestScoreText.anchor.set(0.5, 0);
bestScoreText.x = 0;
bestScoreText.y = 130;
LK.gui.top.addChild(bestScoreText);
// Achievement button
var achievementButton = new Text2('ACHIEVEMENTS', {
size: 30,
fill: 0xFFFFFF,
font: "monospace"
});
achievementButton.anchor.set(1, 0);
LK.gui.topRight.addChild(achievementButton);
// Achievement menu (initially hidden)
var achievementMenu = new Container();
achievementMenu.visible = false;
LK.gui.center.addChild(achievementMenu);
// Achievement menu background
var menuBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 15,
scaleY: 20,
tint: 0x000000,
alpha: 0.8
});
achievementMenu.addChild(menuBackground);
// Achievement title background
var titleBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 1.5,
tint: 0x000000,
alpha: 0.9
});
titleBackground.x = 0;
titleBackground.y = -400;
achievementMenu.addChild(titleBackground);
// Achievement title
var achievementTitle = new Text2('ACHIEVEMENTS', {
size: 60,
fill: 0xFFFF00,
font: "monospace"
});
achievementTitle.anchor.set(0.5, 0.5);
achievementTitle.x = 0;
achievementTitle.y = -400;
achievementMenu.addChild(achievementTitle);
// Initialize achievements in storage if they don't exist
var achievements = storage.achievements || {
killAllEnemies: false,
useFirstMedkit: false,
killFirstEnemy: false,
finishWithoutDying: false,
get150Score: false,
beatPreviousBest: false,
arriveAtLevel3: false,
kill50EnemiesTotal: false,
killWhiteTank: false,
killBlackTank: false,
have1000Score: false,
pass5LevelsWithoutDying: false
};
storage.achievements = achievements;
// Achievement tracking variables
var totalEnemiesAtStart = 0;
var hasUsedMedkit = false;
var hasKilledEnemy = false;
var hasBeenHurt = false;
var totalEnemiesKilled = storage.totalEnemiesKilled || 0;
var hasKilledWhiteTank = storage.hasKilledWhiteTank || false;
var hasKilledBlackTank = storage.hasKilledBlackTank || false;
var levelsWithoutDying = storage.levelsWithoutDying || 0;
var hasReachedScore1000 = storage.hasReachedScore1000 || false;
// Keyboard movement variables
var keys = {
w: false,
a: false,
s: false,
d: false
};
// Keyboard controls are not supported in LK sandbox environment
// Movement is handled via touch/drag controls only
// Create disarm button (initially hidden)
disarmButton = new Text2('DISARM', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
disarmButton.anchor.set(0, 1);
disarmButton.x = 20;
disarmButton.y = -20;
disarmButton.visible = false;
LK.gui.bottomLeft.addChild(disarmButton);
// Disarm button background
var disarmButtonBg = LK.getAsset('wall', {
anchorX: 0,
anchorY: 1,
scaleX: 2.5,
scaleY: 0.8,
tint: 0x333333,
alpha: 0.8
});
disarmButtonBg.x = 10;
disarmButtonBg.y = -10;
disarmButtonBg.visible = false;
LK.gui.bottomLeft.addChild(disarmButtonBg);
// Disarm button click handler
disarmButton.down = function (x, y, obj) {
if (currentNearbyTrap && currentNearbyTrap.isArmed) {
currentNearbyTrap.destroy();
var index = bearTraps.indexOf(currentNearbyTrap);
if (index > -1) {
bearTraps.splice(index, 1);
}
disarmButton.visible = false;
disarmButtonBg.visible = false;
currentNearbyTrap = null;
LK.getSound('hit').play();
}
};
// Achievement text elements
var achievement1Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement1Text.anchor.set(0, 0.5);
achievement1Text.x = -300;
achievement1Text.y = -200;
achievementMenu.addChild(achievement1Text);
var achievement2Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement2Text.anchor.set(0, 0.5);
achievement2Text.x = -300;
achievement2Text.y = -100;
achievementMenu.addChild(achievement2Text);
var achievement3Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement3Text.anchor.set(0, 0.5);
achievement3Text.x = -300;
achievement3Text.y = 0;
achievementMenu.addChild(achievement3Text);
var achievement4Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement4Text.anchor.set(0, 0.5);
achievement4Text.x = -300;
achievement4Text.y = 100;
achievementMenu.addChild(achievement4Text);
var achievement5Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement5Text.anchor.set(0, 0.5);
achievement5Text.x = -300;
achievement5Text.y = 200;
achievementMenu.addChild(achievement5Text);
var achievement6Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement6Text.anchor.set(0, 0.5);
achievement6Text.x = -300;
achievement6Text.y = 300;
achievementMenu.addChild(achievement6Text);
var achievement7Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement7Text.anchor.set(0, 0.5);
achievement7Text.x = -300;
achievement7Text.y = 400;
achievementMenu.addChild(achievement7Text);
var achievement8Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement8Text.anchor.set(0, 0.5);
achievement8Text.x = -300;
achievement8Text.y = 500;
achievementMenu.addChild(achievement8Text);
function updateAchievementTexts() {
achievement1Text.setText('Kill A White Tank - ' + (achievements.killWhiteTank ? 'DONE' : 'NOT DONE'));
achievement2Text.setText('Kill A Black Tank - ' + (achievements.killBlackTank ? 'DONE' : 'NOT DONE'));
achievement3Text.setText('Have 1000 Score - ' + (achievements.have1000Score ? 'DONE' : 'NOT DONE'));
achievement4Text.setText('Pass 5 Levels Without Dying - ' + (achievements.pass5LevelsWithoutDying ? 'DONE' : 'NOT DONE'));
achievement5Text.setText('Kill all enemies in map - ' + (achievements.killAllEnemies ? 'DONE' : 'NOT DONE'));
achievement6Text.setText('Use your first MedKit - ' + (achievements.useFirstMedkit ? 'DONE' : 'NOT DONE'));
achievement7Text.setText('Kill your first enemy - ' + (achievements.killFirstEnemy ? 'DONE' : 'NOT DONE'));
achievement8Text.setText('Finish a level without dying - ' + (achievements.finishWithoutDying ? 'DONE' : 'NOT DONE'));
// Set colors for achievement text - green for DONE, red for NOT DONE
if (achievements.killWhiteTank) {
achievement1Text.fill = 0x00FF00;
achievement1Text.tint = 0x00FF00;
} else {
achievement1Text.fill = 0xFF0000;
achievement1Text.tint = 0xFF0000;
}
if (achievements.killBlackTank) {
achievement2Text.fill = 0x00FF00;
achievement2Text.tint = 0x00FF00;
} else {
achievement2Text.fill = 0xFF0000;
achievement2Text.tint = 0xFF0000;
}
if (achievements.have1000Score) {
achievement3Text.fill = 0x00FF00;
achievement3Text.tint = 0x00FF00;
} else {
achievement3Text.fill = 0xFF0000;
achievement3Text.tint = 0xFF0000;
}
if (achievements.pass5LevelsWithoutDying) {
achievement4Text.fill = 0x00FF00;
achievement4Text.tint = 0x00FF00;
} else {
achievement4Text.fill = 0xFF0000;
achievement4Text.tint = 0xFF0000;
}
if (achievements.killAllEnemies) {
achievement5Text.fill = 0x00FF00;
achievement5Text.tint = 0x00FF00;
} else {
achievement5Text.fill = 0xFF0000;
achievement5Text.tint = 0xFF0000;
}
if (achievements.useFirstMedkit) {
achievement6Text.fill = 0x00FF00;
achievement6Text.tint = 0x00FF00;
} else {
achievement6Text.fill = 0xFF0000;
achievement6Text.tint = 0xFF0000;
}
if (achievements.killFirstEnemy) {
achievement7Text.fill = 0x00FF00;
achievement7Text.tint = 0x00FF00;
} else {
achievement7Text.fill = 0xFF0000;
achievement7Text.tint = 0xFF0000;
}
if (achievements.finishWithoutDying) {
achievement8Text.fill = 0x00FF00;
achievement8Text.tint = 0x00FF00;
} else {
achievement8Text.fill = 0xFF0000;
achievement8Text.tint = 0xFF0000;
}
}
// Initial text update
updateAchievementTexts();
// Achievement button click handler
achievementButton.down = function (x, y, obj) {
achievementMenu.visible = !achievementMenu.visible;
gamePaused = achievementMenu.visible;
updateAchievementTexts();
};
// Close menu when clicking background
menuBackground.down = function (x, y, obj) {
achievementMenu.visible = false;
gamePaused = false;
};
function generateMaze() {
walls = [];
var playerTankX = 1024;
var playerTankY = 1366;
// Set background color based on map style
if (mapStyle === 'lava') {
game.setBackgroundColor(0xFF4500); // Orange background
} else if (mapStyle === 'ice') {
game.setBackgroundColor(0x0000FF); // Blue background
} else {
game.setBackgroundColor(0x2F4F2F); // Green background
}
for (var x = 0; x < gridWidth; x++) {
for (var y = 0; y < gridHeight; y++) {
var wallX = x * cellSize + cellSize / 2;
var wallY = y * cellSize + cellSize / 2;
// Check if this wall position would be too close to player tank position
var dx = Math.abs(wallX - playerTankX);
var dy = Math.abs(wallY - playerTankY);
var isNearPlayerTank = dx < 64 && dy < 64; // Within one cell distance
if (x === 0 || x === gridWidth - 1 || y === 0 || y === gridHeight - 1) {
if (!isNearPlayerTank) {
var wall = new Wall();
// Change wall appearance based on map style
if (mapStyle === 'lava') {
wall.attachAsset('lavaWall', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (mapStyle === 'ice') {
wall.attachAsset('iceWall', {
anchorX: 0.5,
anchorY: 0.5
});
}
wall.x = wallX;
wall.y = wallY;
walls.push(wall);
game.addChild(wall);
}
} else if (Math.random() < 0.3 && !isNearPlayerTank) {
var wall = new Wall();
// Change wall appearance based on map style
if (mapStyle === 'lava') {
wall.attachAsset('lavaWall', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (mapStyle === 'ice') {
wall.attachAsset('iceWall', {
anchorX: 0.5,
anchorY: 0.5
});
}
wall.x = wallX;
wall.y = wallY;
walls.push(wall);
game.addChild(wall);
}
}
}
}
function spawnEnemies() {
if (mapStyle === 'normal') {
var skinCount = Math.floor(Math.random() * 6) + 10; // 10-15 skin tanks
var redCount = Math.floor(Math.random() * 6) + 5; // 5-10 red tanks
var greenCount = Math.floor(Math.random() * 6) + 7; // 7-12 green tanks
for (var i = 0; i < skinCount; i++) {
var tank = new SkinTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
skinTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < redCount; i++) {
var tank = new RedTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
redTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < greenCount; i++) {
var tank = new GreenTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
greenTanks.push(tank);
game.addChild(tank);
}
} else if (mapStyle === 'lava') {
var whiteCount = Math.floor(Math.random() * 3) + 2; // 2-4 white tanks
var blackCount = Math.floor(Math.random() * 3) + 1; // 1-3 black tanks
var orangeCount = Math.floor(Math.random() * 4) + 3; // 3-6 orange tanks
for (var i = 0; i < whiteCount; i++) {
var tank = new WhiteTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
whiteTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < blackCount; i++) {
var tank = new BlackTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
blackTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < orangeCount; i++) {
var tank = new OrangeTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
orangeTanks.push(tank);
game.addChild(tank);
}
} else if (mapStyle === 'ice') {
var blueCount = Math.floor(Math.random() * 4) + 3; // 3-6 blue tanks
var iceCount = Math.floor(Math.random() * 5) + 5; // 5-9 ice tanks
for (var i = 0; i < blueCount; i++) {
var tank = new BlueTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
blueTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < iceCount; i++) {
var tank = new IceTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
iceTanks.push(tank);
game.addChild(tank);
}
}
}
function checkWallCollision(x, y) {
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var dx = Math.abs(x - wall.x);
var dy = Math.abs(y - wall.y);
if (dx < 32 && dy < 32) {
return true;
}
}
return false;
}
function getDistanceToPlayer(x, y) {
if (!playerTank) {
return 1000;
}
var dx = x - playerTank.x;
var dy = y - playerTank.y;
return Math.sqrt(dx * dx + dy * dy);
}
function canReachPosition(startX, startY, targetX, targetY) {
// Create a grid to track visited positions
var visited = {};
var queue = [{
x: startX,
y: startY
}];
var gridSize = 32; // Step size for pathfinding
var maxDistance = 100; // Maximum distance to consider reachable
// Simple flood-fill algorithm to check connectivity
while (queue.length > 0) {
var current = queue.shift();
var key = Math.floor(current.x / gridSize) + ',' + Math.floor(current.y / gridSize);
if (visited[key]) continue;
visited[key] = true;
// Check if we've reached the target
var dx = current.x - targetX;
var dy = current.y - targetY;
if (Math.abs(dx) < maxDistance && Math.abs(dy) < maxDistance) {
return true;
}
// Add neighboring positions to queue if they're not blocked
var directions = [{
x: gridSize,
y: 0
}, {
x: -gridSize,
y: 0
}, {
x: 0,
y: gridSize
}, {
x: 0,
y: -gridSize
}];
for (var i = 0; i < directions.length; i++) {
var newX = current.x + directions[i].x;
var newY = current.y + directions[i].y;
// Check bounds
if (newX < 100 || newX > 1948 || newY < 100 || newY > 2632) continue;
// Check if position is blocked by walls
if (!checkWallCollision(newX, newY)) {
queue.push({
x: newX,
y: newY
});
}
}
// Limit search to prevent infinite loops
if (Object.keys(visited).length > 500) break;
}
return false;
}
function spawnMedkits() {
var medkitCount = Math.floor(Math.random() * 4) + 3; // 3-6 medkits per level
for (var i = 0; i < medkitCount; i++) {
var medkit = new Medkit();
do {
medkit.x = Math.random() * (2048 - 200) + 100;
medkit.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(medkit.x, medkit.y) || getDistanceToPlayer(medkit.x, medkit.y) < 150);
medkits.push(medkit);
game.addChild(medkit);
}
}
function spawnBearTraps() {
var trapCount = Math.floor(Math.random() * 3) + 2; // 2-4 bear traps per level
for (var i = 0; i < trapCount; i++) {
var bearTrap = new BearTrap();
do {
bearTrap.x = Math.random() * (2048 - 200) + 100;
bearTrap.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(bearTrap.x, bearTrap.y) || getDistanceToPlayer(bearTrap.x, bearTrap.y) < 200);
bearTraps.push(bearTrap);
game.addChild(bearTrap);
}
}
function createExplosion(x, y, radius, damage) {
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: radius / 60,
scaleY: radius / 60,
alpha: 0.8
});
game.addChild(explosion);
explosions.push(explosion);
tween(explosion, {
alpha: 0,
scaleX: explosion.scaleX * 1.5,
scaleY: explosion.scaleY * 1.5
}, {
duration: 500,
onFinish: function onFinish() {
explosion.destroy();
var index = explosions.indexOf(explosion);
if (index > -1) {
explosions.splice(index, 1);
}
}
});
var dx = playerTank.x - x;
var dy = playerTank.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < radius) {
playerTank.health -= damage;
LK.getSound('hit').play();
// Track that player has been hurt
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
LK.getSound('explosion').play();
}
function startLevel() {
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
for (var i = skinTanks.length - 1; i >= 0; i--) {
skinTanks[i].destroy();
}
skinTanks = [];
for (var i = redTanks.length - 1; i >= 0; i--) {
redTanks[i].destroy();
}
redTanks = [];
for (var i = greenTanks.length - 1; i >= 0; i--) {
greenTanks[i].destroy();
}
greenTanks = [];
for (var i = medkits.length - 1; i >= 0; i--) {
medkits[i].destroy();
}
medkits = [];
for (var i = whiteTanks.length - 1; i >= 0; i--) {
whiteTanks[i].destroy();
}
whiteTanks = [];
for (var i = blackTanks.length - 1; i >= 0; i--) {
blackTanks[i].destroy();
}
blackTanks = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
for (var i = bearTraps.length - 1; i >= 0; i--) {
bearTraps[i].destroy();
}
bearTraps = [];
generateMaze();
spawnEnemies();
spawnMedkits();
spawnBearTraps();
// Hide disarm button when starting new level
disarmButton.visible = false;
disarmButtonBg.visible = false;
currentNearbyTrap = null;
// Track total enemies for achievement
totalEnemiesAtStart = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length + orangeTanks.length + blueTanks.length + iceTanks.length;
// Reset achievement tracking variables
hasUsedMedkit = false;
hasKilledEnemy = false;
hasBeenHurt = false;
// Reset hard mode portal tracking
firstPortalUsed = false;
previousPortalX = 0;
previousPortalY = 0;
// Only create player tank if it doesn't exist (first level)
if (!playerTank) {
playerTank = new PlayerTank();
playerTank.x = 1024;
playerTank.y = 1366;
playerTank.health = 100;
game.addChild(playerTank);
} else {
// Just reset position and health for existing player tank
playerTank.x = 1024;
playerTank.y = 1366;
playerTank.health = 100;
}
portal = new Portal();
var attempts = 0;
var maxAttempts = 50;
do {
portal.x = Math.random() * (2048 - 200) + 100;
portal.y = Math.random() * (2732 - 200) + 100;
attempts++;
// If we can't find a reachable position after many attempts, reduce wall density
if (attempts > maxAttempts) {
// Remove some random walls to create more open paths
for (var i = walls.length - 1; i >= 0 && walls.length > 20; i--) {
if (Math.random() < 0.1) {
walls[i].destroy();
walls.splice(i, 1);
}
}
attempts = 0;
}
} while ((checkWallCollision(portal.x, portal.y) || getDistanceToPlayer(portal.x, portal.y) < 300 || !canReachPosition(playerTank.x, playerTank.y, portal.x, portal.y)) && attempts < maxAttempts);
game.addChild(portal);
levelText.setText('Level: ' + currentLevel);
gameStarted = true;
// Achievement: Arrive at level 3
if (currentLevel >= 3 && !achievements.arriveAtLevel3) {
achievements.arriveAtLevel3 = true;
storage.achievements = achievements;
}
}
// Mouse functionality - player tank follows mouse position
game.down = function (x, y, obj) {
// Only start dragging if mouse is pressed on the player tank and achievements menu is not visible and next level screen is not visible
if (playerTank && playerTank.x && playerTank.y && !achievementMenu.visible && !nextLevelScreen.visible) {
var dx = x - playerTank.x;
var dy = y - playerTank.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 60) {
// Within tank radius (tank is 120px wide, so radius ~60)
isDragging = true;
}
}
};
game.move = function (x, y, obj) {
if (!gameStarted || !playerTank || !isDragging || achievementMenu.visible || nextLevelScreen.visible) {
return;
}
// Only allow dragging if mouse is not on a wall
if (checkWallCollision(x, y)) {
isDragging = false; // Stop dragging when mouse is on wall
return;
}
// Calculate direction from tank to mouse for rotation
var dx = x - playerTank.x;
var dy = y - playerTank.y;
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(playerTank, {
rotation: true
});
// Smoothly rotate the tank to face the mouse direction
tween(playerTank, {
rotation: targetAngle
}, {
duration: 200,
easing: tween.easeOut
});
// Move player tank directly to mouse position if no wall collision
playerTank.x = x;
playerTank.y = y;
};
game.up = function (x, y, obj) {
isDragging = false;
if (!gameStarted || !playerTank || achievementMenu.visible || nextLevelScreen.visible) {
return;
}
if (playerTank.shootCooldown <= 0) {
var dx = x - playerTank.x;
var dy = y - playerTank.y;
var length = Math.sqrt(dx * dx + dy * dy);
if (length > 0) {
// Calculate the angle to face the shooting direction
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(playerTank, {
rotation: true
});
// Rotate the tank to face the shooting direction
tween(playerTank, {
rotation: targetAngle
}, {
duration: 200,
easing: tween.easeOut
});
var dirX = dx / length;
var dirY = dy / length;
var bullet = new PlayerBullet();
bullet.x = playerTank.x;
bullet.y = playerTank.y;
bullet.directionX = dirX;
bullet.directionY = dirY;
playerBullets.push(bullet);
game.addChild(bullet);
playerTank.shootCooldown = 15;
LK.getSound('shoot').play();
}
}
};
// Game Over screen setup
var gameOverHandled = false;
// Override LK.showGameOver to add custom functionality
var originalShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
if (!gameOverHandled) {
gameOverHandled = true;
// Create game over screen with return to main menu button
var gameOverScreen = new Container();
gameOverScreen.visible = true;
LK.gui.center.addChild(gameOverScreen);
// Game over background
var gameOverBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 12,
scaleY: 8,
tint: 0x000000,
alpha: 0.9
});
gameOverScreen.addChild(gameOverBackground);
// Game Over text
var gameOverText = new Text2('GAME OVER', {
size: 80,
fill: 0xFF0000,
font: "monospace"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = -50;
gameOverScreen.addChild(gameOverText);
// Return to main menu button for game over
var gameOverReturnButton = new Text2('RETURN TO MAIN MENU', {
size: 60,
fill: 0xFFFFFF,
font: "monospace"
});
gameOverReturnButton.anchor.set(0.5, 0.5);
gameOverReturnButton.x = 0;
gameOverReturnButton.y = 50;
gameOverScreen.addChild(gameOverReturnButton);
// Return to main menu button click handler for game over
gameOverReturnButton.down = function (x, y, obj) {
// Clear all game objects
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
for (var i = skinTanks.length - 1; i >= 0; i--) {
skinTanks[i].destroy();
}
skinTanks = [];
for (var i = redTanks.length - 1; i >= 0; i--) {
redTanks[i].destroy();
}
redTanks = [];
for (var i = greenTanks.length - 1; i >= 0; i--) {
greenTanks[i].destroy();
}
greenTanks = [];
for (var i = medkits.length - 1; i >= 0; i--) {
medkits[i].destroy();
}
medkits = [];
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
for (var i = dynamites.length - 1; i >= 0; i--) {
dynamites[i].destroy();
}
dynamites = [];
for (var i = acidBombs.length - 1; i >= 0; i--) {
acidBombs[i].destroy();
}
acidBombs = [];
for (var i = explosions.length - 1; i >= 0; i--) {
explosions[i].destroy();
}
explosions = [];
for (var i = whiteTanks.length - 1; i >= 0; i--) {
whiteTanks[i].destroy();
}
whiteTanks = [];
for (var i = blackTanks.length - 1; i >= 0; i--) {
blackTanks[i].destroy();
}
blackTanks = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
for (var i = bearTraps.length - 1; i >= 0; i--) {
bearTraps[i].destroy();
}
bearTraps = [];
// Destroy player tank and portal if they exist
if (playerTank) {
playerTank.destroy();
playerTank = null;
}
if (portal) {
portal.destroy();
portal = null;
}
// Reset game state
currentLevel = 1;
gameStarted = false;
isDragging = false;
gamePaused = false;
showingMainMenu = true;
gameOverHandled = false;
levelsWithoutDying = 0;
storage.levelsWithoutDying = levelsWithoutDying;
firstPortalUsed = false;
previousPortalX = 0;
previousPortalY = 0;
LK.setScore(0);
// Hide game over screen and show main menu
gameOverScreen.destroy();
mainMenu.visible = true;
};
// Auto-hide after 3 seconds and call original game over
LK.setTimeout(function () {
gameOverScreen.destroy();
originalShowGameOver();
}, 3000);
} else {
originalShowGameOver();
}
};
game.update = function () {
if (showingMainMenu) {
return;
}
if (!gameStarted) {
return;
}
if (gamePaused) {
return;
}
// Movement is handled via touch/drag in game.move method only
// Keyboard controls are not supported in LK sandbox environment
// Movement is handled via touch/drag in game.move method and WASD keys
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
for (var j = skinTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(skinTanks[j])) {
skinTanks[j].health -= 3;
bullet.destroy();
playerBullets.splice(i, 1);
if (skinTanks[j].health <= 0) {
createExplosion(skinTanks[j].x, skinTanks[j].y, 100, 15);
skinTanks[j].destroy();
skinTanks.splice(j, 1);
LK.setScore(LK.getScore() + 10);
// Track total enemies killed
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
// Achievement: Kill first enemy
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
// Achievement: Kill 50 enemies total
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = redTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(redTanks[j])) {
redTanks[j].health -= 10;
bullet.destroy();
playerBullets.splice(i, 1);
if (redTanks[j].health <= 0) {
redTanks[j].destroy();
redTanks.splice(j, 1);
LK.setScore(LK.getScore() + 20);
// Track total enemies killed
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
// Achievement: Kill first enemy
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
// Achievement: Kill 50 enemies total
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = greenTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(greenTanks[j])) {
greenTanks[j].health -= 25;
bullet.destroy();
playerBullets.splice(i, 1);
if (greenTanks[j].health <= 0) {
greenTanks[j].destroy();
greenTanks.splice(j, 1);
LK.setScore(LK.getScore() + 30);
// Track total enemies killed
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
// Achievement: Kill first enemy
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
// Achievement: Kill 50 enemies total
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = whiteTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(whiteTanks[j])) {
whiteTanks[j].health -= 25;
bullet.destroy();
playerBullets.splice(i, 1);
if (whiteTanks[j].health <= 0) {
whiteTanks[j].destroy();
whiteTanks.splice(j, 1);
LK.setScore(LK.getScore() + 40);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
// Achievement: Kill a white tank
if (!hasKilledWhiteTank) {
hasKilledWhiteTank = true;
storage.hasKilledWhiteTank = hasKilledWhiteTank;
achievements.killWhiteTank = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = blackTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(blackTanks[j])) {
blackTanks[j].health -= 25;
bullet.destroy();
playerBullets.splice(i, 1);
if (blackTanks[j].health <= 0) {
blackTanks[j].destroy();
blackTanks.splice(j, 1);
LK.setScore(LK.getScore() + 50);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
// Achievement: Kill a black tank
if (!hasKilledBlackTank) {
hasKilledBlackTank = true;
storage.hasKilledBlackTank = hasKilledBlackTank;
achievements.killBlackTank = true;
storage.achievements = achievements;
}
}
break;
}
}
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (bullet.intersects(playerTank)) {
var damage = hardModeEnabled ? bullet.damage * 2 : bullet.damage;
playerTank.health -= damage;
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('hit').play();
// Track that player has been hurt
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
}
for (var i = dynamites.length - 1; i >= 0; i--) {
var dynamite = dynamites[i];
if (dynamite.x < 0 || dynamite.x > 2048 || dynamite.y < 0 || dynamite.y > 2732) {
createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage);
dynamite.destroy();
dynamites.splice(i, 1);
continue;
}
if (checkWallCollision(dynamite.x, dynamite.y)) {
createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage);
dynamite.destroy();
dynamites.splice(i, 1);
continue;
}
if (dynamite.intersects(playerTank)) {
createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage);
dynamite.destroy();
dynamites.splice(i, 1);
continue;
}
}
for (var i = acidBombs.length - 1; i >= 0; i--) {
var acidBomb = acidBombs[i];
if (acidBomb.x < 0 || acidBomb.x > 2048 || acidBomb.y < 0 || acidBomb.y > 2732) {
acidBomb.destroy();
acidBombs.splice(i, 1);
continue;
}
if (checkWallCollision(acidBomb.x, acidBomb.y)) {
acidBomb.destroy();
acidBombs.splice(i, 1);
continue;
}
if (acidBomb.intersects(playerTank)) {
var damage = hardModeEnabled ? acidBomb.damage * 2 : acidBomb.damage;
var poisonDamage = hardModeEnabled ? acidBomb.poisonDamage * 2 : acidBomb.poisonDamage;
playerTank.health -= damage;
playerTank.poisonTimer = acidBomb.poisonDuration;
playerTank.poisonDamage = poisonDamage;
acidBomb.destroy();
acidBombs.splice(i, 1);
LK.getSound('hit').play();
// Track that player has been hurt
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
}
// Handle white bullets
for (var i = whiteBullets.length - 1; i >= 0; i--) {
var bullet = whiteBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
whiteBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
whiteBullets.splice(i, 1);
continue;
}
if (bullet.intersects(playerTank)) {
// Create electric field
var electricField = new ElectricField();
electricField.x = bullet.x;
electricField.y = bullet.y;
electricFields.push(electricField);
game.addChild(electricField);
bullet.destroy();
whiteBullets.splice(i, 1);
LK.getSound('explosion').play();
continue;
}
}
// Handle black bullets
for (var i = blackBullets.length - 1; i >= 0; i--) {
var bullet = blackBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
blackBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
blackBullets.splice(i, 1);
continue;
}
if (bullet.intersects(playerTank)) {
// Create black hole
var blackHole = new BlackHole();
blackHole.x = bullet.x;
blackHole.y = bullet.y;
blackHoles.push(blackHole);
game.addChild(blackHole);
bullet.destroy();
blackBullets.splice(i, 1);
LK.getSound('explosion').play();
continue;
}
// Check collision with white bullets
for (var j = whiteBullets.length - 1; j >= 0; j--) {
if (bullet.intersects(whiteBullets[j])) {
// Create black hole from black bullet
var blackHole = new BlackHole();
blackHole.x = bullet.x;
blackHole.y = bullet.y;
blackHoles.push(blackHole);
game.addChild(blackHole);
// Create electric field from white bullet
var electricField = new ElectricField();
electricField.x = whiteBullets[j].x;
electricField.y = whiteBullets[j].y;
electricFields.push(electricField);
game.addChild(electricField);
// Destroy both bullets
bullet.destroy();
blackBullets.splice(i, 1);
whiteBullets[j].destroy();
whiteBullets.splice(j, 1);
LK.getSound('explosion').play();
break;
}
}
}
for (var i = skinTanks.length - 1; i >= 0; i--) {
if (skinTanks[i].intersects(playerTank)) {
createExplosion(skinTanks[i].x, skinTanks[i].y, skinTanks[i].explosionRadius, 20);
skinTanks[i].destroy();
skinTanks.splice(i, 1);
}
}
for (var i = redTanks.length - 1; i >= 0; i--) {
if (redTanks[i].intersects(playerTank)) {
// Check if any part of player is within circular explosion area (radius 100)
// Player tank is 120px wide, so radius is 60px
var dx = playerTank.x - redTanks[i].x;
var dy = playerTank.y - redTanks[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
var playerRadius = 60; // Half of player tank width (120px)
var explosionRadius = 100;
// Check if there's a clear path from explosion center to player (no walls blocking)
var canDamagePlayer = true;
var stepSize = 32; // Check every 32 pixels along the path
var steps = Math.ceil(distance / stepSize);
for (var step = 1; step <= steps; step++) {
var checkX = redTanks[i].x + dx * step / steps;
var checkY = redTanks[i].y + dy * step / steps;
if (checkWallCollision(checkX, checkY)) {
canDamagePlayer = false;
break;
}
}
if (distance <= explosionRadius + playerRadius && canDamagePlayer) {
// Any part of player is within explosion radius and no walls block - deal 70 damage
playerTank.health -= 70;
LK.getSound('hit').play();
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
createExplosion(redTanks[i].x, redTanks[i].y, 100, 0); // No additional damage from explosion
redTanks[i].destroy();
redTanks.splice(i, 1);
}
}
// Check medkit collision for healing
for (var i = medkits.length - 1; i >= 0; i--) {
var medkit = medkits[i];
var dx = playerTank.x - medkit.x;
var dy = playerTank.y - medkit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50 && playerTank.health < playerTank.maxHealth) {
// Close enough to collect medkit and player needs healing
playerTank.health = playerTank.maxHealth; // Restore to full health
medkit.destroy();
medkits.splice(i, 1);
LK.getSound('hit').play(); // Use existing sound for medkit pickup
// Achievement: Use first medkit
if (!hasUsedMedkit) {
hasUsedMedkit = true;
achievements.useFirstMedkit = true;
storage.achievements = achievements;
}
}
}
// Check bear trap collision and proximity
var nearbyTrap = null;
for (var i = bearTraps.length - 1; i >= 0; i--) {
var bearTrap = bearTraps[i];
if (!bearTrap.isArmed) continue;
var dx = playerTank.x - bearTrap.x;
var dy = playerTank.y - bearTrap.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Direct collision - damage player and destroy trap
if (distance < 40) {
var damage = hardModeEnabled ? bearTrap.damage * 2 : bearTrap.damage;
playerTank.health -= damage;
hasBeenHurt = true;
LK.getSound('hit').play();
bearTrap.destroy();
bearTraps.splice(i, 1);
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
// Near but not touching - show disarm button
if (distance < 100 && distance >= 40) {
nearbyTrap = bearTrap;
}
}
// Update disarm button visibility
if (nearbyTrap && nearbyTrap !== currentNearbyTrap) {
currentNearbyTrap = nearbyTrap;
disarmButton.visible = true;
disarmButtonBg.visible = true;
} else if (!nearbyTrap && currentNearbyTrap) {
currentNearbyTrap = null;
disarmButton.visible = false;
disarmButtonBg.visible = false;
}
// Check if player is close to portal (within 100 pixels)
var dx = playerTank.x - portal.x;
var dy = playerTank.y - portal.y;
var distanceToPortal = Math.sqrt(dx * dx + dy * dy);
if (distanceToPortal < 100) {
if (hardModeEnabled && !firstPortalUsed) {
// In hard mode, first portal disappears and creates a new one
firstPortalUsed = true;
previousPortalX = portal.x;
previousPortalY = portal.y;
portal.destroy();
// Create new portal in a different location
var newPortal = new Portal();
var attempts = 0;
var maxAttempts = 50;
do {
newPortal.x = Math.random() * (2048 - 200) + 100;
newPortal.y = Math.random() * (2732 - 200) + 100;
attempts++;
// If we can't find a reachable position after many attempts, reduce wall density
if (attempts > maxAttempts) {
// Remove some random walls to create more open paths
for (var i = walls.length - 1; i >= 0 && walls.length > 20; i--) {
if (Math.random() < 0.1) {
walls[i].destroy();
walls.splice(i, 1);
}
}
attempts = 0;
}
} while ((checkWallCollision(newPortal.x, newPortal.y) || getDistanceToPlayer(newPortal.x, newPortal.y) < 300 || Math.abs(newPortal.x - previousPortalX) < 200 && Math.abs(newPortal.y - previousPortalY) < 200 || !canReachPosition(playerTank.x, playerTank.y, newPortal.x, newPortal.y)) && attempts < maxAttempts);
portal = newPortal;
game.addChild(portal);
return;
}
// Achievement: Kill all enemies in map
var totalEnemiesRemaining = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length + orangeTanks.length + blueTanks.length + iceTanks.length;
if (totalEnemiesRemaining === 0) {
achievements.killAllEnemies = true;
storage.achievements = achievements;
}
// Achievement: Finish without dying
if (!hasBeenHurt) {
achievements.finishWithoutDying = true;
storage.achievements = achievements;
// Track consecutive levels without dying
levelsWithoutDying++;
storage.levelsWithoutDying = levelsWithoutDying;
// Achievement: Pass 5 levels without dying
if (levelsWithoutDying >= 5 && !achievements.pass5LevelsWithoutDying) {
achievements.pass5LevelsWithoutDying = true;
storage.achievements = achievements;
}
} else {
// Reset consecutive levels counter if player was hurt
levelsWithoutDying = 0;
storage.levelsWithoutDying = levelsWithoutDying;
}
LK.getSound('win').play();
// Clear current level enemies and bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
for (var i = dynamites.length - 1; i >= 0; i--) {
dynamites[i].destroy();
}
dynamites = [];
for (var i = acidBombs.length - 1; i >= 0; i--) {
acidBombs[i].destroy();
}
acidBombs = [];
for (var i = explosions.length - 1; i >= 0; i--) {
explosions[i].destroy();
}
explosions = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
for (var i = bearTraps.length - 1; i >= 0; i--) {
bearTraps[i].destroy();
}
bearTraps = [];
// Hide disarm button when completing level
disarmButton.visible = false;
disarmButtonBg.visible = false;
currentNearbyTrap = null;
// Remove current portal
portal.destroy();
// Reset portal tracking for next level
firstPortalUsed = false;
previousPortalX = 0;
previousPortalY = 0;
// Advance to next level
currentLevel++;
// Show next level screen
nextLevelScreen.visible = true;
gamePaused = true;
}
// Spawn falling fireballs in lava map style
if (mapStyle === 'lava' && Math.random() < 0.001) {
// Very rare spawn
var fallingFireball = new FallingFireball();
fallingFireball.targetX = playerTank.x + (Math.random() - 0.5) * 200; // Around player position
fallingFireball.targetY = playerTank.y + (Math.random() - 0.5) * 200;
fallingFireballs.push(fallingFireball);
game.addChild(fallingFireball);
}
// Handle fire signs damage
for (var i = fireSigns.length - 1; i >= 0; i--) {
var fireSign = fireSigns[i];
var dx = playerTank.x - fireSign.x;
var dy = playerTank.y - fireSign.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 32 && fireSign.damageTimer >= 60) {
// Every second
var damage = hardModeEnabled ? fireSign.damage * 2 : fireSign.damage;
playerTank.health -= damage;
fireSign.damageTimer = 0;
hasBeenHurt = true;
LK.getSound('hit').play();
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
}
// Handle fireballs
for (var i = fireballs.length - 1; i >= 0; i--) {
var fireball = fireballs[i];
if (fireball.x < 0 || fireball.x > 2048 || fireball.y < 0 || fireball.y > 2732) {
fireball.destroy();
fireballs.splice(i, 1);
continue;
}
if (checkWallCollision(fireball.x, fireball.y)) {
fireball.destroy();
fireballs.splice(i, 1);
continue;
}
if (fireball.intersects(playerTank)) {
var damage = hardModeEnabled ? fireball.damage * 2 : fireball.damage;
playerTank.health -= damage;
fireball.destroy();
fireballs.splice(i, 1);
LK.getSound('hit').play();
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
}
// Handle waterballs
for (var i = waterballs.length - 1; i >= 0; i--) {
var waterball = waterballs[i];
if (waterball.x < 0 || waterball.x > 2048 || waterball.y < 0 || waterball.y > 2732) {
waterball.destroy();
waterballs.splice(i, 1);
continue;
}
if (checkWallCollision(waterball.x, waterball.y)) {
waterball.destroy();
waterballs.splice(i, 1);
continue;
}
if (waterball.intersects(playerTank)) {
var damage = hardModeEnabled ? waterball.damage * 2 : waterball.damage;
playerTank.health -= damage;
// Create 8 smaller waterballs
for (var j = 0; j < 8; j++) {
var smallWaterball = new Waterball();
smallWaterball.x = waterball.x;
smallWaterball.y = waterball.y;
var angle = j / 8 * Math.PI * 2;
smallWaterball.directionX = Math.cos(angle);
smallWaterball.directionY = Math.sin(angle);
smallWaterball.speed = 2;
smallWaterball.damage = hardModeEnabled ? 2 : 1;
waterballs.push(smallWaterball);
game.addChild(smallWaterball);
}
waterball.destroy();
waterballs.splice(i, 1);
LK.getSound('hit').play();
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
// Check if small waterballs hit other tanks
for (var j = orangeTanks.length - 1; j >= 0; j--) {
if (waterball.intersects(orangeTanks[j])) {
orangeTanks[j].targetPlayer = false; // Stop attacking player
waterball.destroy();
waterballs.splice(i, 1);
break;
}
}
}
// Handle ice blocks
for (var i = iceBlocks.length - 1; i >= 0; i--) {
var iceBlock = iceBlocks[i];
if (iceBlock.x < 0 || iceBlock.x > 2048 || iceBlock.y < 0 || iceBlock.y > 2732) {
iceBlock.destroy();
iceBlocks.splice(i, 1);
continue;
}
if (checkWallCollision(iceBlock.x, iceBlock.y)) {
iceBlock.destroy();
iceBlocks.splice(i, 1);
continue;
}
if (iceBlock.intersects(playerTank)) {
var damage = hardModeEnabled ? iceBlock.damage * 2 : iceBlock.damage;
playerTank.health -= damage;
iceBlock.destroy();
iceBlocks.splice(i, 1);
LK.getSound('hit').play();
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
}
// Handle orange tank collisions with player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
for (var j = orangeTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(orangeTanks[j])) {
orangeTanks[j].health -= 5;
bullet.destroy();
playerBullets.splice(i, 1);
if (orangeTanks[j].health <= 0) {
orangeTanks[j].destroy();
orangeTanks.splice(j, 1);
LK.setScore(LK.getScore() + 35);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = blueTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(blueTanks[j])) {
blueTanks[j].health -= 3;
bullet.destroy();
playerBullets.splice(i, 1);
if (blueTanks[j].health <= 0) {
blueTanks[j].destroy();
blueTanks.splice(j, 1);
LK.setScore(LK.getScore() + 25);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = iceTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(iceTanks[j])) {
iceTanks[j].health -= 25;
// Show breaking animation
tween(iceTanks[j], {
alpha: 0.5,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
tween(iceTanks[j], {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
bullet.destroy();
playerBullets.splice(i, 1);
if (iceTanks[j].health <= 0) {
iceTanks[j].destroy();
iceTanks.splice(j, 1);
LK.setScore(LK.getScore() + 15);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
}
break;
}
}
}
// Update score display
scoreText.setText('Score: ' + LK.getScore());
// Update best score if current score is higher
var currentScore = LK.getScore();
var bestScore = storage.bestScore || 0;
if (currentScore > bestScore) {
storage.bestScore = currentScore;
bestScoreText.setText('Best: ' + currentScore);
// Achievement: Beat previous best score
if (bestScore > 0) {
achievements.beatPreviousBest = true;
storage.achievements = achievements;
}
}
// Achievement: Get 150 Score
if (currentScore >= 150 && !achievements.get150Score) {
achievements.get150Score = true;
storage.achievements = achievements;
}
// Achievement: Have 1000 Score
if (currentScore >= 1000 && !hasReachedScore1000) {
hasReachedScore1000 = true;
storage.hasReachedScore1000 = hasReachedScore1000;
achievements.have1000Score = true;
storage.achievements = achievements;
}
var healthPercentage = Math.max(0, playerTank.health) / 100;
healthBarFill.scaleX = 4 * healthPercentage;
if (healthPercentage > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercentage > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
pixel art dynamite. In-Game asset. 2d. High contrast. No shadows
skin color tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
green tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
red tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
blue tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
pixel art bullet. In-Game asset. 2d. High contrast. No shadows
a green bomb (pixel art) writes "Acid" on it. In-Game asset. 2d. High contrast. No shadows
medkit pixel art. In-Game asset. 2d. High contrast. No shadows
dark green square 16*16 pixels pixel art. In-Game asset. 2d. High contrast. No shadows
orange circle pixel art. In-Game asset. 2d. High contrast. No shadows
A portal, outline is purple, and inside is magenta. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat pixel art
dark gray square 16*16 pixels pixel art.. In-Game asset. 2d. High contrast. No shadows
pixel art blackhole. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Pixel art bear trap top down. In-Game asset. 2d. High contrast. No shadows