User prompt
Que la doble pistola solo la puede atener cuando derroté el primer boss ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Y por último aumenta la hitbox del boss y que no sea tan grande el boss
User prompt
Y que en cada noche aparezcan ma monstruos y hagan un 0.50% más de daño en cada noche y lo mismo con velocidad, y que aparezcan variedades de monstruos, como varios sworm, tank y sccot
User prompt
Que al tradear con el npc aparezcan los botones con buff aleatorios pero con precios, y que al presionar ese buff gastaría esa cierta cantidad de dinero pero mi personaje tendría ese buff por el resto de la partida ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Y dale una textura única al boss del día 10
User prompt
Hay un bug donde los días de la nada aparecen en 30 arregla esto y también otro bug donde el boss del día 3 aparece en el día
User prompt
Ahora creemos un nuevo boss qué spamee en la noche 15 y que sea un árbol que este en el medio y sus ataques son estos, cada 3 segundos dispare 3 balas al player qué cada una haga 5 de daño, y su habilidad cuando tenga la mitad de la vida sea que dispare proyectiles sin parar al player por 5 segundos, y su coldown sea de 3 segundos
User prompt
Ahora que haigan 5 recursos por cada día, y que cuando tenga la doble pistola la tenga por el resto de la partida, y que se recargue también
User prompt
Ahora que el modo berserk de los personajes se quite cuando el personaje tiene más de 30 de vida, y que cada 5 días spamee una poción qué regenera 15 de vida
User prompt
Que los días se pasen en orden del 1a al 100
User prompt
Soluciona ese error [L43]
User prompt
Aun no me deja abrir el juego
User prompt
Haz que me deje entrar al juego
User prompt
Por último haz que le pueda hacer daño a los enemigos con las balas
User prompt
Haz que le pueda hacer daño a los enemigos
User prompt
Bien ahora haz que se le pueda hacer daño a los enemigos, un corrupted sworm de 1 disparo, un corrupted tank de 3 disparos, y un corrupted scout de 2 tiros
User prompt
Y cuando aparezca un boss se haga una cinemática épica donde la cámara se acerca al boss mostrando uan animación épica y después de 2 segundos la cámara vuelve a su estado normal ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Arregla a los enemigos que me hagan daño y que yo a ellos también, y cuando el personaje esté en modo berserk 30% de vida, que el personaje se ponga de tono rojo y le de su velocidad y más daño ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pero a las balas déjale la textura que tenían y dale la animacion épica de correr al player ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Esa posición está muuuuyyyy mal para el menú principal arregla esto
User prompt
Arregla en el menú principal la textura que este bien ubicada y el fondo de atrás que sea morado
User prompt
Optimiza un poco el juego para que pueda entrar
User prompt
Aumenta la hitbox un poco de los enemigos para darle un golpe más fácil, y en el menú principal ponle una textura al nombre del juego y un fondo atrás épico
User prompt
Haz que me deje entrar al juego que no deja
User prompt
Optimiza para que pueda entrar al juego que no deja, y te olvidaste de los corruptos tank pon que aparezca 1 por cada noche y cada noche se suma 1 más
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Remove bomb tint for performance
self.speed = 6;
self.type = 'bomb';
self.direction = {
x: 0,
y: 0
};
self.explosionRadius = 120;
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Remove bomb if it goes off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
for (var i = bombs.length - 1; i >= 0; i--) {
if (bombs[i] === self) {
bombs.splice(i, 1);
break;
}
}
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('bossTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
// Remove boss tint for performance
self.health = 20;
self.maxHealth = 20;
self.speed = 0; // Boss doesn't move
self.damage = 30;
self.type = 'boss';
self.spawnTimer = 0;
self.attackTimer = 0;
self.attackWarning = null;
self.attackCooldown = 300; // 5 seconds between attacks
self.update = function () {
// Boss stays at center
self.x = 1024;
self.y = 1366;
// Attack system
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
self.attackTimer = 0;
// Special lightning attack when health is low
if (self.health <= 5) {
// Create multiple warnings
var warningPositions = [];
for (var w = 0; w < 5; w++) {
var warning = game.addChild(new Text2('!', {
size: 150,
fill: 0xFFFF00
}));
warning.anchor.set(0.5, 0.5);
warning.x = player.x + (Math.random() - 0.5) * 300;
warning.y = player.y + (Math.random() - 0.5) * 300;
warning.alpha = 1;
warningPositions.push(warning);
// Flash warning
tween(warning, {
alpha: 0.3,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeInOut
});
}
// Lightning attack after 2 seconds
LK.setTimeout(function () {
for (var i = 0; i < warningPositions.length; i++) {
var warning = warningPositions[i];
if (warning) {
// Create lightning effect
var lightning = game.addChild(LK.getAsset('lightningTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
}));
lightning.x = warning.x;
lightning.y = warning.y;
lightning.tint = 0xFFFF00;
// Check if player is in lightning area
var dx = player.x - warning.x;
var dy = player.y - warning.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
playerHealth -= 40;
healthText.setText('Health: ' + playerHealth);
LK.getSound('damage').play();
if (playerHealth <= 0) {
LK.showGameOver();
}
}
// Lightning effect lasts 3 seconds
LK.setTimeout(function () {
if (lightning) {
lightning.destroy();
}
}, 3000);
warning.destroy();
}
}
}, 2000);
} else {
// Normal attack
if (self.attackWarning) {
self.attackWarning.destroy();
}
self.attackWarning = game.addChild(LK.getAsset('bossAttackTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 3.0
}));
self.attackWarning.x = player.x;
self.attackWarning.y = player.y;
self.attackWarning.alpha = 1;
self.attackWarning.tint = 0xFF0000;
// Flash warning
tween(self.attackWarning, {
alpha: 0.3,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeInOut
});
// Attack after 2 seconds
LK.setTimeout(function () {
if (self.attackWarning) {
// Check if player is still in attack area
var dx = player.x - self.attackWarning.x;
var dy = player.y - self.attackWarning.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
// Player is in attack area, take damage
// Increase boss damage by 0.5% per night
var damageMultiplier = 1 + currentNight * 0.005;
var actualDamage = Math.floor(self.damage * damageMultiplier);
playerHealth -= actualDamage;
healthText.setText('Health: ' + playerHealth);
LK.getSound('damage').play();
if (playerHealth <= 0) {
LK.showGameOver();
}
}
// Create explosion effect
LK.effects.flashObject(self.attackWarning, 0xFF6600, 500);
self.attackWarning.destroy();
self.attackWarning = null;
}
}, 2000);
}
}
// Spawn zombies every 10 seconds (600 frames at 60fps)
self.spawnTimer++;
if (self.spawnTimer >= 600) {
self.spawnTimer = 0;
// Spawn a zombie near the boss
var zombie = new CorruptedScout();
zombie.x = self.x + (Math.random() - 0.5) * 200;
zombie.y = self.y + (Math.random() - 0.5) * 200;
zombie.health = 15; // Weaker zombies
monsters.push(zombie);
game.addChild(zombie);
}
};
self.takeDamage = function (damage) {
var actualDamage = Math.floor(damage * characterStats.damageMultiplier);
self.health -= actualDamage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bulletTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
// Remove bullet tint for performance
self.speed = 8;
self.damage = 1;
self.type = 'bullet';
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Remove bullet if it goes off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var CorruptedScout = Container.expand(function () {
var self = Container.call(this);
var scoutGraphics = self.attachAsset('corruptedScout', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.maxHealth = 2;
self.speed = 2;
self.damage = 10;
self.type = 'scout';
self.isDead = false;
self.deadTimer = 0;
self.update = function () {
if (self.isDead) {
self.deadTimer++;
if (self.deadTimer >= 120) {
// 2 seconds at 60fps
self.destroy();
for (var i = monsters.length - 1; i >= 0; i--) {
if (monsters[i] === self) {
monsters.splice(i, 1);
break;
}
}
}
return;
}
// Always pursue the player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Calculate intended next position
var nextX = self.x + dx / distance * self.speed;
var nextY = self.y + dy / distance * self.speed;
var blocked = false;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
if (wall.health > 0) {
// Simulate monster at next position
var tempDist = Math.sqrt((nextX - wall.x) * (nextX - wall.x) + (nextY - wall.y) * (nextY - wall.y));
if (tempDist < 50) {
blocked = true;
break;
}
}
}
if (!blocked) {
self.x = nextX;
self.y = nextY;
// Minimal animation for performance
if (LK.ticks % 300 === 0) {
self.scaleX = self.scaleX === 1.0 ? 1.02 : 1.0;
}
}
}
};
self.takeDamage = function (damage) {
var actualDamage = Math.floor(damage * characterStats.damageMultiplier);
self.health -= actualDamage;
if (self.health <= 0) {
self.isDead = true;
self.alpha = 0.5;
scoutGraphics.rotation = Math.PI / 2; // Rotate to show fallen
return true;
}
return false;
};
return self;
});
var CorruptedSwarm = Container.expand(function () {
var self = Container.call(this);
var swarmGraphics = self.attachAsset('corruptedSwarm', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.maxHealth = 1;
self.speed = 3;
self.damage = 5;
self.type = 'swarm';
self.isDead = false;
self.deadTimer = 0;
self.update = function () {
if (self.isDead) {
self.deadTimer++;
if (self.deadTimer >= 120) {
// 2 seconds at 60fps
self.destroy();
for (var i = monsters.length - 1; i >= 0; i--) {
if (monsters[i] === self) {
monsters.splice(i, 1);
break;
}
}
}
return;
}
// Always pursue the player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Calculate intended next position
var nextX = self.x + dx / distance * self.speed;
var nextY = self.y + dy / distance * self.speed;
var blocked = false;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
if (wall.health > 0) {
var tempDist = Math.sqrt((nextX - wall.x) * (nextX - wall.x) + (nextY - wall.y) * (nextY - wall.y));
if (tempDist < 50) {
blocked = true;
break;
}
}
}
if (!blocked) {
self.x = nextX;
self.y = nextY;
// Minimal animation for performance
if (LK.ticks % 450 === 0) {
self.scaleX = self.scaleX === 1.0 ? 1.05 : 1.0;
}
}
}
};
self.takeDamage = function (damage) {
var actualDamage = Math.floor(damage * characterStats.damageMultiplier);
self.health -= actualDamage;
if (self.health <= 0) {
self.isDead = true;
self.alpha = 0.5;
swarmGraphics.rotation = Math.PI / 2; // Rotate to show fallen
return true;
}
return false;
};
return self;
});
var CorruptedTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('corruptedTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.maxHealth = 3;
self.speed = 1;
self.damage = 25;
self.type = 'tank';
self.isDead = false;
self.deadTimer = 0;
self.update = function () {
if (self.isDead) {
self.deadTimer++;
if (self.deadTimer >= 120) {
// 2 seconds at 60fps
self.destroy();
for (var i = monsters.length - 1; i >= 0; i--) {
if (monsters[i] === self) {
monsters.splice(i, 1);
break;
}
}
}
return;
}
// Always pursue the player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Calculate intended next position
var nextX = self.x + dx / distance * self.speed;
var nextY = self.y + dy / distance * self.speed;
var blocked = false;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
if (wall.health > 0) {
var tempDist = Math.sqrt((nextX - wall.x) * (nextX - wall.x) + (nextY - wall.y) * (nextY - wall.y));
if (tempDist < 50) {
blocked = true;
break;
}
}
}
if (!blocked) {
self.x = nextX;
self.y = nextY;
// Minimal animation for performance
if (LK.ticks % 600 === 0) {
self.scaleX = self.scaleX === 1.0 ? 1.03 : 1.0;
}
}
}
};
self.takeDamage = function (damage) {
var actualDamage = Math.floor(damage * characterStats.damageMultiplier);
self.health -= actualDamage;
if (self.health <= 0) {
self.isDead = true;
self.alpha = 0.5;
tankGraphics.rotation = Math.PI / 2; // Rotate to show fallen
return true;
}
return false;
};
return self;
});
var DualPistol = Container.expand(function () {
var self = Container.call(this);
var pistolGraphics = self.attachAsset('pistolTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
// Remove dual pistol tint for performance
self.type = 'dualPistol';
self.bullets = 6;
self.maxBullets = 6;
self.isReloading = false;
self.reloadTimer = 0;
self.update = function () {
self.rotation += 0.05;
if (self.isReloading) {
self.reloadTimer--;
if (self.reloadTimer <= 0) {
self.isReloading = false;
self.bullets = self.maxBullets;
}
}
};
self.canShoot = function () {
return self.bullets > 0 && !self.isReloading;
};
self.shoot = function () {
if (self.canShoot()) {
self.bullets--;
if (self.bullets <= 0) {
self.isReloading = true;
self.reloadTimer = 180; // 3 seconds
}
return true;
}
return false;
};
return self;
});
var RandomBoss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('bossTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 3.0
});
// Remove random boss tint for performance
self.health = 30;
self.maxHealth = 30;
self.speed = 1;
self.damage = 40;
self.type = 'randomBoss';
self.attackTimer = 0;
self.attackCooldown = 240; // 4 seconds between attacks
self.update = function () {
// Move towards player slowly
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Attack system
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
self.attackTimer = 0;
// Spawn corrupted scouts around the boss
for (var i = 0; i < 3; i++) {
var scout = new CorruptedScout();
scout.x = self.x + (Math.random() - 0.5) * 150;
scout.y = self.y + (Math.random() - 0.5) * 150;
scout.health = 3; // Stronger scouts
monsters.push(scout);
game.addChild(scout);
}
}
};
self.takeDamage = function (damage) {
var actualDamage = Math.floor(damage * characterStats.damageMultiplier);
self.health -= actualDamage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var Resource = Container.expand(function () {
var self = Container.call(this);
var resourceGraphics = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
self.value = 10;
self.type = 'resource';
self.update = function () {
self.rotation += 0.05;
};
self.down = function (x, y, obj) {
// Allow direct tapping on resources to collect them
playerResources += self.value;
resourceText.setText('Resources: ' + playerResources);
self.destroy();
for (var i = resources.length - 1; i >= 0; i--) {
if (resources[i] === self) {
resources.splice(i, 1);
break;
}
}
LK.getSound('collect').play();
};
return self;
});
var TraderNPC = Container.expand(function () {
var self = Container.call(this);
var traderGraphics = self.attachAsset('traderNPC', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
// Remove trader tint for performance
self.type = 'trader';
self.update = function () {
// Trader stays stationary - no movement
};
return self;
});
var Trap = Container.expand(function () {
var self = Container.call(this);
var trapGraphics = self.attachAsset('trap', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 30;
self.cooldown = 0;
self.type = 'trap';
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
}
};
self.activate = function () {
if (self.cooldown <= 0) {
self.cooldown = 60;
LK.effects.flashObject(self, 0xff6b35, 300);
return self.damage;
}
return 0;
};
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.type = 'wall';
// Track monster hits
self.hitCount = 0;
self.lastMonsterHitTick = 0; // LK.ticks of last monster hit
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
wallGraphics.alpha = 0.3;
} else {
wallGraphics.alpha = 0.5 + self.health / self.maxHealth * 0.5;
}
};
self.registerMonsterHit = function () {
self.hitCount++;
self.lastMonsterHitTick = LK.ticks;
if (self.hitCount >= 3) {
self.health = 0;
wallGraphics.alpha = 0.3;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Initialize game safely with error handling
try {
// Frames left for placement cooldown (60 = 1s)
// Update UI visibility based on game state
var _updateUIVisibility = function _updateUIVisibility() {
if (gameState === 'mainMenu') {
mainMenuContainer.alpha = 1;
characterMenuContainer.alpha = 0;
gameStateText.alpha = 0;
timerText.alpha = 0;
healthText.alpha = 0;
resourceText.alpha = 0;
nightText.alpha = 0;
joystickBase.alpha = 0;
joystickKnob.alpha = 0;
wallButton.alpha = 0;
trapButton.alpha = 0;
collectButton.alpha = 0;
wallButtonText.alpha = 0;
trapButtonText.alpha = 0;
collectButtonText.alpha = 0;
wallIcon.alpha = 0;
trapIcon.alpha = 0;
defenseText.alpha = 0;
healButton.alpha = 0;
healButtonText.alpha = 0;
bossHealthBar.alpha = 0;
bossHealthBarFill.alpha = 0;
bossHealthText.alpha = 0;
} else if (gameState === 'characterSelect') {
mainMenuContainer.alpha = 0;
characterMenuContainer.alpha = 1;
gameStateText.alpha = 0;
timerText.alpha = 0;
healthText.alpha = 0;
resourceText.alpha = 0;
nightText.alpha = 0;
joystickBase.alpha = 0;
joystickKnob.alpha = 0;
wallButton.alpha = 0;
trapButton.alpha = 0;
collectButton.alpha = 0;
wallButtonText.alpha = 0;
trapButtonText.alpha = 0;
collectButtonText.alpha = 0;
wallIcon.alpha = 0;
trapIcon.alpha = 0;
defenseText.alpha = 0;
healButton.alpha = 0;
healButtonText.alpha = 0;
bossHealthBar.alpha = 0;
bossHealthBarFill.alpha = 0;
bossHealthText.alpha = 0;
} else {
mainMenuContainer.alpha = 0;
characterMenuContainer.alpha = 0;
gameStateText.alpha = 1;
timerText.alpha = 1;
healthText.alpha = 1;
resourceText.alpha = 1;
nightText.alpha = 1;
joystickBase.alpha = 0.5;
joystickKnob.alpha = 1;
wallButton.alpha = 1;
trapButton.alpha = 1;
collectButton.alpha = 1;
wallButtonText.alpha = 1;
trapButtonText.alpha = 1;
collectButtonText.alpha = 1;
wallIcon.alpha = 1;
trapIcon.alpha = 1;
defenseText.alpha = gameState === 'day' ? 1 : 0;
}
};
// Add backgrounds
var dayBackground = game.addChild(LK.getAsset('dayBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
dayBackground.alpha = 1;
var nightBackground = game.addChild(LK.getAsset('nightBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
nightBackground.alpha = 0;
var gameState = 'mainMenu'; // Start with main menu
var currentNight = 0;
var dayTimer = 1800; // 30 seconds at 60fps
var nightTimer = 0;
var playerHealth = 100;
var playerResources = 50;
var selectedDefense = 'wall';
var walls = [];
var traps = [];
var resources = [];
var monsters = [];
var boss = null;
var randomBoss = null;
var bullets = [];
var bombs = [];
var playerPistol = true; // Player has pistol
var pistolBullets = 5; // Bullets left before reload
var pistolReloading = false; // Is pistol reloading
var pistolReloadTimer = 0; // Frames left for reload (180 = 3s)
var hasDualPistol = false; // Player has dual pistol
var dualPistolWeapon = null; // Dual pistol weapon object
var dualPistolPickup = null; // Dual pistol pickup object
var weaponPickupText = null; // Weapon pickup message
var selectedCharacter = storage.selectedCharacter || 0; // 0=damage, 1=heal, 2=discount
var characterStats = {
damageMultiplier: 1.0,
healPerNight: selectedCharacter === 1 ? 10 : 0,
discountMultiplier: 1.0
};
// Trader system variables
var currentDay = storage.currentDay || 1;
var traderActive = false;
var traderContainer = null;
var weaponUpgradePurchased = storage.weaponUpgradePurchased || false;
var costReductionPurchased = storage.costReductionPurchased || false;
var traderNPC = null;
var isTrading = false;
var playerCanMove = true;
var traderUpgrades = [{
name: "Weapon Damage +10%",
cost: 50,
type: "weapon",
purchased: false
}, {
name: "Build Cost -10%",
cost: 30,
type: "cost",
purchased: false
}, {
name: "Health +20",
cost: 40,
type: "health",
purchased: false
}, {
name: "Speed +20%",
cost: 35,
type: "speed",
purchased: false
}, {
name: "Reload Speed +30%",
cost: 45,
type: "reload",
purchased: false
}];
// Special ability states
var berserkMode = false;
var berserkUsed = false;
var medicReviveUsed = false;
var engineerBoostActive = false;
var engineerBoostUsed = false;
var slowEnemiesActive = false;
var slowEnemiesTimer = 0;
// Heal button for medic character
var healButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: 0,
scaleX: 3,
scaleY: 3
});
// Remove heal button tint for performance
healButton.alpha = 0;
var healButtonText = new Text2('HEAL', {
size: 60,
fill: 0xFFFFFF
});
healButtonText.anchor.set(0.5, 0.5);
healButtonText.x = -250;
healButtonText.y = 0;
healButtonText.alpha = 0;
LK.gui.center.addChild(healButton);
LK.gui.center.addChild(healButtonText);
var pistolReloadText = new Text2('', {
size: 80,
fill: 0xFF0000
});
pistolReloadText.anchor.set(0.5, 0.5);
pistolReloadText.x = 0;
pistolReloadText.y = 200;
pistolReloadText.alpha = 0;
LK.gui.center.addChild(pistolReloadText);
// Main Menu UI
var mainMenuContainer = new Container();
// Add epic background to main menu
var epicMenuBg = LK.getAsset('epicBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 1.0,
scaleY: 1.0
});
epicMenuBg.tint = 0x8B008B; // Purple tint for epic background
mainMenuContainer.addChild(epicMenuBg);
// Add textured title
var mainMenuTitle = LK.getAsset('titleTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -300,
scaleX: 2.0,
scaleY: 2.0
});
mainMenuTitle.tint = 0xFFD700; // Gold tint for epic look
mainMenuContainer.addChild(mainMenuTitle);
var playButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scaleX: 4,
scaleY: 2
});
var playButtonText = new Text2('PLAY', {
size: 80,
fill: 0xFFFFFF
});
playButtonText.anchor.set(0.5, 0.5);
playButtonText.x = 0;
playButtonText.y = -100;
mainMenuContainer.addChild(playButton);
mainMenuContainer.addChild(playButtonText);
// Add instructions text
var instructionsText = new Text2('Press (C) to collect resources\nand survive the nights!', {
size: 60,
fill: 0xFFD700
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 0;
instructionsText.y = 200;
mainMenuContainer.addChild(instructionsText);
var charactersButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 50,
scaleX: 4,
scaleY: 2
});
var charactersButtonText = new Text2('CHARACTERS', {
size: 80,
fill: 0xFFFFFF
});
charactersButtonText.anchor.set(0.5, 0.5);
charactersButtonText.x = 0;
charactersButtonText.y = 50;
mainMenuContainer.addChild(charactersButton);
mainMenuContainer.addChild(charactersButtonText);
LK.gui.center.addChild(mainMenuContainer);
// Character Selection UI
var characterMenuContainer = new Container();
var characterMenuTitle = new Text2('SELECT CHARACTER', {
size: 100,
fill: 0xFFFFFF
});
characterMenuTitle.anchor.set(0.5, 0.5);
characterMenuTitle.x = 0;
characterMenuTitle.y = -400;
characterMenuContainer.addChild(characterMenuTitle);
// Character 1 - Damage
var char1Button = LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
y: -100,
scaleX: 2,
scaleY: 2
});
var char1Text = new Text2('WARRIOR\n+30% Damage', {
size: 50,
fill: 0xFFFFFF
});
char1Text.anchor.set(0.5, 0.5);
char1Text.x = -300;
char1Text.y = 50;
characterMenuContainer.addChild(char1Button);
characterMenuContainer.addChild(char1Text);
// Character 2 - Heal
var char2Button = LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scaleX: 2,
scaleY: 2
});
var char2Text = new Text2('MEDIC\n+10 Health\nper Night', {
size: 50,
fill: 0xFFFFFF
});
char2Text.anchor.set(0.5, 0.5);
char2Text.x = 0;
char2Text.y = 50;
characterMenuContainer.addChild(char2Button);
characterMenuContainer.addChild(char2Text);
// Character 3 - Discount
var char3Button = LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: -100,
scaleX: 2,
scaleY: 2
});
var char3Text = new Text2('ENGINEER\n-20% Build\nCost', {
size: 50,
fill: 0xFFFFFF
});
// Remove character selection visual state tints
char3Text.anchor.set(0.5, 0.5);
char3Text.x = 300;
char3Text.y = 50;
characterMenuContainer.addChild(char3Button);
characterMenuContainer.addChild(char3Text);
var backButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 300,
scaleX: 3,
scaleY: 2
});
var backButtonText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 0;
backButtonText.y = 300;
characterMenuContainer.addChild(backButton);
characterMenuContainer.addChild(backButtonText);
characterMenuContainer.alpha = 0;
LK.gui.center.addChild(characterMenuContainer);
var player = game.addChild(LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
// Remove character colors - no tint applied
// Button visibility is now handled by the UI buttons
disablePlacement = false;
var gameStateText = new Text2('Day Phase', {
size: 80,
fill: 0xFFFFFF
});
gameStateText.anchor.set(0.5, 0);
LK.gui.top.addChild(gameStateText);
var timerText = new Text2('30s', {
size: 60,
fill: 0xFFFF00
});
timerText.anchor.set(0.5, 0);
timerText.y = 100;
LK.gui.top.addChild(timerText);
var healthText = new Text2('Health: 100', {
size: 50,
fill: 0xFF0000
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 120;
var resourceText = new Text2('Resources: 50', {
size: 50,
fill: 0xFFD700
});
resourceText.anchor.set(0, 0);
resourceText.y = 60;
LK.gui.topLeft.addChild(resourceText);
resourceText.x = 120;
var nightText = new Text2('Night: 0', {
size: 50,
fill: 0x8B3A8B
});
nightText.anchor.set(1, 0);
LK.gui.topRight.addChild(nightText);
// Boss health bar UI elements
var bossHealthBar = LK.getAsset('healthBarTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 150,
scaleX: 10,
scaleY: 1
});
bossHealthBar.tint = 0x333333;
bossHealthBar.alpha = 0;
LK.gui.top.addChild(bossHealthBar);
var bossHealthBarFill = LK.getAsset('healthBarTexture', {
anchorX: 0.0,
anchorY: 0.5,
x: -300,
y: 150,
scaleX: 10,
scaleY: 1
});
bossHealthBarFill.tint = 0xFF0000;
bossHealthBarFill.alpha = 0;
LK.gui.top.addChild(bossHealthBarFill);
var bossHealthText = new Text2('BOSS', {
size: 50,
fill: 0xFF0000
});
bossHealthText.anchor.set(0.5, 0.5);
bossHealthText.x = 0;
bossHealthText.y = 100;
bossHealthText.alpha = 0;
LK.gui.top.addChild(bossHealthText);
// Joystick control elements
var joystickBase = LK.getAsset('joystickTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: -300,
scaleX: 2.5,
scaleY: 2.5
});
joystickBase.alpha = 0.5;
LK.gui.bottomLeft.addChild(joystickBase);
var joystickKnob = LK.getAsset('joystickTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: -300,
scaleX: 1.5,
scaleY: 1.5
});
joystickKnob.tint = 0xFFFFFF;
LK.gui.bottomLeft.addChild(joystickKnob);
var joystickActive = false;
var joystickCenterX = 200;
var joystickCenterY = -300;
var joystickRadius = 60;
var defenseText = new Text2('Defense: Wall (Cost: 10)', {
size: 40,
fill: 0xFFFFFF
});
defenseText.anchor.set(0.5, 1);
defenseText.y = -120;
defenseText.alpha = 0;
LK.gui.bottom.addChild(defenseText);
// Action buttons on the right side
var wallButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
y: -200,
scaleX: 2.5,
scaleY: 2.5
});
LK.gui.bottomRight.addChild(wallButton);
var wallIcon = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
y: -200,
scaleX: 1.5,
scaleY: 1.5
});
LK.gui.bottomRight.addChild(wallIcon);
var trapButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: -200,
scaleX: 2.5,
scaleY: 2.5
});
LK.gui.bottomRight.addChild(trapButton);
var trapIcon = LK.getAsset('trap', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: -200,
scaleX: 1.5,
scaleY: 1.5
});
LK.gui.bottomRight.addChild(trapIcon);
var collectButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
y: -350,
scaleX: 2.5,
scaleY: 2.5
});
LK.gui.bottomRight.addChild(collectButton);
var wallButtonText = new Text2('W', {
size: 40,
fill: 0xFFFFFF
});
wallButtonText.anchor.set(0.5, 0.5);
wallButtonText.x = -300;
wallButtonText.y = -200;
LK.gui.bottomRight.addChild(wallButtonText);
var trapButtonText = new Text2('T', {
size: 40,
fill: 0xFFFFFF
});
trapButtonText.anchor.set(0.5, 0.5);
trapButtonText.x = -150;
trapButtonText.y = -200;
LK.gui.bottomRight.addChild(trapButtonText);
var collectButtonText = new Text2('C', {
size: 40,
fill: 0xFFFFFF
});
collectButtonText.anchor.set(0.5, 0.5);
collectButtonText.x = -300;
collectButtonText.y = -350;
LK.gui.bottomRight.addChild(collectButtonText);
// Movement control variables
var moveX = 0;
var moveY = 0;
var playerSpeed = 5;
// Pistol graphics
var pistolGraphics = null;
var pistolTimer = 0;
// Game mode state
var gameMode = 'build'; // 'build' or 'collect'
var disablePlacement = false; // Prevents placing objects while a button is pressed
var placementCooldown = 0;
_updateUIVisibility();
} catch (error) {
console.error('Game initialization error:', error);
// Fallback initialization
gameState = 'mainMenu';
playerHealth = 100;
playerResources = 50;
}
function createTraderUI() {
traderContainer = new Container();
// Background
var traderBg = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 8,
scaleY: 6
});
traderBg.tint = 0x333333;
traderContainer.addChild(traderBg);
// Title
var traderTitle = new Text2('TRADER', {
size: 80,
fill: 0xFFD700
});
traderTitle.anchor.set(0.5, 0.5);
traderTitle.x = 0;
traderTitle.y = -200;
traderContainer.addChild(traderTitle);
// Create upgrade buttons
var availableUpgrades = traderUpgrades.filter(function (upgrade) {
return !upgrade.purchased;
});
// Show up to 3 random upgrades
for (var i = 0; i < Math.min(3, availableUpgrades.length); i++) {
var upgrade = availableUpgrades[Math.floor(Math.random() * availableUpgrades.length)];
var yPos = -50 + i * 80;
var upgradeButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: yPos,
scaleX: 6,
scaleY: 1.5
});
upgradeButton.upgradeData = upgrade;
traderContainer.addChild(upgradeButton);
var upgradeText = new Text2(upgrade.name + ' - ' + upgrade.cost + ' Resources', {
size: 40,
fill: 0xFFFFFF
});
upgradeText.anchor.set(0.5, 0.5);
upgradeText.x = 0;
upgradeText.y = yPos;
traderContainer.addChild(upgradeText);
// Remove from available list to prevent duplicates
availableUpgrades.splice(availableUpgrades.indexOf(upgrade), 1);
}
// Close button
var closeButton = LK.getAsset('buttonTexture', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 150,
scaleX: 3,
scaleY: 2
});
var closeText = new Text2('CLOSE', {
size: 60,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 0;
closeText.y = 150;
traderContainer.addChild(closeButton);
traderContainer.addChild(closeText);
LK.gui.center.addChild(traderContainer);
}
function closeTrader() {
if (traderContainer) {
traderContainer.destroy();
traderContainer = null;
}
traderActive = false;
isTrading = false;
playerCanMove = true;
}
function purchaseUpgrade(upgrade) {
if (playerResources >= upgrade.cost) {
playerResources -= upgrade.cost;
resourceText.setText('Resources: ' + playerResources);
upgrade.purchased = true;
// Apply upgrade effects
switch (upgrade.type) {
case "weapon":
characterStats.damageMultiplier += 0.1;
weaponUpgradePurchased = true;
storage.weaponUpgradePurchased = true;
break;
case "cost":
characterStats.discountMultiplier *= 0.9;
costReductionPurchased = true;
storage.costReductionPurchased = true;
break;
case "health":
playerHealth = Math.min(120, playerHealth + 20);
healthText.setText('Health: ' + playerHealth);
break;
case "speed":
playerSpeed *= 1.2;
break;
case "reload":
// This will be applied in reload logic
break;
}
closeTrader();
// Remove trader NPC after purchase
if (traderNPC) {
traderNPC.destroy();
traderNPC = null;
}
traderActive = false;
LK.getSound('collect').play();
}
}
var placementCooldownText = new Text2('', {
size: 80,
fill: 0xFF0000
});
placementCooldownText.anchor.set(0.5, 0.5);
placementCooldownText.x = 0;
placementCooldownText.y = 0;
placementCooldownText.alpha = 0;
LK.gui.center.addChild(placementCooldownText);
// Spawn initial resources - minimal spawn to improve loading
var resourcesToSpawn = Math.min(2, 1 + Math.floor(currentDay / 3));
for (var i = 0; i < resourcesToSpawn; i++) {
var resource = new Resource();
resource.x = 200 + Math.random() * 1648;
resource.y = 200 + Math.random() * 1200;
resources.push(resource);
game.addChild(resource);
}
// Trader NPC will be spawned only every 5 days
var traderNPC = null;
function spawnMonster(type) {
var monster;
switch (type) {
case 'scout':
monster = new CorruptedScout();
break;
case 'tank':
monster = new CorruptedTank();
break;
case 'swarm':
monster = new CorruptedSwarm();
break;
default:
monster = new CorruptedScout();
}
// Spawn from edges
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
monster.x = Math.random() * 2048;
monster.y = -50;
break;
case 1:
// Right
monster.x = 2098;
monster.y = Math.random() * 2732;
break;
case 2:
// Bottom
monster.x = Math.random() * 2048;
monster.y = 2782;
break;
case 3:
// Left
monster.x = -50;
monster.y = Math.random() * 2732;
break;
}
monsters.push(monster);
game.addChild(monster);
}
function switchToNight() {
gameState = 'night';
currentNight++;
nightTimer = 1800 + (currentNight - 1) * 60; // Base 30s + 1s per night
gameStateText.setText('Night ' + currentNight);
timerText.setText(Math.ceil(nightTimer / 60) + 's');
nightText.setText('Night: ' + currentNight);
// Remove trader NPC during night
if (traderNPC) {
traderNPC.destroy();
traderNPC = null;
}
// Close any open trader UI
if (isTrading) {
closeTrader();
}
// Switch to night background
dayBackground.alpha = 0;
nightBackground.alpha = 1;
LK.playMusic('nightfall');
defenseText.setText('Night Phase - Survive!');
// Show heal button for medic character
if (characterStats.healPerNight > 0 && currentNight > 0) {
healButton.alpha = 1;
healButtonText.alpha = 1;
}
// Spawn initial monsters for the night - start with 6 and increase gradually
var initialMonsters = Math.min(6 + Math.floor(currentNight * 0.5), 8); // Start with 6, cap at 8
for (var i = 0; i < initialMonsters; i++) {
spawnMonster('scout'); // Start with scouts for the initial wave
}
// Spawn boss every 5th night
if (currentNight % 5 === 0 && boss === null) {
boss = new Boss();
// Spawn boss at center
boss.x = 1024;
boss.y = 1366;
game.addChild(boss);
// Show boss health bar
bossHealthBar.alpha = 1;
bossHealthBarFill.alpha = 1;
bossHealthText.alpha = 1;
// Epic boss cinematic - zoom camera to boss
playerCanMove = false; // Disable player movement during cinematic
// Store original game scale for restoration
var originalScaleX = game.scaleX || 1;
var originalScaleY = game.scaleY || 1;
var originalX = game.x || 0;
var originalY = game.y || 0;
// Calculate zoom position to center boss on screen
var targetX = -(boss.x - 1024) * 2; // 2x zoom
var targetY = -(boss.y - 1366) * 2; // 2x zoom
// Zoom in to boss with epic animation
tween(game, {
scaleX: 2.0,
scaleY: 2.0,
x: targetX,
y: targetY
}, {
duration: 1000,
easing: tween.easeInOut
});
// Add epic boss entrance animation
tween(boss, {
scaleX: 3.5,
scaleY: 3.5,
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.elasticOut
});
// Flash screen red for dramatic effect
LK.effects.flashScreen(0xFF0000, 1500);
// After 2 seconds, zoom back to normal
LK.setTimeout(function () {
// Restore camera to normal
tween(game, {
scaleX: originalScaleX,
scaleY: originalScaleY,
x: originalX,
y: originalY
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Re-enable player movement
playerCanMove = true;
}
});
// Reset boss scale to normal
tween(boss, {
scaleX: 2.5,
scaleY: 2.5,
rotation: 0
}, {
duration: 800,
easing: tween.easeOut
});
}, 2000);
}
}
function switchToDay() {
gameState = 'day';
currentDay++;
storage.currentDay = currentDay;
dayTimer = 1800; // 30 seconds per day
gameStateText.setText('Day ' + currentDay);
timerText.setText('30s');
// Switch to day background
dayBackground.alpha = 1;
nightBackground.alpha = 0;
LK.stopMusic();
// Reset to default mode
gameMode = 'build';
selectedDefense = 'wall';
defenseText.setText('Defense: Wall (Cost: 10)');
// Clear reload text bug fix
pistolReloadText.alpha = 0;
pistolReloadText.setText('');
wallButtonText.tint = 0x00FF00;
trapButtonText.tint = 0xFFFFFF;
collectButtonText.tint = 0xFFFFFF;
// Initialize wall button as selected
wallButton.tint = 0x00FF00;
trapButton.tint = 0xFFFFFF;
wallIcon.tint = 0x00FF00;
trapIcon.tint = 0xFFFFFF;
// Spawn very few resources to prevent performance issues
var resourcesToSpawn = Math.min(1, 1 + Math.floor(currentDay / 10));
// Only spawn if we have less than 2 resources total
if (resources.length < 2) {
for (var i = 0; i < resourcesToSpawn && resources.length < 2; i++) {
var resource = new Resource();
resource.x = 200 + Math.random() * 1648;
resource.y = 200 + Math.random() * 1200;
resources.push(resource);
game.addChild(resource);
}
}
// Remove any existing trader NPC
if (traderNPC) {
traderNPC.destroy();
traderNPC = null;
}
// Check if trader should appear (every 3 days)
if (currentDay % 3 === 0) {
traderActive = true;
traderNPC = new TraderNPC();
traderNPC.x = 300 + Math.random() * 1400;
traderNPC.y = 300 + Math.random() * 1000;
game.addChild(traderNPC);
} else {
traderActive = false;
}
// Check if random boss should appear (every 10 days)
if (currentDay % 10 === 0 && randomBoss === null) {
randomBoss = new RandomBoss();
randomBoss.x = 200 + Math.random() * 1648;
randomBoss.y = 200 + Math.random() * 1200;
game.addChild(randomBoss);
}
}
// Joystick movement handler
function updateJoystick(x, y) {
var dx = x - joystickCenterX;
var dy = y - joystickCenterY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > joystickRadius) {
dx = dx / distance * joystickRadius;
dy = dy / distance * joystickRadius;
}
joystickKnob.x = joystickCenterX + dx;
joystickKnob.y = joystickCenterY + dy;
// Calculate movement values (-1 to 1)
moveX = dx / joystickRadius;
moveY = dy / joystickRadius;
}
function resetJoystick() {
joystickKnob.x = joystickCenterX;
joystickKnob.y = joystickCenterY;
moveX = 0;
moveY = 0;
joystickActive = false;
}
// Action button handlers
wallButton.down = function (x, y, obj) {
if (gameState === 'day') {
selectedDefense = 'wall';
gameMode = 'build';
defenseText.setText('Defense: Wall (Cost: 10)');
wallButtonText.tint = 0x00FF00;
trapButtonText.tint = 0xFFFFFF;
collectButtonText.tint = 0xFFFFFF;
// Update button visual states
wallButton.tint = 0x00FF00;
trapButton.tint = 0xFFFFFF;
wallIcon.tint = 0x00FF00;
trapIcon.tint = 0xFFFFFF;
}
disablePlacement = true;
placementCooldown = 60;
placementCooldownText.alpha = 1;
placementCooldownText.setText('1');
};
trapButton.down = function (x, y, obj) {
if (gameState === 'day') {
selectedDefense = 'trap';
gameMode = 'build';
defenseText.setText('Defense: Trap (Cost: 15)');
wallButtonText.tint = 0xFFFFFF;
trapButtonText.tint = 0x00FF00;
collectButtonText.tint = 0xFFFFFF;
// Update button visual states
wallButton.tint = 0xFFFFFF;
trapButton.tint = 0x00FF00;
wallIcon.tint = 0xFFFFFF;
trapIcon.tint = 0x00FF00;
}
disablePlacement = true;
placementCooldown = 60;
placementCooldownText.alpha = 1;
placementCooldownText.setText('1');
};
collectButton.down = function (x, y, obj) {
if (gameState === 'day') {
gameMode = 'collect';
defenseText.setText('Mode: Resource Collection');
wallButtonText.tint = 0xFFFFFF;
trapButtonText.tint = 0xFFFFFF;
collectButtonText.tint = 0x00FF00;
// Reset button visual states
wallButton.tint = 0xFFFFFF;
trapButton.tint = 0xFFFFFF;
wallIcon.tint = 0xFFFFFF;
trapIcon.tint = 0xFFFFFF;
}
disablePlacement = true;
placementCooldown = 60;
placementCooldownText.alpha = 1;
placementCooldownText.setText('1');
};
// Joystick event handlers
game.down = function (x, y, obj) {
if (gameState === 'mainMenu') {
var local = LK.gui.center.toLocal({
x: x,
y: y
}, game);
// Check play button
if (local.x >= -200 && local.x <= 200 && local.y >= -150 && local.y <= -50) {
gameState = 'day';
_updateUIVisibility();
return;
}
// Check characters button
if (local.x >= -200 && local.x <= 200 && local.y >= 0 && local.y <= 100) {
gameState = 'characterSelect';
_updateUIVisibility();
return;
}
return;
}
if (gameState === 'characterSelect') {
var local = LK.gui.center.toLocal({
x: x,
y: y
}, game);
// Check character 1
if (local.x >= -400 && local.x <= -200 && local.y >= -200 && local.y <= 0) {
selectedCharacter = 0;
storage.selectedCharacter = 0;
characterStats.damageMultiplier = weaponUpgradePurchased ? 1.3 : 1.0;
characterStats.healPerNight = 0;
characterStats.discountMultiplier = costReductionPurchased ? 0.8 : 1.0;
// Update character appearance - no tints applied
gameState = 'day';
_updateUIVisibility();
return;
}
// Check character 2
if (local.x >= -100 && local.x <= 100 && local.y >= -200 && local.y <= 0) {
selectedCharacter = 1;
storage.selectedCharacter = 1;
characterStats.damageMultiplier = weaponUpgradePurchased ? 1.1 : 1.0;
characterStats.healPerNight = 10;
characterStats.discountMultiplier = costReductionPurchased ? 0.9 : 1.0;
// Update character appearance - no tints applied
// Update player graphics to use medic texture
player.destroy();
player = game.addChild(LK.getAsset('medicPlayer', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
gameState = 'day';
_updateUIVisibility();
return;
}
// Check character 3
if (local.x >= 200 && local.x <= 400 && local.y >= -200 && local.y <= 0) {
selectedCharacter = 2;
storage.selectedCharacter = 2;
characterStats.damageMultiplier = weaponUpgradePurchased ? 1.1 : 1.0;
characterStats.healPerNight = 0;
characterStats.discountMultiplier = costReductionPurchased ? 0.6 : 1.0;
// Update character appearance - no tints applied
// Update player graphics to use engineer texture
player.destroy();
player = game.addChild(LK.getAsset('engineerPlayer', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
}));
gameState = 'day';
_updateUIVisibility();
return;
}
// Check back button
if (local.x >= -150 && local.x <= 150 && local.y >= 250 && local.y <= 350) {
gameState = 'mainMenu';
_updateUIVisibility();
return;
}
return;
}
// Check if touch is on joystick base
var local = LK.gui.bottomLeft.toLocal({
x: x,
y: y
}, game);
var dx = local.x - joystickCenterX;
var dy = local.y - joystickCenterY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= joystickRadius + 30) {
joystickActive = true;
updateJoystick(local.x, local.y);
return;
}
// Check heal button
if (healButton.alpha > 0) {
var local = LK.gui.center.toLocal({
x: x,
y: y
}, game);
if (local.x >= -370 && local.x <= -130 && local.y >= -120 && local.y <= 120) {
playerHealth = Math.min(100, playerHealth + characterStats.healPerNight);
healthText.setText('Health: ' + playerHealth);
healButton.alpha = 0;
healButtonText.alpha = 0;
LK.getSound('collect').play();
return;
}
}
// Check trader NPC interaction when not already trading
if (!isTrading && traderNPC && gameState === 'day' && traderActive) {
var dx = player.x - traderNPC.x;
var dy = player.y - traderNPC.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120 && gameMode === 'collect') {
// Player is near trader and in collect mode (C pressed)
isTrading = true;
playerCanMove = false;
createTraderUI();
return;
}
}
// Check trader interactions
if (traderActive && traderContainer) {
var local = LK.gui.center.toLocal({
x: x,
y: y
}, game);
// Check upgrade buttons
for (var i = 0; i < traderContainer.children.length; i++) {
var child = traderContainer.children[i];
if (child.upgradeData) {
var childBounds = child.getBounds();
if (local.x >= childBounds.x && local.x <= childBounds.x + childBounds.width && local.y >= childBounds.y && local.y <= childBounds.y + childBounds.height) {
purchaseUpgrade(child.upgradeData);
// Remove trader NPC after purchase
if (traderNPC) {
traderNPC.destroy();
traderNPC = null;
}
traderActive = false;
return;
}
}
}
// Check close button
if (local.x >= -180 && local.x <= 180 && local.y >= 90 && local.y <= 210) {
closeTrader();
return;
}
}
// Check if player tapped directly on a resource (works in any mode)
for (var i = resources.length - 1; i >= 0; i--) {
var resource = resources[i];
var dx = x - resource.x;
var dy = y - resource.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Direct tap on resource - increased hitbox
playerResources += resource.value;
resourceText.setText('Resources: ' + playerResources);
resource.destroy();
resources.splice(i, 1);
LK.getSound('collect').play();
return; // Exit early after collecting
}
}
if (disablePlacement) {
return; // Prevent placing objects while a button is pressed
}
if (gameState === 'day') {
if (gameMode === 'build') {
var baseCost = selectedDefense === 'wall' ? 10 : 15;
var cost = Math.floor(baseCost * characterStats.discountMultiplier);
if (playerResources >= cost) {
var defense;
if (selectedDefense === 'wall') {
defense = new Wall();
} else {
defense = new Trap();
}
defense.x = x;
defense.y = y;
if (selectedDefense === 'wall') {
walls.push(defense);
} else {
traps.push(defense);
}
game.addChild(defense);
playerResources -= cost;
resourceText.setText('Resources: ' + playerResources);
LK.getSound('build').play();
}
} else if (gameMode === 'collect') {
// Enhanced resource collection in collect mode - collect all resources in range
var resourcesCollected = 0;
for (var i = resources.length - 1; i >= 0; i--) {
var resource = resources[i];
var dx = x - resource.x;
var dy = y - resource.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
// Collect resources in range
playerResources += resource.value;
resourceText.setText('Resources: ' + playerResources);
resource.destroy();
resources.splice(i, 1);
resourcesCollected++;
// Don't break - collect all resources in range
}
}
if (resourcesCollected > 0) {
LK.getSound('collect').play();
}
}
} else if (gameState === 'night' && hasDualPistol && dualPistolWeapon && dualPistolWeapon.canShoot()) {
// Shoot dual pistol (2 bullets)
if (dualPistolWeapon.shoot()) {
var dx = x - player.x;
var dy = y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Shoot two bullets with slight angle difference
for (var b = 0; b < 2; b++) {
var projectile = new Bullet();
projectile.x = player.x;
projectile.y = player.y;
// Add slight angle variation for dual shots
var angle = Math.atan2(dy, dx) + (b === 0 ? -0.1 : 0.1);
projectile.direction.x = Math.cos(angle);
projectile.direction.y = Math.sin(angle);
bullets.push(projectile);
game.addChild(projectile);
}
// Create dual pistol graphics
if (pistolGraphics) {
pistolGraphics.destroy();
}
pistolGraphics = game.addChild(LK.getAsset('pistolTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
}));
// Remove pistol tint for performance
pistolGraphics.x = player.x + dx / distance * 40;
pistolGraphics.y = player.y + dy / distance * 40;
pistolGraphics.rotation = Math.atan2(dy, dx);
pistolTimer = 20;
// Animate pistol with tween
tween(pistolGraphics, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeOut
});
LK.getSound('shoot').play();
// Update reload text
if (dualPistolWeapon.isReloading) {
pistolReloadText.alpha = 1;
pistolReloadText.setText('Dual Pistol Reloading...');
}
}
} else if (gameState === 'night' && playerPistol && !pistolReloading && pistolBullets > 0) {
// Shoot bullet or bomb towards click position
var projectile;
if (selectedCharacter === 1) {
// Medic shoots bombs
projectile = new Bomb();
} else {
// Others shoot bullets
projectile = new Bullet();
}
projectile.x = player.x;
projectile.y = player.y;
// Calculate direction to target
var dx = x - player.x;
var dy = y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
projectile.direction.x = dx / distance;
projectile.direction.y = dy / distance;
if (selectedCharacter === 1) {
bombs.push(projectile);
} else {
bullets.push(projectile);
}
game.addChild(projectile);
// Create pistol graphics
if (pistolGraphics) {
pistolGraphics.destroy();
}
pistolGraphics = game.addChild(LK.getAsset('pistolTexture', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
// Remove pistol tint for performance
pistolGraphics.x = player.x + dx / distance * 40;
pistolGraphics.y = player.y + dy / distance * 40;
pistolGraphics.rotation = Math.atan2(dy, dx);
pistolTimer = 20; // Show pistol for 20 frames
// Animate pistol with tween
tween(pistolGraphics, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 100,
easing: tween.easeOut
});
tween(pistolGraphics, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeIn
});
LK.getSound('shoot').play();
pistolBullets--;
if (pistolBullets === 0) {
pistolReloading = true;
pistolReloadTimer = 180; // 3 seconds at 60fps
pistolReloadText.alpha = 1;
pistolReloadText.setText('Reloading...');
}
}
// Check for dual pistol pickup
if (dualPistolPickup && !hasDualPistol) {
var dx = x - dualPistolPickup.x;
var dy = y - dualPistolPickup.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
hasDualPistol = true;
dualPistolWeapon = new DualPistol();
dualPistolPickup.destroy();
dualPistolPickup = null;
// Clean up pickup message
if (weaponPickupText) {
weaponPickupText.destroy();
weaponPickupText = null;
}
LK.getSound('collect').play();
}
}
};
game.move = function (x, y, obj) {
if (joystickActive) {
var local = LK.gui.bottomLeft.toLocal({
x: x,
y: y
}, game);
updateJoystick(local.x, local.y);
}
};
game.up = function (x, y, obj) {
if (joystickActive) {
resetJoystick();
}
};
game.update = function () {
// Skip game logic if in menu states
if (gameState === 'mainMenu' || gameState === 'characterSelect') {
return;
}
// Handle joystick movement (only if player can move)
if (playerCanMove && Math.abs(moveX) > 0.1 || Math.abs(moveY) > 0.1) {
player.x = Math.max(50, Math.min(1998, player.x + moveX * playerSpeed));
player.y = Math.max(50, Math.min(2682, player.y + moveY * playerSpeed));
// Epic running animation using tween
if (LK.ticks % 30 === 0) {
// Create bouncing effect
tween(player, {
scaleY: 1.15,
y: player.y - 5
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleY: 1.0,
y: player.y + 5
}, {
duration: 150,
easing: tween.easeIn
});
}
});
// Add slight rotation for dynamic movement
var rotationAmount = moveX * 0.1;
tween(player, {
rotation: rotationAmount
}, {
duration: 200,
easing: tween.easeInOut
});
}
}
// Handle berserker mode visual effects
if (berserkMode) {
// Pulsing red effect for berserker mode
if (LK.ticks % 20 === 0) {
tween(player, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
} else if (playerCanMove) {
// Epic idle animation when not moving
if (LK.ticks % 120 === 0) {
// Breathing effect
tween(player, {
scaleX: 1.05,
scaleY: 0.98
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
// Reset rotation when idle
if (Math.abs(player.rotation) > 0.01) {
tween(player, {
rotation: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Handle pistol reload timer
if (pistolReloading) {
pistolReloadTimer--;
pistolReloadText.alpha = 1;
pistolReloadText.setText('Reload: ' + Math.ceil(pistolReloadTimer / 60) + 's');
// Apply reload speed upgrade
var reloadTime = 180;
for (var i = 0; i < traderUpgrades.length; i++) {
if (traderUpgrades[i].type === "reload" && traderUpgrades[i].purchased) {
reloadTime = 126; // 30% faster reload
break;
}
}
if (pistolReloadTimer <= 0) {
pistolReloading = false;
pistolBullets = 5;
pistolReloadText.alpha = 0;
}
}
// Handle dual pistol reload
if (hasDualPistol && dualPistolWeapon && dualPistolWeapon.isReloading) {
pistolReloadText.alpha = 1;
pistolReloadText.setText('Dual Pistol: ' + Math.ceil(dualPistolWeapon.reloadTimer / 60) + 's');
if (!dualPistolWeapon.isReloading) {
pistolReloadText.alpha = 0;
}
}
// Handle pistol graphics timer
if (pistolTimer > 0) {
pistolTimer--;
if (pistolTimer <= 0 && pistolGraphics) {
pistolGraphics.destroy();
pistolGraphics = null;
}
}
// Placement cooldown logic
if (placementCooldown > 0) {
placementCooldown--;
if (placementCooldown > 0) {
placementCooldownText.alpha = 1;
placementCooldownText.setText('' + Math.ceil(placementCooldown / 60));
disablePlacement = true;
} else {
placementCooldownText.alpha = 0;
disablePlacement = false;
}
}
if (gameState === 'day') {
dayTimer--;
timerText.setText(Math.ceil(dayTimer / 60) + 's');
if (dayTimer <= 0) {
switchToNight();
}
// Show trader interaction hint when player is near and in collect mode
if (traderNPC && traderActive && gameMode === 'collect') {
var dx = player.x - traderNPC.x;
var dy = player.y - traderNPC.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
// Make trader glow when nearby in collect mode
traderNPC.alpha = 0.7 + 0.3 * Math.sin(LK.ticks * 0.1);
traderNPC.scaleX = 1.0 + 0.1 * Math.sin(LK.ticks * 0.15);
traderNPC.scaleY = 1.0 + 0.1 * Math.sin(LK.ticks * 0.15);
defenseText.setText('Press C near trader to trade!');
} else {
// Reset trader appearance when not nearby
traderNPC.alpha = 1.0;
traderNPC.scaleX = 1.0;
traderNPC.scaleY = 1.0;
if (gameMode === 'collect') {
defenseText.setText('Mode: Resource Collection');
}
}
}
// Resource collection is now handled only in collect mode or manual interaction
// No automatic pickup when player touches resources
// Simplified resource collection - no visual effects for performance
if (gameMode === 'collect' && LK.ticks % 20 === 0) {
for (var i = resources.length - 1; i >= 0; i--) {
var resource = resources[i];
var dx = player.x - resource.x;
var dy = player.y - resource.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Auto collect when player is very close in collect mode
playerResources += resource.value;
resourceText.setText('Resources: ' + playerResources);
resource.destroy();
resources.splice(i, 1);
LK.getSound('collect').play();
}
}
}
} else if (gameState === 'night') {
nightTimer--;
timerText.setText(Math.ceil(nightTimer / 60) + 's');
// Don't spawn monsters when boss is present (unless boss has special spawn ability)
if (boss === null) {
// Spawn monsters with much slower rate for better performance
var spawnRate = 3600; // Every 60 seconds
var maxMonsters = 2; // Limit total monsters
if (LK.ticks % spawnRate === 0 && monsters.length < maxMonsters) {
var monsterTypes = ['scout']; // Only spawn scouts for better performance
var type = monsterTypes[Math.floor(Math.random() * monsterTypes.length)];
spawnMonster(type);
}
// Spawn CorruptedTank - reduced frequency
var tankSpawnRate = 7200; // Every 120 seconds
var tanksToSpawn = Math.min(currentNight, 1); // Max 1 tank
var tanksSpawned = 0;
// Count existing tanks
for (var t = 0; t < monsters.length; t++) {
if (monsters[t].type === 'tank') {
tanksSpawned++;
}
}
// Spawn tanks if we need more
if (LK.ticks % tankSpawnRate === 0 && tanksSpawned < tanksToSpawn) {
spawnMonster('tank');
}
}
// Handle slow enemies timer
if (slowEnemiesTimer > 0) {
slowEnemiesTimer--;
if (slowEnemiesTimer <= 0) {
slowEnemiesActive = false;
}
}
// Monster AI and collision - process much less frequently for better performance
var shouldProcessMonsters = LK.ticks % 120 === 0; // Process every 120th frame
var processedMonsters = 0;
var maxMonstersPerFrame = 1; // Limit monsters processed per frame
for (var i = monsters.length - 1; i >= 0; i--) {
var monster = monsters[i];
// Skip if monster doesn't exist
if (!monster) {
monsters.splice(i, 1);
continue;
}
// Skip dead monsters for collision and movement
if (monster.isDead) {
continue;
}
// Skip processing for most monsters to reduce lag
if (i % 5 !== 0) {
continue;
}
// Limit processing to prevent lag
if (processedMonsters >= maxMonstersPerFrame) {
break;
}
processedMonsters++;
// Apply slow effect if active
var originalSpeed = monster.speed;
if (slowEnemiesActive) {
monster.speed = originalSpeed * 0.3; // 70% slower
}
// Skip AI processing for some frames to reduce lag - process only 1 in 5 monsters per frame
if (!shouldProcessMonsters && i % 5 !== 0) {
continue;
}
// Check collision with player
var dx = player.x - monster.x;
var dy = player.y - monster.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 90) {
// Increase monster damage by 0.5% per night
var damageMultiplier = 1 + currentNight * 0.005;
var actualDamage = Math.floor(monster.damage * damageMultiplier);
playerHealth -= actualDamage;
healthText.setText('Health: ' + playerHealth);
monster.destroy();
monsters.splice(i, 1);
LK.getSound('damage').play();
// Check for special abilities when health drops to 30% (30 health out of 100)
if (playerHealth <= 30) {
if (selectedCharacter === 0 && !berserkUsed) {
// Warrior berserk mode
berserkMode = true;
berserkUsed = true;
playerSpeed = 8; // Increased speed
characterStats.damageMultiplier = 2.0; // Double damage
slowEnemiesActive = true;
slowEnemiesTimer = 600; // 10 seconds
// Add red tint to player for berserker mode
player.tint = 0xFF0000;
LK.effects.flashScreen(0xFF0000, 1000); // Red flash
} else if (selectedCharacter === 1 && !medicReviveUsed) {
// Medic auto-heal
playerHealth = 50;
medicReviveUsed = true;
healthText.setText('Health: ' + playerHealth);
LK.effects.flashScreen(0x00FF00, 1000); // Green flash
} else if (selectedCharacter === 2 && !engineerBoostUsed) {
// Engineer boost
engineerBoostActive = true;
engineerBoostUsed = true;
playerSpeed = 7; // Increased speed
LK.effects.flashScreen(0x0000FF, 1000); // Blue flash
}
}
if (playerHealth <= 0) {
LK.showGameOver();
}
continue;
}
// Check collision with walls
var hitWall = false;
for (var j = 0; j < walls.length; j++) {
var wall = walls[j];
if (wall.health > 0 && !monster.isDead && monster.intersects(wall)) {
// Monster only attacks wall every 2 seconds (120 ticks)
// Only if player is within 300px or monster is within 300px of wall (simulate "seeing" wall)
var playerDist = Math.sqrt((player.x - monster.x) * (player.x - monster.x) + (player.y - monster.y) * (player.y - monster.y));
var wallDist = Math.sqrt((wall.x - monster.x) * (wall.x - monster.x) + (wall.y - monster.y) * (wall.y - monster.y));
if (playerDist < 300 || wallDist < 300) {
if (LK.ticks - wall.lastMonsterHitTick >= 120) {
wall.registerMonsterHit();
wall.takeDamage(monster.damage);
LK.effects.flashObject(wall, 0xff0000, 200);
// If wall is destroyed after 3 hits, set health to 0 and alpha to 0.3
if (wall.hitCount >= 3 || wall.health <= 0) {
wall.health = 0;
wall.alpha = 0.3;
}
}
}
// Monster stays and keeps attacking, do not destroy monster
hitWall = true;
break;
}
}
if (hitWall) continue;
// Check collision with traps
for (var k = 0; k < traps.length; k++) {
var trap = traps[k];
if (!monster.isDead && monster.intersects(trap)) {
var trapDamage = trap.activate();
if (trapDamage > 0) {
var isDead = monster.takeDamage(trapDamage);
if (isDead) {
// Simple death effect for performance
monster.alpha = 0.3;
monster.scaleX = 1.5;
monster.scaleY = 1.5;
LK.setScore(LK.getScore() + 10);
break;
}
}
}
}
}
// Handle boss combat
if (boss !== null) {
// Update boss health bar
var healthPercent = boss.health / boss.maxHealth;
bossHealthBarFill.scaleX = 10 * healthPercent;
bossHealthText.setText('BOSS: ' + boss.health + '/' + boss.maxHealth);
}
// Handle random boss combat
if (randomBoss !== null) {
// Check collision with player
var dx = player.x - randomBoss.x;
var dy = player.y - randomBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Increase random boss damage by 0.5% per night
var damageMultiplier = 1 + currentNight * 0.005;
var actualDamage = Math.floor(randomBoss.damage * damageMultiplier);
playerHealth -= actualDamage;
healthText.setText('Health: ' + playerHealth);
LK.getSound('damage').play();
// Check for special abilities when health drops to 30% (30 health out of 100)
if (playerHealth <= 30) {
if (selectedCharacter === 0 && !berserkUsed) {
// Warrior berserk mode
berserkMode = true;
berserkUsed = true;
playerSpeed = 8; // Increased speed
characterStats.damageMultiplier = 2.0; // Double damage
slowEnemiesActive = true;
slowEnemiesTimer = 600; // 10 seconds
// Add red tint to player for berserker mode
player.tint = 0xFF0000;
LK.effects.flashScreen(0xFF0000, 1000); // Red flash
} else if (selectedCharacter === 1 && !medicReviveUsed) {
// Medic auto-heal
playerHealth = 50;
medicReviveUsed = true;
healthText.setText('Health: ' + playerHealth);
LK.effects.flashScreen(0x00FF00, 1000); // Green flash
} else if (selectedCharacter === 2 && !engineerBoostUsed) {
// Engineer boost
engineerBoostActive = true;
engineerBoostUsed = true;
playerSpeed = 7; // Increased speed
LK.effects.flashScreen(0x0000FF, 1000); // Blue flash
}
}
if (playerHealth <= 0) {
LK.showGameOver();
}
}
}
// Handle bomb collisions and explosions
var processedBombs = 0;
var maxBombsPerFrame = 1; // Limit bombs processed per frame
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
// Skip if bomb doesn't exist
if (!bomb) {
bombs.splice(i, 1);
continue;
}
// Skip processing for most bombs to reduce lag
if (i % 2 !== 0) {
continue;
}
// Limit processing to prevent lag
if (processedBombs >= maxBombsPerFrame) {
break;
}
processedBombs++;
var bombHit = false;
// Check collision with monsters
for (var j = monsters.length - 1; j >= 0; j--) {
var monster = monsters[j];
var dx = bomb.x - monster.x;
var dy = bomb.y - monster.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Create explosion effect
LK.effects.flashObject(bomb, 0xFF6600, 500);
// Stun and damage all monsters within explosion radius
for (var k = monsters.length - 1; k >= 0; k--) {
var targetMonster = monsters[k];
var expDx = bomb.x - targetMonster.x;
var expDy = bomb.y - targetMonster.y;
var expDistance = Math.sqrt(expDx * expDx + expDy * expDy);
if (expDistance < bomb.explosionRadius) {
var isDead = targetMonster.takeDamage(2);
// Stun effect - reduce speed temporarily
targetMonster.speed = targetMonster.speed * 0.1;
if (isDead) {
// Add kill animation
tween(targetMonster, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
LK.setScore(LK.getScore() + 10);
}
}
}
bomb.destroy();
bombs.splice(i, 1);
bombHit = true;
break;
}
}
// Check collision with boss
if (!bombHit && boss !== null) {
var dx = bomb.x - boss.x;
var dy = bomb.y - boss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Explosion damage to boss
var isBossDead = boss.takeDamage(3);
if (isBossDead) {
LK.setScore(LK.getScore() + 100);
// Drop dual pistol weapon
if (!hasDualPistol && !dualPistolPickup) {
dualPistolPickup = new DualPistol();
dualPistolPickup.x = boss.x;
dualPistolPickup.y = boss.y;
game.addChild(dualPistolPickup);
// Simple visual effect for performance
dualPistolPickup.scaleX = 1.2;
dualPistolPickup.scaleY = 1.2;
// Add pickup message
weaponPickupText = new Text2('Hacer click para agarrar', {
size: 60,
fill: 0xFFFF00
});
weaponPickupText.anchor.set(0.5, 0.5);
weaponPickupText.x = boss.x;
weaponPickupText.y = boss.y - 100;
game.addChild(weaponPickupText);
}
boss.destroy();
boss = null;
// Hide boss health bar
bossHealthBar.alpha = 0;
bossHealthBarFill.alpha = 0;
bossHealthText.alpha = 0;
LK.effects.flashScreen(0x00ff00, 500);
}
bomb.destroy();
bombs.splice(i, 1);
}
}
// Check collision with random boss
if (!bombHit && randomBoss !== null) {
var dx = bomb.x - randomBoss.x;
var dy = bomb.y - randomBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
var isBossDead = randomBoss.takeDamage(4);
if (isBossDead) {
LK.setScore(LK.getScore() + 150);
playerResources += 50;
resourceText.setText('Resources: ' + playerResources);
randomBoss.destroy();
randomBoss = null;
LK.effects.flashScreen(0xFFD700, 500);
}
bomb.destroy();
bombs.splice(i, 1);
}
}
}
// Handle bullet collisions - process much less frequently for better performance
if (LK.ticks % 60 === 0) {
var processedBullets = 0;
var maxBulletsPerFrame = 1; // Limit bullets processed per frame
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Skip if bullet doesn't exist
if (!bullet) {
bullets.splice(i, 1);
continue;
}
// Skip processing for most bullets to reduce lag
if (i % 3 !== 0) {
continue;
}
// Limit processing to prevent lag
if (processedBullets >= maxBulletsPerFrame) {
break;
}
processedBullets++;
var bulletHit = false;
// Modify bullet size for engineer
if (engineerBoostActive && selectedCharacter === 2) {
bullet.scaleX = 2.0;
bullet.scaleY = 2.0;
}
// Check collision with monsters
for (var j = monsters.length - 1; j >= 0; j--) {
var monster = monsters[j];
// Skip dead monsters
if (monster.isDead) continue;
var dx = bullet.x - monster.x;
var dy = bullet.y - monster.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var hitRadius = engineerBoostActive && selectedCharacter === 2 ? 70 : 50;
if (distance < hitRadius + 20) {
var isDead = monster.takeDamage(bullet.damage);
if (isDead) {
// Add kill animation
tween(monster, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
LK.setScore(LK.getScore() + 10);
}
bullet.destroy();
bullets.splice(i, 1);
bulletHit = true;
break;
}
}
// Check collision with boss
if (!bulletHit && boss !== null) {
var dx = bullet.x - boss.x;
var dy = bullet.y - boss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
var isBossDead = boss.takeDamage(bullet.damage);
if (isBossDead) {
LK.setScore(LK.getScore() + 100);
// Drop dual pistol weapon
if (!hasDualPistol && !dualPistolPickup) {
dualPistolPickup = new DualPistol();
dualPistolPickup.x = boss.x;
dualPistolPickup.y = boss.y;
game.addChild(dualPistolPickup);
// Add floating animation to make it more visible
tween(dualPistolPickup, {
y: dualPistolPickup.y - 20,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
// Add pickup message
weaponPickupText = new Text2('Hacer click para agarrar', {
size: 60,
fill: 0xFFFF00
});
weaponPickupText.anchor.set(0.5, 0.5);
weaponPickupText.x = boss.x;
weaponPickupText.y = boss.y - 100;
game.addChild(weaponPickupText);
}
boss.destroy();
boss = null;
// Hide boss health bar
bossHealthBar.alpha = 0;
bossHealthBarFill.alpha = 0;
bossHealthText.alpha = 0;
LK.effects.flashScreen(0x00ff00, 500); // Green flash for boss kill
}
bullet.destroy();
bullets.splice(i, 1);
}
}
// Check collision with random boss
if (!bulletHit && randomBoss !== null) {
var dx = bullet.x - randomBoss.x;
var dy = bullet.y - randomBoss.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
var isBossDead = randomBoss.takeDamage(bullet.damage);
if (isBossDead) {
LK.setScore(LK.getScore() + 150);
playerResources += 50; // Extra resources for random boss
resourceText.setText('Resources: ' + playerResources);
randomBoss.destroy();
randomBoss = null;
LK.effects.flashScreen(0xFFD700, 500); // Gold flash for random boss kill
}
bullet.destroy();
bullets.splice(i, 1);
}
}
}
}
if (nightTimer <= 0 && boss === null) {
// Clear remaining monsters
for (var m = monsters.length - 1; m >= 0; m--) {
monsters[m].destroy();
monsters.splice(m, 1);
}
// Clear remaining bullets
for (var b = bullets.length - 1; b >= 0; b--) {
bullets[b].destroy();
bullets.splice(b, 1);
}
// Clear remaining bombs
for (var bomb = bombs.length - 1; bomb >= 0; bomb--) {
bombs[bomb].destroy();
bombs.splice(bomb, 1);
}
switchToDay();
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1405,8 +1405,65 @@
// Show boss health bar
bossHealthBar.alpha = 1;
bossHealthBarFill.alpha = 1;
bossHealthText.alpha = 1;
+ // Epic boss cinematic - zoom camera to boss
+ playerCanMove = false; // Disable player movement during cinematic
+ // Store original game scale for restoration
+ var originalScaleX = game.scaleX || 1;
+ var originalScaleY = game.scaleY || 1;
+ var originalX = game.x || 0;
+ var originalY = game.y || 0;
+ // Calculate zoom position to center boss on screen
+ var targetX = -(boss.x - 1024) * 2; // 2x zoom
+ var targetY = -(boss.y - 1366) * 2; // 2x zoom
+ // Zoom in to boss with epic animation
+ tween(game, {
+ scaleX: 2.0,
+ scaleY: 2.0,
+ x: targetX,
+ y: targetY
+ }, {
+ duration: 1000,
+ easing: tween.easeInOut
+ });
+ // Add epic boss entrance animation
+ tween(boss, {
+ scaleX: 3.5,
+ scaleY: 3.5,
+ rotation: Math.PI * 2
+ }, {
+ duration: 1000,
+ easing: tween.elasticOut
+ });
+ // Flash screen red for dramatic effect
+ LK.effects.flashScreen(0xFF0000, 1500);
+ // After 2 seconds, zoom back to normal
+ LK.setTimeout(function () {
+ // Restore camera to normal
+ tween(game, {
+ scaleX: originalScaleX,
+ scaleY: originalScaleY,
+ x: originalX,
+ y: originalY
+ }, {
+ duration: 800,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // Re-enable player movement
+ playerCanMove = true;
+ }
+ });
+ // Reset boss scale to normal
+ tween(boss, {
+ scaleX: 2.5,
+ scaleY: 2.5,
+ rotation: 0
+ }, {
+ duration: 800,
+ easing: tween.easeOut
+ });
+ }, 2000);
}
}
function switchToDay() {
gameState = 'day';
Crea picos de madera, que todos estén unidos en una tablilla por abajo y que arriba estén los picos. In-Game asset. 2d. High contrast. No shadows
Crea un botón de color azul pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de lava pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un guerrero pixel, sin armas, y que tenga la cabeza un poco más grande que el cuerpo tipo pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un monstruo corrupto morado de piedra qué no sea tan terrorífico, y que sea pixel.Y qué tenga manos grandes, y torso y que la cabeza no sea tan terrorífico, y no le ponga ojos perturbadores, y que su cabeza sea de un tamaño moderado no muy grande, que algo que si sea grande sea sus brazos, y que tenga algas moradas y que tenga algunas piedras moradas y otras piedras que no sean moradas qué sean grises In-Game asset. 2d. High contrast. No shadows.
Genera una imagen verde solo verde oscuro. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de una avispa no terroríficas, pixel y que sean moradas. Que sea corrupta In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un corrupto pixel, y que no sea terrorífico y que sea morado. In-Game asset. 2d. High contrast. No shadows
Genera una imagen morado oscuro solo morado oscuro In-Game asset. 2d. High contrast. No shadows
Genera una imagen de una roca morada sonriente. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un círculo verde pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un destello brillante morado pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de una pistola pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de una bala pixel. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un médico guerrero pixel, y que su cabeza sea un poco más grande que el cuerpo. Y que no tenga armas In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un albañil guerrero pixel, que su cabeza sea un poco más grande que su cuerpo, y que no tenga armas. In-Game asset. 2d. High contrast. No shadows
Genera una imagen de un comerciante pixel y que su cabeza sea un poco más grande que su cuerpo. In-Game asset. 2d. High contrast. No shadows
Crea una imagen de un texto que diga "The corrupt survival" qué sea pixel y en la palabra "i" ponle una espada pixel. In-Game asset. 2d. High contrast. No shadows