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