User prompt
Quiero que agregues otro jefe secreto que ese se invoque poniendo 3 lanceros y 1 arquero
User prompt
Quiero que al principio de la aparición del secret Boos un personaje haga una animación rápida que se mueva en zic Zac hasta el jefe haciendole una ataqué en estocada ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Sigue sin funcionar así que te pido que deshagas esa funcion
User prompt
El botón de tienda y de empezar sigue sin tener acción para solucionarlo puedes cambiarlos totalmente contal de que cumplan su función
User prompt
Ahora quiero que el botón de empezar si pueda empezar la lógica del juego pero solo ese botón
User prompt
Ok aver así quiero que no se active el juego ni la cinemática de intro a menos que se toque el boton de empezá o el de ir a la tienda en su defecto
User prompt
El juego sigue empezando aún tocando cualquier lugar
User prompt
Quiero que arregles la caja de colisión de el botón de empezar para así no acaparar toda la pantalla que la vuelvas un botón definido
User prompt
El botón de tienda no funciona muy bien puedes agreglarlo también quiero que agregues nueva función de volver a menu en el botón de pausa ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Quiero que mejores este sistema y prevé posibles errores ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Poquiero que cres un sistema tipo tienda antes de empezar el juego para cambiar el daño y poder de las armas de cada Classe ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Quiero que hagas un mega rework a todo y te encargués de agregar otra mecánica nueva ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Arregla errores y habré un a párrafo para un jefe que ocupe animaciones ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ahora quiero hacer algo muy ambicioso quiero que le hagas una entrada triunfal al jefe ogro ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok quiero que saques las bombas nucleares de prueba por ahora
User prompt
Muy bien parce que no entendíste quiero que hagas que el cubo verde de defensa contra ataques sea 100% invincible y que el activo sea más grande ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
No no oculta los gráficos del cubo de defensa contra ataques nucleares
User prompt
Ok quiero que no se vea el cubo verde solo el activo y que el activo sea igual de grande que la otra vez ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok no quiero que el tamaño del activo vuelvan a ser igual de grande pero que el cubo tenga el mismo tamaño y no sobre pase el activó ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Quiero que achiques el cubo de defensa contra ataques nucleares para que coincida con el tamaño del acti ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
No, que le agregues a los cubos de defensa contra ataque s núcleares el activó "peligro", deja BigPoder como estaba
User prompt
Quiero que cambies la imagen de cuadrado del quick Time event por la del activó "peligro"
User prompt
Quiero que desactives la invitación de tropas cuándo esté en mecánica de Quick Time Event a esepcion del escudo
User prompt
Quiero que lo agregues al principio de la partida de modo de prueba
User prompt
Please fix the bug: 'ReferenceError: nuclearDefenseCubes is not defined' in or related to this line: 'for (var reset_i = 0; reset_i < nuclearDefenseCubes.length; reset_i++) {' Line Number: 2002
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
unitUpgrades: {
archer: {
damage: 0,
power: 0
},
spearman: {
damage: 0,
power: 0
},
cavalry: {
damage: 0,
power: 0
}
},
shopCoins: 50
});
/****
* Classes
****/
var Avion = Container.expand(function () {
var self = Container.call(this);
var avionGraphics = self.attachAsset('avion', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Flight properties
self.speed = 3;
self.altitude = Math.random() * 200 + 100; // Random altitude
self.direction = Math.random() < 0.5 ? 1 : -1; // Random direction
self.bobAmount = 0;
self.bobSpeed = 0.05;
// Set initial position based on direction
if (self.direction > 0) {
self.x = -250; // Start from left
} else {
self.x = 2298; // Start from right
}
self.y = Math.random() * 800 + 200;
// Flip airplane if moving right to left
if (self.direction < 0) {
avionGraphics.scaleX = -1.5;
}
self.update = function () {
// Move directly toward fortress instead of horizontally
if (fortress) {
var dx = fortress.x - self.x;
var dy = fortress.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 250) {
// Move toward fortress
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Add bobbing motion for realistic flight
self.bobAmount += self.bobSpeed;
self.y += Math.sin(self.bobAmount) * 2;
// Slight rotation for banking effect
avionGraphics.rotation = Math.sin(self.bobAmount) * 0.1;
// Check collision with fortress
if (fortress) {
var fortressDist = Math.sqrt(Math.pow(fortress.x - self.x, 2) + Math.pow(fortress.y - self.y, 2));
if (fortressDist < 250) {
// Direct collision without cinematic
var explosion = new Explosion(self.x, self.y);
game.addChild(explosion);
// Play explosion sound
LK.getSound('explosion').play();
// Airplane crashed into fortress - hide all non-alternate enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
// Hide enemies that are not airplanes (check if enemy doesn't have airplane properties)
if (enemy.direction === undefined && enemy.speed === undefined) {
enemy.visible = false;
}
}
// Stop enemy spawning by setting current scenario permanently
currentScenario = 'alternate';
// Airplane crashed into fortress - game over
LK.effects.flashObject(fortress, 0xFF0000, 1000);
LK.effects.flashScreen(0xFF0000, 1000);
gameOver = true;
self.markForDestroy = true;
// Show game over immediately
LK.showGameOver();
return;
}
}
// Remove when off screen
if (self.x < -300 || self.x > 2348) {
self.markForDestroy = true;
}
};
return self;
});
var BigPoderProjectile = Container.expand(function (startX, startY, target, damage) {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('BigPoder', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = startX;
self.y = startY;
self.target = target;
self.damage = damage;
self.speed = 6; // Slower than regular Poder
// Calculate direction to target
var dx = target.x - startX;
var dy = target.y - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
// Set rotation to face target
projectileGraphics.rotation = Math.atan2(dy, dx);
// Start with growing animation
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut
});
// Add pulsing effect
var spinSpeed = 0.08;
self.pulseDirection = 1;
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
// Spin and pulse the projectile
projectileGraphics.rotation += spinSpeed;
// Pulsing scale effect
if (self.scaleX >= 1.8) {
self.pulseDirection = -1;
} else if (self.scaleX <= 1.2) {
self.pulseDirection = 1;
}
self.scaleX += self.pulseDirection * 0.02;
self.scaleY += self.pulseDirection * 0.02;
// Check if hit fortress (secret boss attacks fortress directly)
if (fortress && fortress.takeDamage) {
var fortressDist = Math.sqrt(Math.pow(fortress.x - self.x, 2) + Math.pow(fortress.y - self.y, 2));
if (fortressDist < 250) {
// Ensure damage is exactly 2 points for reduced boss attack power
fortress.takeDamage(2);
// Big explosion effect
LK.effects.flashObject(fortress, 0x00FFFF, 800);
// Shrinking effect on hit
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.markForDestroy = true;
}
});
return;
}
}
// Remove if off screen
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.markForDestroy = true;
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('Bossogro', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 2.0,
// Make boss twice as big
scaleY: 2.0
});
// Add boss details
var eyesAsset = self.attachAsset('spear', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
eyesAsset.x = 0;
eyesAsset.y = -240; // Adjusted for larger size
eyesAsset.tint = 0xFF0000; // Red eyes for boss
// Add crown/spikes
var crownAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.6,
scaleY: 1.2
});
crownAsset.x = 0;
crownAsset.y = -320; // Adjusted for larger size
crownAsset.tint = 0xFFD700; // Gold crown
self.health = 500; // Same health as secret boss
self.maxHealth = 500;
self.speed = 0.5; // Slower than regular enemies
self.damage = 30; // More damage than regular enemies
self.coinValue = 50; // Lots of coins when defeated
self.enemyType = 'boss';
self.isBoss = true;
self.lastSpecialAttack = 0;
self.specialAttackCooldown = 300; // 5 seconds at 60fps
self.update = function () {
// Add intimidating pulsing aura effect
if (LK.ticks % 120 === 0) {
// Every 2 seconds
LK.effects.flashObject(self, 0xFF4500, 300); // Orange intimidation flash
// Slight scale pulse for intimidation
tween(self, {
scaleX: 2.1,
scaleY: 2.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
// Enemy special power - speed boost when in range of units
if (LK.ticks - self.lastSpecialPower >= self.specialPowerCooldown && self.canUseSpecialPower) {
for (var i = 0; i < defensiveUnits.length; i++) {
var unit = defensiveUnits[i];
var unitDistance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (unitDistance <= 300) {
// Within range of a unit
self.lastSpecialPower = LK.ticks;
// Temporary speed boost and visual effect
var originalSpeed = self.speed;
self.speed *= 2.5; // 2.5x speed boost
LK.effects.flashObject(self, 0xFF8800, 300); // Orange flash
// Special attack when in range but not at fortress yet
// Speed boost animation
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
// Return to normal after 1 second
LK.setTimeout(function () {
self.speed = originalSpeed;
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}, 1000);
break; // Only use power once per cooldown
}
}
}
// Move toward fortress
var dx = fortress.x - self.x;
var dy = fortress.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 400 && distance > 215 && LK.ticks - self.lastSpecialAttack >= self.specialAttackCooldown) {
self.lastSpecialAttack = LK.ticks;
// Boss special power - weakens fortress
LK.effects.flashObject(self, 0xFF00FF, 500);
fortress.takeDamage(15); // Special attack damage
tween(self, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeOut
});
tween(self, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 300,
easing: tween.easeIn
});
}
if (distance > 300) {
// Not at fortress yet - move closer
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Boss doesn't reach fortress - just damages it from distance and disappears
fortress.takeDamage(5);
enemiesEntered++; // Count boss entry
self.markForDestroy = true;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
coins += self.coinValue;
enemiesKilled++;
// Reset trollface flag when boss dies to allow repeat triggers
trollfaceShown = false;
gameWon = true; // Win when boss is defeated!
self.markForDestroy = true;
}
};
return self;
});
var DefensiveUnit = Container.expand(function (unitType) {
var self = Container.call(this);
var unitGraphics = self.attachAsset(unitType, {
anchorX: 0.5,
anchorY: 1.0
});
// Add character details for Mario-style appearance
var hatAsset, weaponAsset;
if (unitType === 'archer') {
// Add archer hat
hatAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.8,
scaleY: 0.6
});
hatAsset.x = 0;
hatAsset.y = -140;
hatAsset.tint = 0x228B22;
} else if (unitType === 'spearman') {
// Add spearman helmet
hatAsset = self.attachAsset('spear', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.9,
scaleY: 0.7
});
hatAsset.x = 0;
hatAsset.y = -140;
hatAsset.tint = 0x4169E1;
} else if (unitType === 'cavalry') {
// Add cavalry plume
hatAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.2,
scaleY: 0.8
});
hatAsset.x = 0;
hatAsset.y = -140;
hatAsset.tint = 0x9932CC;
}
if (unitType === 'archer') {
self.damage = 15;
self.range = 350;
self.attackSpeed = 45; // frames between attacks
self.cost = 10;
} else if (unitType === 'spearman') {
self.damage = 25;
self.range = 225;
self.attackSpeed = 30;
self.cost = 15;
} else if (unitType === 'cavalry') {
self.damage = 35;
self.range = 250;
self.attackSpeed = 20;
self.cost = 25;
}
// Apply shop power upgrades to range and attack speed with validation
var powerUpgrade = 0;
if (unitUpgrades[unitType] && typeof unitUpgrades[unitType].power === 'number') {
powerUpgrade = Math.max(0, unitUpgrades[unitType].power);
}
self.range += powerUpgrade * 25; // Each power level adds 25 range
self.attackSpeed = Math.max(5, self.attackSpeed - powerUpgrade * 3); // Each power level improves speed (lower = faster), minimum 5
self.unitType = unitType;
self.attackTimer = 0;
self.target = null;
self.battlesCount = 0; // Track number of battles
self.maxDamage = self.damage; // Store original damage for weakening calculation
self.fatigueLevel = 0; // Unit fatigue from battles
self.update = function () {
self.attackTimer--;
if (self.attackTimer <= 0) {
self.findTarget();
if (self.target && self.isInRange(self.target)) {
self.attack();
self.attackTimer = self.attackSpeed;
}
}
};
self.findTarget = function () {
var closestDistance = self.range;
self.target = null;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance < closestDistance) {
closestDistance = distance;
self.target = enemy;
}
}
};
self.isInRange = function (target) {
var distance = Math.sqrt(Math.pow(target.x - self.x, 2) + Math.pow(target.y - self.y, 2));
return distance <= self.range;
};
self.attack = function () {
if (self.target) {
// Apply battle fatigue - units get weaker with each battle
self.battlesCount++;
self.fatigueLevel = Math.min(self.battlesCount * 0.05, 0.4); // Max 40% damage reduction
var currentDamage = Math.max(1, Math.floor(self.maxDamage * (1 - self.fatigueLevel))); // Ensure minimum 1 damage
// Apply shop damage upgrades with validation
var damageUpgrade = 0;
if (unitUpgrades[self.unitType] && typeof unitUpgrades[self.unitType].damage === 'number') {
damageUpgrade = Math.max(0, unitUpgrades[self.unitType].damage);
}
currentDamage += damageUpgrade * 5;
// Apply combo multiplier to damage
if (comboSystem && comboSystem.comboMultiplier) {
currentDamage = Math.floor(currentDamage * comboSystem.comboMultiplier);
}
var projectile = new Projectile(self.unitType, self.x, self.y, self.target, currentDamage);
// Mark projectile with unit type for tracking
projectile.sourceUnitType = self.unitType;
projectiles.push(projectile);
game.addChild(projectile);
// Play general attack sound for all units
LK.getSound('Ataque').play();
if (self.unitType === 'cavalry') {
LK.getSound('Espada').play();
} else if (self.unitType === 'archer') {
LK.getSound('Arco').play();
}
// Visual feedback for tired units
if (self.fatigueLevel > 0.2) {
tween(self, {
alpha: 0.7
}, {
duration: 200,
easing: tween.easeOut
});
tween(self, {
alpha: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
}
};
// Nuclear defense cubes are 100% invincible - no takeDamage method needed
return self;
});
var DialogueSound = Container.expand(function () {
var self = Container.call(this);
self.playDialogueSound = function () {
// Play dialogue sound effect when characters speak
LK.getSound('dialogo').play();
};
return self;
});
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
var enemyGraphics = self.attachAsset(enemyType, {
anchorX: 0.5,
anchorY: 1.0
});
// Add enemy details for Mario-style appearance
var eyesAsset = self.attachAsset('spear', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
eyesAsset.x = 0;
eyesAsset.y = -120;
eyesAsset.tint = 0xFFFFFF;
if (enemyType === 'strongEnemy') {
// Add spikes for strong enemy
var spikesAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.8,
scaleY: 0.6
});
spikesAsset.x = 0;
spikesAsset.y = -160;
spikesAsset.tint = 0x000000;
}
if (enemyType === 'enemy') {
self.health = 30;
self.maxHealth = 30;
self.speed = 1;
self.damage = 10;
self.coinValue = 2;
} else if (enemyType === 'strongEnemy') {
self.health = 60;
self.maxHealth = 60;
self.speed = 0.8;
self.damage = 20;
self.coinValue = 5;
}
self.enemyType = enemyType;
self.lastSpecialPower = 0;
self.specialPowerCooldown = 120; // 2 seconds at 60fps (shorter than other units)
self.canUseSpecialPower = true;
self.update = function () {
// Enemy special power - launch Poder attack when in range of units
if (LK.ticks - self.lastSpecialPower >= self.specialPowerCooldown && self.canUseSpecialPower) {
for (var i = 0; i < defensiveUnits.length; i++) {
var unit = defensiveUnits[i];
var unitDistance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (unitDistance <= 300) {
// Within range of a unit - launch Poder attack
self.lastSpecialPower = LK.ticks;
var poderProjectile = new PoderProjectile(self.x, self.y, unit, self.damage * 0.5);
projectiles.push(poderProjectile);
game.addChild(poderProjectile);
// Play power sound effect
LK.getSound('Poder').play();
// Visual effect for enemy using power
LK.effects.flashObject(self, 0x00FFFF, 300);
break; // Only use power once per cooldown
}
}
}
// Move toward fortress
var dx = fortress.x - self.x;
var dy = fortress.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 215) {
// Not at fortress yet
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Attack fortress
fortress.takeDamage(self.damage);
enemiesEntered++; // Count enemy entry
self.markForDestroy = true;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
coins += self.coinValue;
enemiesKilled++;
// Reset trollface flag when enemy dies to allow repeat triggers
trollfaceShown = false;
self.markForDestroy = true;
}
};
return self;
});
var Explosion = Container.expand(function (x, y) {
var self = Container.call(this);
// Create multiple explosion particles with more variety
var particles = [];
var particleCount = 12 + Math.floor(Math.random() * 6); // 12-18 particles
for (var i = 0; i < particleCount; i++) {
var particle = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.6,
scaleY: 0.2 + Math.random() * 0.6
});
// Random position offset in circular pattern
var angle = Math.PI * 2 * i / particleCount + Math.random() * 0.5;
var distance = Math.random() * 80;
particle.x = Math.cos(angle) * distance;
particle.y = Math.sin(angle) * distance;
// Enhanced color variety with bright explosion colors
var colors = [0xFF0000, 0xFF4500, 0xFF6600, 0xFF8800, 0xFFAA00, 0xFFCC00, 0xFFFFFF];
particle.tint = colors[Math.floor(Math.random() * colors.length)];
// Random rotation for variety
particle.rotation = Math.random() * Math.PI * 2;
particles.push(particle);
}
self.x = x;
self.y = y;
// Create central flash effect
var centralFlash = self.attachAsset('BigPoder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
centralFlash.tint = 0xFFFFFF;
centralFlash.alpha = 1.0;
// Central flash expansion and fade
tween(centralFlash, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
// Animate explosion particles with improved effects
for (var j = 0; j < particles.length; j++) {
var particle = particles[j];
var finalDistance = 150 + Math.random() * 100;
var particleAngle = Math.atan2(particle.y, particle.x);
var finalX = particle.x + Math.cos(particleAngle) * finalDistance;
var finalY = particle.y + Math.sin(particleAngle) * finalDistance;
// Expanding animation with rotation
tween(particle, {
x: finalX,
y: finalY,
scaleX: particle.scaleX * 1.5,
scaleY: particle.scaleY * 1.5,
rotation: particle.rotation + Math.PI * 3,
alpha: 0
}, {
duration: 600 + Math.random() * 400,
// Varied duration
easing: tween.easeOut
});
}
// Screen shake effect for big explosions
if (Math.random() < 0.3) {
// 30% chance for screen shake
LK.effects.flashScreen(0xFFAA00, 300);
}
// Auto-destroy after animation
LK.setTimeout(function () {
self.markForDestroy = true;
}, 1200);
return self;
});
var Fortress = Container.expand(function () {
var self = Container.call(this);
var fortressGraphics = self.attachAsset('fortress', {
anchorX: 0.5,
anchorY: 1.0
});
// Add castle tower details
var leftTower = self.attachAsset('spearman', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.6,
scaleY: 0.8
});
leftTower.x = -125;
leftTower.y = -75;
leftTower.tint = 0x696969;
var rightTower = self.attachAsset('spearman', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.6,
scaleY: 0.8
});
rightTower.x = 125;
rightTower.y = -75;
rightTower.tint = 0x696969;
// Add flag
var flag = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.8,
scaleY: 0.5
});
flag.x = 0;
flag.y = -350;
flag.tint = 0xFF4500;
// Add shield visual effect
var shieldGraphics = self.attachAsset('fortress', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.2,
scaleY: 1.2
});
shieldGraphics.alpha = 0;
shieldGraphics.tint = 0x00FFFF;
self.health = fortressMaxHealth;
self.maxHealth = fortressMaxHealth;
self.activateShield = function () {
if (shieldCooldown <= 0) {
shieldActive = true;
shieldCooldown = shieldMaxCooldown;
shieldGraphics.alpha = 0.5;
tween(shieldGraphics, {
alpha: 0.8
}, {
duration: 500,
easing: tween.easeInOut
});
LK.setTimeout(function () {
shieldActive = false;
tween(shieldGraphics, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
}, 3000); // Shield lasts 3 seconds
}
};
self.takeDamage = function (damage) {
if (!shieldActive) {
fortressCurrentHealth -= damage;
self.health = fortressCurrentHealth;
LK.effects.flashObject(self, 0xFF0000, 300);
if (fortressCurrentHealth <= 0) {
gameOver = true;
}
} else {
// Shield blocks damage
LK.effects.flashObject(shieldGraphics, 0xFFFFFF, 200);
}
};
return self;
});
var Fortress2 = Container.expand(function () {
var self = Container.call(this);
var fortressGraphics = self.attachAsset('fortress2', {
anchorX: 0.5,
anchorY: 1.0
});
// Add castle tower details
var leftTower = self.attachAsset('spearman', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.6,
scaleY: 0.8
});
leftTower.x = -125;
leftTower.y = -75;
leftTower.tint = 0x696969;
var rightTower = self.attachAsset('spearman', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.6,
scaleY: 0.8
});
rightTower.x = 125;
rightTower.y = -75;
rightTower.tint = 0x696969;
// Add flag
var flag = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.8,
scaleY: 0.5
});
flag.x = 0;
flag.y = -350;
flag.tint = 0xFF4500;
// Add shield visual effect
var shieldGraphics = self.attachAsset('fortress2', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.2,
scaleY: 1.2
});
shieldGraphics.alpha = 0;
shieldGraphics.tint = 0x00FFFF;
self.health = fortressMaxHealth;
self.maxHealth = fortressMaxHealth;
self.activateShield = function () {
if (shieldCooldown <= 0) {
shieldActive = true;
shieldCooldown = shieldMaxCooldown;
shieldGraphics.alpha = 0.5;
tween(shieldGraphics, {
alpha: 0.8
}, {
duration: 500,
easing: tween.easeInOut
});
LK.setTimeout(function () {
shieldActive = false;
tween(shieldGraphics, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
}, 3000); // Shield lasts 3 seconds
}
};
self.takeDamage = function (damage) {
if (!shieldActive) {
fortressCurrentHealth -= damage;
self.health = fortressCurrentHealth;
LK.effects.flashObject(self, 0xFF0000, 300);
if (fortressCurrentHealth <= 0) {
gameOver = true;
}
} else {
// Shield blocks damage
LK.effects.flashObject(shieldGraphics, 0xFFFFFF, 200);
}
};
return self;
});
var MiniBoss = Container.expand(function () {
var self = Container.call(this);
var miniBossGraphics = self.attachAsset('miniboos1', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.5,
// Smaller than regular boss but bigger than normal enemy
scaleY: 1.5
});
// Add mini boss details
var eyesAsset = self.attachAsset('spear', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
eyesAsset.x = 0;
eyesAsset.y = -180; // Adjusted for smaller size
eyesAsset.tint = 0xFFFF00; // Yellow eyes for mini boss
// Add small crown/spikes
var crownAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.2,
scaleY: 1.0
});
crownAsset.x = 0;
crownAsset.y = -240; // Adjusted for smaller size
crownAsset.tint = 0xC0C0C0; // Silver crown
self.health = 150; // More health than enemies but less than boss
self.maxHealth = 150;
self.speed = 0.8; // Faster than regular boss but slower than normal enemies
self.damage = 20; // Less damage than regular boss
self.coinValue = 25; // Medium reward
self.enemyType = 'miniboss';
self.isMiniBoss = true;
self.lastSpecialAttack = 0;
self.specialAttackCooldown = 240; // 4 seconds at 60fps
self.lastSpecialPower = 0;
self.specialPowerCooldown = 120; // 2 seconds at 60fps
self.canUseSpecialPower = true;
self.update = function () {
// Mini boss special power - similar to regular boss but weaker
if (LK.ticks - self.lastSpecialPower >= self.specialPowerCooldown && self.canUseSpecialPower) {
for (var i = 0; i < defensiveUnits.length; i++) {
var unit = defensiveUnits[i];
var unitDistance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (unitDistance <= 250) {
// Shorter range than regular boss
// Within range of a unit
self.lastSpecialPower = LK.ticks;
// Temporary speed boost and visual effect
var originalSpeed = self.speed;
self.speed *= 2.0; // 2x speed boost (less than regular boss)
LK.effects.flashObject(self, 0xFFFF00, 300); // Yellow flash
// Speed boost animation
tween(self, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 300,
easing: tween.easeOut
});
// Return to normal after 1 second
LK.setTimeout(function () {
self.speed = originalSpeed;
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeIn
});
}, 1000);
break; // Only use power once per cooldown
}
}
}
// Move toward fortress
var dx = fortress.x - self.x;
var dy = fortress.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 350 && distance > 215 && LK.ticks - self.lastSpecialAttack >= self.specialAttackCooldown) {
self.lastSpecialAttack = LK.ticks;
// Mini boss special power - weakens fortress but less than regular boss
LK.effects.flashObject(self, 0xFFFF00, 400);
fortress.takeDamage(10); // Less special attack damage than regular boss
tween(self, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 200,
easing: tween.easeOut
});
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
if (distance > 300) {
// Not at fortress yet - move closer
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Mini boss doesn't reach fortress - just damages it from distance and disappears
fortress.takeDamage(5);
enemiesEntered++; // Count mini boss entry
self.markForDestroy = true;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
coins += self.coinValue;
enemiesKilled++;
// Reset trollface flag when mini boss dies to allow repeat triggers
trollfaceShown = false;
self.markForDestroy = true;
}
};
return self;
});
var MiniBoss2 = Container.expand(function () {
var self = Container.call(this);
var miniBossGraphics = self.attachAsset('Miniboos2', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.5,
// Smaller than regular boss but bigger than normal enemy
scaleY: 1.5
});
// Add mini boss details
var eyesAsset = self.attachAsset('spear', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
eyesAsset.x = 0;
eyesAsset.y = -180; // Adjusted for smaller size
eyesAsset.tint = 0xFFFF00; // Yellow eyes for mini boss
// Add small crown/spikes
var crownAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.2,
scaleY: 1.0
});
crownAsset.x = 0;
crownAsset.y = -240; // Adjusted for smaller size
crownAsset.tint = 0xC0C0C0; // Silver crown
self.health = 150; // More health than enemies but less than boss
self.maxHealth = 150;
self.speed = 0.8; // Faster than regular boss but slower than normal enemies
self.damage = 20; // Less damage than regular boss
self.coinValue = 25; // Medium reward
self.enemyType = 'miniboss';
self.isMiniBoss = true;
self.lastSpecialAttack = 0;
self.specialAttackCooldown = 240; // 4 seconds at 60fps
self.lastSpecialPower = 0;
self.specialPowerCooldown = 120; // 2 seconds at 60fps
self.canUseSpecialPower = true;
self.update = function () {
// Mini boss special power - similar to regular boss but weaker
if (LK.ticks - self.lastSpecialPower >= self.specialPowerCooldown && self.canUseSpecialPower) {
for (var i = 0; i < defensiveUnits.length; i++) {
var unit = defensiveUnits[i];
var unitDistance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (unitDistance <= 250) {
// Shorter range than regular boss
// Within range of a unit
self.lastSpecialPower = LK.ticks;
// Temporary speed boost and visual effect
var originalSpeed = self.speed;
self.speed *= 2.0; // 2x speed boost (less than regular boss)
LK.effects.flashObject(self, 0xFFFF00, 300); // Yellow flash
// Speed boost animation
tween(self, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 300,
easing: tween.easeOut
});
// Return to normal after 1 second
LK.setTimeout(function () {
self.speed = originalSpeed;
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeIn
});
}, 1000);
break; // Only use power once per cooldown
}
}
}
// Move toward fortress
var dx = fortress.x - self.x;
var dy = fortress.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 350 && distance > 215 && LK.ticks - self.lastSpecialAttack >= self.specialAttackCooldown) {
self.lastSpecialAttack = LK.ticks;
// Mini boss special power - weakens fortress but less than regular boss
LK.effects.flashObject(self, 0xFFFF00, 400);
fortress.takeDamage(10); // Less special attack damage than regular boss
tween(self, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 200,
easing: tween.easeOut
});
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
if (distance > 300) {
// Not at fortress yet - move closer
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Mini boss doesn't reach fortress - just damages it from distance and disappears
fortress.takeDamage(5);
enemiesEntered++; // Count mini boss entry
self.markForDestroy = true;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
coins += self.coinValue;
enemiesKilled++;
// Reset trollface flag when mini boss dies to allow repeat triggers
trollfaceShown = false;
self.markForDestroy = true;
}
};
return self;
});
// Missile class for missile rain events
var Missile = Container.expand(function (x) {
var self = Container.call(this);
var missileAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
self.x = x;
self.y = -60;
self.speed = 18 + Math.random() * 8;
self.hasDamaged = false;
self.update = function () {
self.y += self.speed;
// Check collision with fortress (centered)
if (!self.hasDamaged && fortress && Math.abs(self.x - fortress.x) < 180 && Math.abs(self.y - fortress.y) < 220) {
self.hasDamaged = true;
if (!shieldActive) {
fortressCurrentHealth = Math.max(0, fortressCurrentHealth - 5);
fortress.health = fortressCurrentHealth;
LK.effects.flashObject(fortress, 0xFF0000, 200);
} else {
LK.effects.flashObject(fortress, 0x00FFFF, 200);
}
// Explosion effect
var explosion = new Explosion(self.x, self.y);
game.addChild(explosion);
self.markForDestroy = true;
}
// Remove if off screen
if (self.y > 2800) {
self.markForDestroy = true;
}
};
return self;
});
// MissileRain class for random missile rain event
var MissileRain = Container.expand(function () {
var self = Container.call(this);
self.duration = 1200; // 20 seconds at 60fps
self.ticks = 0;
self.missiles = [];
self.active = true;
// Show warning overlay
var warningOverlay = LK.getAsset('Alerta', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 7
});
warningOverlay.x = 1024;
warningOverlay.y = 600;
warningOverlay.alpha = 1.0;
self.addChild(warningOverlay);
// Animate warning overlay
tween(warningOverlay, {
alpha: 0
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
warningOverlay.destroy();
}
});
// Play alert sound
LK.getSound('alerta').play();
self.update = function () {
self.ticks++;
// Spawn missiles randomly across the screen every 8-16 ticks
if (self.ticks % (8 + Math.floor(Math.random() * 8)) === 0 && self.ticks < self.duration) {
var missileX = 100 + Math.random() * 1848;
var missile = new Missile(missileX);
self.missiles.push(missile);
game.addChild(missile);
}
// Update all missiles
for (var i = self.missiles.length - 1; i >= 0; i--) {
var m = self.missiles[i];
m.update();
if (m.markForDestroy) {
m.destroy();
self.missiles.splice(i, 1);
}
}
// End rain after duration
if (self.ticks >= self.duration && self.missiles.length === 0) {
self.active = false;
self.markForDestroy = true;
}
};
return self;
});
var NuclearDefenseCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('BigPoder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
// Show the green cube
cubeGraphics.visible = true;
// Add Peligro asset as danger indicator - larger size
var dangerGraphics = self.attachAsset('Peligro', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
dangerGraphics.x = 0;
dangerGraphics.y = 0;
// Visual warning indicators
self.warningLevel = 0;
self.maxWarningLevel = 240; // 4 seconds at 60fps
self.isDefused = false;
// Warning colors from green to red
var warningColors = [0x00FF00, 0x66FF00, 0xCCFF00, 0xFFFF00, 0xFFCC00, 0xFF8800, 0xFF4400, 0xFF0000];
self.update = function () {
if (!self.isDefused) {
self.warningLevel++;
// Change color based on warning level
var colorIndex = Math.min(Math.floor(self.warningLevel / 30), warningColors.length - 1);
dangerGraphics.tint = warningColors[colorIndex];
// Pulsing effect gets faster as time runs out
var pulseSpeed = 0.02 + self.warningLevel / self.maxWarningLevel * 0.08;
dangerGraphics.scaleX = 1.5 + Math.sin(LK.ticks * pulseSpeed) * 0.2;
dangerGraphics.scaleY = 1.5 + Math.sin(LK.ticks * pulseSpeed) * 0.2;
// Rotation effect
dangerGraphics.rotation += 0.05 + self.warningLevel / self.maxWarningLevel * 0.1;
// Check if time is up
if (self.warningLevel >= self.maxWarningLevel) {
// Nuclear bomb hits fortress
self.triggerNuclearBomb();
}
}
};
self.triggerNuclearBomb = function () {
// Massive damage to fortress
if (!shieldActive) {
fortressCurrentHealth = Math.max(0, fortressCurrentHealth - 50);
fortress.health = fortressCurrentHealth;
} else {
// Even with shield, some damage gets through
fortressCurrentHealth = Math.max(0, fortressCurrentHealth - 15);
fortress.health = fortressCurrentHealth;
}
// Massive explosion at fortress
var nuclearExplosion = new Explosion(fortress.x, fortress.y);
// Scale up the explosion
tween(nuclearExplosion, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 800,
easing: tween.easeOut
});
game.addChild(nuclearExplosion);
// Screen effects
LK.effects.flashScreen(0xFFFFFF, 1200);
LK.effects.flashObject(fortress, 0xFF0000, 1500);
// Play explosion sound
LK.getSound('explosion').play();
self.markForDestroy = true;
};
self.down = function (x, y, obj) {
if (!self.isDefused) {
// Successfully defused
self.isDefused = true;
// Visual feedback
dangerGraphics.tint = 0x00FF00;
LK.effects.flashObject(self, 0x00FF00, 500);
// Reward player with coins
coins += 5;
// Play success sound
LK.getSound('Poder').play();
// Shrinking animation
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
self.markForDestroy = true;
}
});
}
};
return self;
});
var PoderProjectile = Container.expand(function (startX, startY, target, damage) {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('Poder', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = startX;
self.y = startY;
self.target = target;
self.damage = damage;
self.speed = 8; // Slower than regular projectiles
// Calculate direction to target
var dx = target.x - startX;
var dy = target.y - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
// Set rotation to face target
projectileGraphics.rotation = Math.atan2(dy, dx);
// Add spinning effect
var spinSpeed = 0.1;
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
// Spin the projectile
projectileGraphics.rotation += spinSpeed;
// Check if hit target
if (self.target && self.target.takeDamage && Math.sqrt(Math.pow(self.target.x - self.x, 2) + Math.pow(self.target.y - self.y, 2)) < 80) {
self.target.takeDamage(self.damage);
// Add special effect when hitting
LK.effects.flashObject(self.target, 0x00FFFF, 500);
self.markForDestroy = true;
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.markForDestroy = true;
}
};
return self;
});
var Projectile = Container.expand(function (unitType, startX, startY, target, damage) {
var self = Container.call(this);
var assetType = unitType === 'archer' ? 'arrow' : 'spear';
var projectileGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = startX;
self.y = startY;
self.target = target;
self.damage = damage;
self.speed = 12;
// Calculate direction to target
var dx = target.x - startX;
var dy = target.y - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
// Set rotation to face target
projectileGraphics.rotation = Math.atan2(dy, dx);
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
// Check if hit target
if (self.target && self.target.takeDamage && Math.sqrt(Math.pow(self.target.x - self.x, 2) + Math.pow(self.target.y - self.y, 2)) < 80) {
// Track health before damage for kill detection
var targetHealthBefore = self.target.health;
self.target.takeDamage(self.damage);
// Check if this projectile killed the target and we're tracking
if (trackingActive && targetHealthBefore > 0 && self.target.health <= 0) {
// Only count kills from archer or spearman projectiles
if (self.sourceUnitType === 'archer' || self.sourceUnitType === 'spearman') {
enemiesKilledByTrackedUnits++;
// Check if we've killed 5 enemies with only our tracked units
if (enemiesKilledByTrackedUnits >= 5 && !secretBossSpawned) {
secretBossConditionMet = true;
}
}
}
// Trigger combo on kill
if (targetHealthBefore > 0 && self.target.health <= 0) {
// Find the source unit and add to combo
for (var cu = 0; cu < defensiveUnits.length; cu++) {
var checkUnit = defensiveUnits[cu];
if (checkUnit && checkUnit.unitType === self.sourceUnitType) {
comboSystem.addKill(checkUnit);
break;
}
}
}
self.markForDestroy = true;
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.markForDestroy = true;
}
};
return self;
});
var ScenarioCube = Container.expand(function () {
var self = Container.call(this);
var cubeGraphics = self.attachAsset('ScenarioCube', {
anchorX: 0.5,
anchorY: 0.5
});
// Add pulsing animation
self.pulseDirection = 1;
self.spawnTime = LK.ticks;
self.update = function () {
// Pulsing effect
if (cubeGraphics.scaleX >= 1.3) {
self.pulseDirection = -1;
} else if (cubeGraphics.scaleX <= 0.8) {
self.pulseDirection = 1;
}
cubeGraphics.scaleX += self.pulseDirection * 0.02;
cubeGraphics.scaleY += self.pulseDirection * 0.02;
// Rotation effect
cubeGraphics.rotation += 0.1;
// Auto-disappear after 10 seconds
if (LK.ticks - self.spawnTime > 600) {
self.markForDestroy = true;
}
};
self.down = function (x, y, obj) {
// Trigger scenario change
changeScenario();
self.markForDestroy = true;
};
return self;
});
var SecretBoss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('Jefesecreto', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 3.0,
scaleY: 3.0
});
// Add mystical aura
var auraAsset = self.attachAsset('Poder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
auraAsset.x = 0;
auraAsset.y = -200;
auraAsset.alpha = 0.3;
auraAsset.tint = 0xFF00FF;
// Add health bar background
var healthBarBg = self.attachAsset('HealthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -350;
// Add health bar fill
var healthBarFill = self.attachAsset('HealthBarFill', {
anchorX: 0,
anchorY: 0.5
});
healthBarFill.x = -200;
healthBarFill.y = -350;
self.health = 500; // Even more health than regular boss
self.maxHealth = 500;
self.speed = 0.3; // Very slow but powerful
self.damage = 50; // Massive damage
self.coinValue = 100; // Huge reward
self.enemyType = 'secretboss';
self.isSecretBoss = true;
self.lastSpecialAttack = 0;
self.specialAttackCooldown = 180; // 3 seconds
self.update = function () {
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.width = 400 * healthPercent;
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00FF00;
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xFFFF00;
} else {
healthBarFill.tint = 0xFF0000;
}
// Mystical aura spinning effect
auraAsset.rotation += 0.05;
// Check distance to fortress for BigPoder attack
var dx = fortress.x - self.x;
var dy = fortress.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// BigPoder attack when in range but not too close
if (LK.ticks - self.lastSpecialAttack >= self.specialAttackCooldown && distance <= 600 && distance > 300) {
self.lastSpecialAttack = LK.ticks;
// Launch BigPoder projectile at fortress with reduced damage
var bigPoderProjectile = new BigPoderProjectile(self.x, self.y, fortress, 2);
projectiles.push(bigPoderProjectile);
game.addChild(bigPoderProjectile);
// Play power sound effect louder
LK.getSound('Poder').play();
// Visual effect with growing animation
LK.effects.flashObject(self, 0xFF00FF, 500);
tween(self, {
scaleX: 3.5,
scaleY: 3.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 400,
easing: tween.easeIn
});
}
});
} else if (distance > 600) {
// Move toward fortress when far away
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else if (distance <= 600) {
// Stay in attack range, don't get too close
// Do nothing, just stay and attack
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
coins += self.coinValue;
enemiesKilled++;
LK.getSound('jefesecreto').play();
// Switch back to normal background music when secret boss is defeated
LK.playMusic('background');
gameWon = true; // Win when secret boss is defeated!
self.markForDestroy = true;
}
};
return self;
});
var TimeDistortion = Container.expand(function () {
var self = Container.call(this);
// Visual effect circle that expands outward
var distortionRing = self.attachAsset('BigPoder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
distortionRing.tint = 0x00FFFF;
distortionRing.alpha = 0.6;
// Inner energy core
var energyCore = self.attachAsset('Poder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
energyCore.tint = 0xFFFFFF;
energyCore.alpha = 0.8;
self.duration = 600; // 10 seconds
self.ticks = 0;
self.active = true;
self.affectedEnemies = [];
self.affectedProjectiles = [];
// Expansion animation for ring
tween(distortionRing, {
scaleX: 15,
scaleY: 15,
alpha: 0.2
}, {
duration: 1000,
easing: tween.easeOut
});
// Pulsing animation for core
function pulseCore() {
if (self.active) {
tween(energyCore, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1.0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
tween(energyCore, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
pulseCore();
}
});
}
}
});
}
}
pulseCore();
self.update = function () {
self.ticks++;
energyCore.rotation += 0.15; // Spinning energy core
distortionRing.rotation -= 0.05; // Counter-rotating ring
// Apply time distortion effects to all enemies and projectiles within range
var distortionRadius = 800;
// Slow down enemies within range
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance <= distortionRadius) {
// Mark enemy as affected if not already
if (self.affectedEnemies.indexOf(enemy) === -1) {
self.affectedEnemies.push(enemy);
enemy.originalSpeed = enemy.speed;
enemy.speed *= 0.3; // Slow to 30% speed
// Visual effect - blue tint
tween(enemy, {
tint: 0x0088FF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
}
// Slow down enemy projectiles within range
for (var j = 0; j < projectiles.length; j++) {
var proj = projectiles[j];
if (proj.target && proj.target === fortress) {
// Only affect enemy projectiles (those targeting fortress)
var projDistance = Math.sqrt(Math.pow(proj.x - self.x, 2) + Math.pow(proj.y - self.y, 2));
if (projDistance <= distortionRadius) {
if (self.affectedProjectiles.indexOf(proj) === -1) {
self.affectedProjectiles.push(proj);
proj.originalSpeed = proj.speed;
proj.speed *= 0.2; // Slow projectiles even more
// Visual trail effect
tween(proj, {
tint: 0x00DDFF
}, {
duration: 200,
easing: tween.easeOut
});
}
}
}
}
// End distortion after duration
if (self.ticks >= self.duration) {
self.active = false;
// Restore original speeds and remove effects
for (var k = 0; k < self.affectedEnemies.length; k++) {
var affectedEnemy = self.affectedEnemies[k];
if (affectedEnemy.originalSpeed !== undefined) {
affectedEnemy.speed = affectedEnemy.originalSpeed;
// Remove tint
tween(affectedEnemy, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
}
}
for (var l = 0; l < self.affectedProjectiles.length; l++) {
var affectedProj = self.affectedProjectiles[l];
if (affectedProj.originalSpeed !== undefined) {
affectedProj.speed = affectedProj.originalSpeed;
// Remove tint
tween(affectedProj, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Fade out effect
tween(self, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
self.markForDestroy = true;
}
});
}
};
return self;
});
// Unit Leveling and Combo System
var UnitCombo = Container.expand(function () {
var self = Container.call(this);
self.comboCount = 0;
self.comboTimer = 0;
self.maxComboTimer = 300; // 5 seconds at 60fps
self.comboMultiplier = 1.0;
self.comboLevel = 0; // 0-5 levels
self.participatingUnits = [];
self.update = function () {
if (self.comboTimer > 0) {
self.comboTimer--;
} else if (self.comboCount > 0) {
// Combo expired
self.resetCombo();
}
};
self.addKill = function (unit) {
self.comboCount++;
self.comboTimer = self.maxComboTimer;
// Update combo multiplier based on count
if (self.comboCount >= 5) {
self.comboLevel = 5;
self.comboMultiplier = 3.0;
} else if (self.comboCount >= 4) {
self.comboLevel = 4;
self.comboMultiplier = 2.5;
} else if (self.comboCount >= 3) {
self.comboLevel = 3;
self.comboMultiplier = 2.0;
} else if (self.comboCount >= 2) {
self.comboLevel = 2;
self.comboMultiplier = 1.5;
} else {
self.comboLevel = 1;
self.comboMultiplier = 1.2;
}
// Track participating unit
if (self.participatingUnits.indexOf(unit) === -1) {
self.participatingUnits.push(unit);
}
// Bonus coins for combo
var bonusCoins = Math.floor(self.comboCount * 2);
coins += bonusCoins;
// Visual feedback
LK.effects.flashScreen(0xFFFF00, 200);
};
self.resetCombo = function () {
self.comboCount = 0;
self.comboLevel = 0;
self.comboMultiplier = 1.0;
self.participatingUnits = [];
self.comboTimer = 0;
};
return self;
});
var UnitLevel = Container.expand(function () {
var self = Container.call(this);
self.level = 1;
self.experience = 0;
self.experienceToNextLevel = 100;
self.bonusDamage = 0;
self.bonusRange = 0;
self.bonusSpeed = 0;
self.gainExperience = function (amount) {
self.experience += amount;
if (self.experience >= self.experienceToNextLevel) {
self.levelUp();
}
};
self.levelUp = function () {
self.level++;
self.experience = 0;
self.experienceToNextLevel = Math.floor(self.experienceToNextLevel * 1.5);
// Calculate stat bonuses based on level
self.bonusDamage = Math.floor((self.level - 1) * 5);
self.bonusRange = Math.floor((self.level - 1) * 25);
self.bonusSpeed = Math.floor((self.level - 1) * 0.1 * 10) / 10; // 0.1 increment
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFFCC00 // Bright 8-bit yellow desert background
});
/****
* Game Code
****/
// Load persisted upgrades into game with validation
// Remove healButton if secret boss is defeated or game reset
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
if (storage.unitUpgrades && _typeof(storage.unitUpgrades) === 'object') {
// Validate structure exists before assignment
if (storage.unitUpgrades.archer && storage.unitUpgrades.spearman && storage.unitUpgrades.cavalry) {
unitUpgrades = storage.unitUpgrades;
}
}
if (storage.shopCoins && typeof storage.shopCoins === 'number' && storage.shopCoins >= 0) {
shopCoins = Math.floor(storage.shopCoins);
}
if ((!secretBossSpawned || gameOver || gameWon) && healButton) {
if (typeof healButton.destroy === "function") {
healButton.destroy();
}
healButton = null;
}
var gameState = 'menu'; // 'menu' or 'playing'
var menuElements = [];
// Scenario change variables
var scenarioCubes = [];
var lastCubeSpawn = 0;
var cubeSpawnInterval = 1200; // 20 seconds at 60fps
var currentScenario = 'desert'; // 'desert' or 'alternate'
var scenarioChangeActive = false;
// Nuclear Defense System variables
var nuclearDefenseActive = false;
var nuclearDefenseCubes = [];
var lastNuclearAttackTime = 0;
var nuclearAttackCooldown = 1800; // 30 seconds between nuclear attack waves
// Missile rain event variables
var missileRainActive = false;
var missileRainTimer = 0;
var missileRainInstance = null;
// Game variables
var fortress;
var defensiveUnits = [];
var enemies = [];
var projectiles = [];
var coins = 50;
var currentWave = 1;
var enemiesInWave = 5;
var enemiesSpawned = 0;
var waveDelay = 180; // 3 seconds at 60fps
var spawnDelay = 60; // 1 second between enemy spawns
var gameOver = false;
var enemiesKilled = 0;
var selectedUnitType = 'archer';
var enemiesEntered = 0; // Track enemies that entered fortress
var maxEnemiesAllowed = 10; // Game ends when 10 enemies enter
var bossSpawned = false;
var bossWave = 10; // Boss appears on wave 10
var gameWon = false;
var fortressMaxHealth = 200;
var fortressCurrentHealth = 200;
var shieldActive = false;
var shieldCooldown = 0;
var shieldMaxCooldown = 600; // 10 seconds at 60fps
var lastShieldTime = 0;
var trollfaceOverlay = null;
var trollfaceShown = false;
var lastAlarmTime = 0;
var alarmCooldown = 300; // 5 seconds at 60fps
// Combo system variables
var comboSystem = new UnitCombo();
var comboText = null;
// Secret boss tracking variables
var secretBossConditionMet = false;
var secretBossSpawned = false;
var archerCount = 0;
var spearmanCount = 0;
var cavalryCount = 0;
var enemiesKilledByTrackedUnits = 0;
var trackingActive = false;
// Healing button variables
var healButton = null;
var healCooldown = 0;
var healMaxCooldown = 360; // 6 seconds at 60fps
// Time Distortion variables
var timeDistortionButton = null;
var timeDistortionCooldown = 0;
var timeDistortionMaxCooldown = 1800; // 30 seconds at 60fps
var timeDistortionActive = false;
var timeDistortionInstance = null;
// Boss spawn tracking variables
var lastBossSpawnKillCount = 0;
var totalMiniBossesSpawned = 0;
var maxMiniBossesToSpawn = 20;
// Shop system variables - initialize persistent weapon upgrades
var shopState = 'menu'; // 'menu' or 'shop'
var unitUpgrades = {
archer: {
damage: 0,
power: 0
},
spearman: {
damage: 0,
power: 0
},
cavalry: {
damage: 0,
power: 0
}
};
var shopCoins = 50;
// Menu initialization function
function initMainMenu() {
gameState = 'menu';
shopState = 'menu';
// Clear any existing menu elements
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].destroy();
}
menuElements = [];
// Set blue background for menu
game.setBackgroundColor(0x0000FF);
// Play menu music
LK.playMusic('Pantalladeinicio');
// Game title
var titleText = new Text2('DEFENSA DE FORTALEZA', {
size: 120,
fill: 0xFFFF00
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
game.addChild(titleText);
menuElements.push(titleText);
// Subtitle
var subtitleText = new Text2('Torre de Defensa Islámica', {
size: 80,
fill: 0xFFFF00
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 550;
game.addChild(subtitleText);
menuElements.push(subtitleText);
// Instructions
var instructionsText = new Text2('¡Defiende tu fortaleza!\nColoca unidades para detener enemigos\n¡No dejes que entren 10 enemigos!', {
size: 80,
fill: 0xFFFF00
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 900;
game.addChild(instructionsText);
menuElements.push(instructionsText);
// Shop button
var shopButton = new Text2('TIENDA', {
size: 90,
fill: 0xFFAA00
});
shopButton.anchor.set(0.5, 0.5);
shopButton.x = 600;
shopButton.y = 1300;
// Create a properly sized hitArea for the shop button
shopButton.hitArea = new Rectangle(-150, -60, 300, 120); //{jl_new}
game.addChild(shopButton);
menuElements.push(shopButton);
shopButton.down = function (x, y, obj) {
// Only trigger if the click is on the button itself
if (obj === shopButton && gameState === 'menu' && shopState === 'menu') {
//{jn_new}
initShop();
} //{jo_new}
};
// Start button with defined clickable area
var startButton = new Text2('JUGAR', {
size: 90,
fill: 0xFFFF00
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 1450;
startButton.y = 1300;
// Create a properly sized hitArea for the button instead of using screen-wide collision
startButton.hitArea = new Rectangle(-150, -60, 300, 120);
game.addChild(startButton);
menuElements.push(startButton);
// Animate start button with continuous twinkling effect
function startTwinkle() {
if (gameState === 'menu' && shopState === 'menu') {
tween(startButton, {
alpha: 0.3,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (gameState === 'menu' && shopState === 'menu') {
tween(startButton, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the twinkling cycle continuously
startTwinkle();
}
});
}
}
});
}
}
startTwinkle();
startButton.interactive = true;
startButton.hitArea = new Rectangle(-150, -60, 300, 120);
startButton.down = function (x, y, obj) {
// Only trigger if the click is on the button itself
if (obj === startButton && gameState === 'menu' && shopState === 'menu') {
//{jV_new}
initCinematic();
} //{jW_new}
};
}
// Shop initialization function
function initShop() {
shopState = 'shop';
// Clear menu elements
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].destroy();
}
menuElements = [];
// Set shop background
game.setBackgroundColor(0x1a1a2e);
// Shop title
var shopTitle = new Text2('TIENDA DE MEJORAS', {
size: 100,
fill: 0xFFFF00
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 1024;
shopTitle.y = 100;
game.addChild(shopTitle);
menuElements.push(shopTitle);
// Coins display
var coinsDisplay = new Text2('Monedas: ' + shopCoins, {
size: 60,
fill: 0xFFCC00
});
coinsDisplay.anchor.set(0.5, 0.5);
coinsDisplay.x = 1024;
coinsDisplay.y = 250;
game.addChild(coinsDisplay);
menuElements.push(coinsDisplay);
// Create upgrade cards for each unit type
var yOffset = 450;
var unitTypes = ['archer', 'spearman', 'cavalry'];
var unitNames = ['Arquero', 'Lancero', 'Caballería'];
var unitColors = [0x00FF00, 0x0080FF, 0xFF00FF];
for (var u = 0; u < unitTypes.length; u++) {
var unitType = unitTypes[u];
var unitName = unitNames[u];
var unitColor = unitColors[u];
// Unit card background
var cardBg = LK.getAsset('HealthBarBg', {
width: 900,
height: 280,
anchorX: 0.5,
anchorY: 0.5
});
cardBg.tint = 0x16213e;
cardBg.x = 1024;
cardBg.y = yOffset;
game.addChild(cardBg);
menuElements.push(cardBg);
// Unit name
var nameText = new Text2(unitName, {
size: 50,
fill: unitColor
});
nameText.anchor.set(0.5, 0.5);
nameText.x = 700;
nameText.y = yOffset - 80;
game.addChild(nameText);
menuElements.push(nameText);
// Damage upgrade section
var damageLabel = new Text2('Daño: ' + unitUpgrades[unitType].damage, {
size: 40,
fill: 0xFFFFFF
});
damageLabel.anchor.set(0.5, 0.5);
damageLabel.x = 900;
damageLabel.y = yOffset - 20;
game.addChild(damageLabel);
menuElements.push(damageLabel);
// Damage upgrade button
var damageButton = new Text2('Mejorar\n(10 monedas)', {
size: 32,
fill: 0x00FF00
});
damageButton.anchor.set(0.5, 0.5);
damageButton.x = 1100;
damageButton.y = yOffset - 20;
game.addChild(damageButton);
menuElements.push(damageButton);
(function (type, damageBtn, damageLabel, coinsDisp) {
damageBtn.down = function () {
if (gameState === 'menu' && shopState === 'shop' && shopCoins >= 10 && unitUpgrades[type] && typeof unitUpgrades[type].damage === 'number') {
shopCoins = Math.max(0, shopCoins - 10);
unitUpgrades[type].damage = Math.max(0, unitUpgrades[type].damage + 1);
coinsDisp.setText('Monedas: ' + shopCoins);
damageLabel.setText('Daño: ' + unitUpgrades[type].damage);
storage.shopCoins = shopCoins;
storage.unitUpgrades = unitUpgrades;
LK.getSound('Poder').play();
tween(damageBtn, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(damageBtn, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
};
})(unitType, damageButton, damageLabel, coinsDisplay);
// Power upgrade section
var powerLabel = new Text2('Poder: ' + unitUpgrades[unitType].power, {
size: 40,
fill: 0xFFFFFF
});
powerLabel.anchor.set(0.5, 0.5);
powerLabel.x = 900;
powerLabel.y = yOffset + 60;
game.addChild(powerLabel);
menuElements.push(powerLabel);
// Power upgrade button
var powerButton = new Text2('Mejorar\n(15 monedas)', {
size: 32,
fill: 0xFF00FF
});
powerButton.anchor.set(0.5, 0.5);
powerButton.x = 1100;
powerButton.y = yOffset + 60;
game.addChild(powerButton);
menuElements.push(powerButton);
(function (type, powerBtn, powerLabel, coinsDisp) {
powerBtn.down = function () {
if (gameState === 'menu' && shopState === 'shop' && shopCoins >= 15 && unitUpgrades[type] && typeof unitUpgrades[type].power === 'number') {
shopCoins = Math.max(0, shopCoins - 15);
unitUpgrades[type].power = Math.max(0, unitUpgrades[type].power + 1);
coinsDisp.setText('Monedas: ' + shopCoins);
powerLabel.setText('Poder: ' + unitUpgrades[type].power);
storage.shopCoins = shopCoins;
storage.unitUpgrades = unitUpgrades;
LK.getSound('Poder').play();
tween(powerBtn, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(powerBtn, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
};
})(unitType, powerButton, powerLabel, coinsDisplay);
yOffset += 350;
}
// Back button to return to main menu
var backButton = new Text2('VOLVER AL MENÚ', {
size: 50,
fill: 0xFF6666
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 1024;
backButton.y = 2550;
game.addChild(backButton);
menuElements.push(backButton);
backButton.down = function () {
if (gameState === 'menu' && shopState === 'shop') {
shopState = 'menu';
initMainMenu();
}
};
}
// Cinematic initialization function
function initCinematic() {
gameState = 'cinematic';
// Clear menu elements
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].destroy();
}
menuElements = [];
// Set dark background for cinematic
game.setBackgroundColor(0x000020);
// Play cinematic music
LK.playMusic('cinematica');
// Create knight character on left
var knight = LK.getAsset('cavalry', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 2.0,
scaleY: 2.0
});
knight.x = 400;
knight.y = 1800;
game.addChild(knight);
// Create spearman character on right
var spearman = LK.getAsset('spearman', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 2.0,
scaleY: 2.0
});
spearman.x = 1648;
spearman.y = 1800;
game.addChild(spearman);
// Create dialogue box background
var dialogueBox = LK.getAsset('HealthBarBg', {
width: 1800,
height: 300,
anchorX: 0.5,
anchorY: 0.5
});
dialogueBox.x = 1024;
dialogueBox.y = 2200;
dialogueBox.tint = 0x222222;
game.addChild(dialogueBox);
// Create dialogue text
var dialogueText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
dialogueText.anchor.set(0.5, 0.5);
dialogueText.x = 1024;
dialogueText.y = 2200;
game.addChild(dialogueText);
// Animate characters entering from sides
tween(knight, {
x: 600
}, {
duration: 1000,
easing: tween.easeOut
});
tween(spearman, {
x: 1448
}, {
duration: 1000,
easing: tween.easeOut
});
// Start dialogue sequence after characters are in position
LK.setTimeout(function () {
// Knight speaks first
dialogueText.setText('Caballero: "Está a punto de empezar el conflicto"');
// Play dialogue sound when knight speaks
LK.getSound('dialogo').play();
tween(knight, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(knight, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// After 3 seconds, spearman responds
LK.setTimeout(function () {
dialogueText.setText('Lancero: "Sí, en guardia"');
// Play dialogue sound when spearman speaks
LK.getSound('dialogo').play();
tween(spearman, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(spearman, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// After another 2 seconds, fade out and start game
LK.setTimeout(function () {
// Fade out all cinematic elements
tween(knight, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
tween(spearman, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
tween(dialogueBox, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
tween(dialogueText, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clean up cinematic elements
knight.destroy();
spearman.destroy();
dialogueBox.destroy();
dialogueText.destroy();
// Start the actual game
initGame();
}
});
}, 2000);
}, 3000);
}, 1500);
}
// Game initialization function
function initGame() {
gameState = 'playing';
// Reset background to game color
game.setBackgroundColor(0xFFCC00);
// Clear menu elements (already cleared in cinematic)
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].destroy();
}
menuElements = [];
// Reset game variables
coins = 50;
currentWave = 1;
enemiesInWave = 5;
enemiesSpawned = 0;
waveDelay = 180;
spawnDelay = 60;
gameOver = false;
enemiesKilled = 0;
selectedUnitType = 'archer';
enemiesEntered = 0;
bossSpawned = false;
gameWon = false;
fortressCurrentHealth = 200;
shieldActive = false;
shieldCooldown = 0;
trollfaceShown = false;
if (trollfaceOverlay) {
trollfaceOverlay.destroy();
trollfaceOverlay = null;
}
// Reset secret boss tracking
secretBossConditionMet = false;
secretBossSpawned = false;
archerCount = 0;
spearmanCount = 0;
cavalryCount = 0;
enemiesKilledByTrackedUnits = 0;
trackingActive = false;
// Reset boss spawn tracking
lastBossSpawnKillCount = 0;
totalMiniBossesSpawned = 0;
// Reset alarm cooldown
lastAlarmTime = 0;
// Reset combo system
comboSystem.resetCombo();
// Reset healing button
healCooldown = 0;
if (healButton) {
if (typeof healButton.destroy === "function") {
healButton.destroy();
}
healButton = null;
}
// Reset time distortion
timeDistortionCooldown = 0;
timeDistortionActive = false;
if (timeDistortionInstance) {
if (typeof timeDistortionInstance.destroy === "function") {
timeDistortionInstance.destroy();
}
timeDistortionInstance = null;
}
if (timeDistortionButton) {
if (typeof timeDistortionButton.destroy === "function") {
timeDistortionButton.destroy();
}
timeDistortionButton = null;
}
// Reset nuclear defense system
nuclearDefenseActive = false;
for (var reset_i = 0; reset_i < nuclearDefenseCubes.length; reset_i++) {
if (nuclearDefenseCubes[reset_i] && typeof nuclearDefenseCubes[reset_i].destroy === "function") {
nuclearDefenseCubes[reset_i].destroy();
}
}
nuclearDefenseCubes = [];
lastNuclearAttackTime = 0;
// Healing button will be created only when secret boss spawns
// Clear arrays
defensiveUnits = [];
enemies = [];
projectiles = [];
scenarioCubes = [];
// Reset scenario variables
currentScenario = 'desert';
scenarioChangeActive = false;
lastCubeSpawn = 0;
cubeSpawnInterval = 1200;
// Initialize fortress at center
fortress = new Fortress();
fortress.x = 1024;
fortress.y = 1366;
game.addChild(fortress);
// Start background music for gameplay
LK.playMusic('background');
}
// Scenario change function
function changeScenario() {
if (scenarioChangeActive) return;
scenarioChangeActive = true;
// Clear all existing enemies except the fortress
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
// Clear all projectiles
for (var j = projectiles.length - 1; j >= 0; j--) {
projectiles[j].destroy();
projectiles.splice(j, 1);
}
// Clear all defensive units placed by player to leave clean scenario
for (var k = defensiveUnits.length - 1; k >= 0; k--) {
var unit = defensiveUnits[k];
unit.destroy();
defensiveUnits.splice(k, 1);
}
// Change scenario
if (currentScenario === 'desert') {
currentScenario = 'alternate';
game.setBackgroundColor(0x808080); // Gray environment
// Change fortress to fortress2
fortress.destroy();
fortress = new Fortress2();
fortress.x = 1024;
fortress.y = 1366;
game.addChild(fortress);
} else {
currentScenario = 'desert';
game.setBackgroundColor(0xFFCC00); // Desert yellow
// Reset fortress to normal
fortress.destroy();
fortress = new Fortress();
fortress.x = 1024;
fortress.y = 1366;
game.addChild(fortress);
}
// Spawn only airplane in alternate scenario, strongEnemy in desert
if (currentScenario === 'alternate') {
var airplane = new Avion();
enemies.push(airplane);
game.addChild(airplane);
} else {
var singleEnemy = new Enemy('strongEnemy');
singleEnemy.x = Math.random() * 1500 + 274; // Random position not too close to edges
singleEnemy.y = Math.random() * 1000 + 200;
enemies.push(singleEnemy);
game.addChild(singleEnemy);
}
// Visual effect for scenario change
LK.effects.flashScreen(0xFFFFFF, 1000);
// Reset scenario change flag after a delay
LK.setTimeout(function () {
scenarioChangeActive = false;
}, 2000);
}
// Start with main menu
initMainMenu();
// UI Elements
var coinsText = new Text2('Monedas: ' + coins, {
size: 32,
fill: 0xFFFF00
});
coinsText.anchor.set(0, 0);
coinsText.x = 120;
coinsText.y = 50;
LK.gui.topLeft.addChild(coinsText);
var waveText = new Text2('Oleada: ' + currentWave, {
size: 32,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
waveText.x = 0;
waveText.y = 50;
LK.gui.top.addChild(waveText);
var healthText = new Text2('Fortaleza: ' + fortressCurrentHealth + '/' + fortressMaxHealth, {
size: 32,
fill: 0xFF0000
});
healthText.anchor.set(1, 0);
healthText.x = -20;
healthText.y = 50;
LK.gui.topRight.addChild(healthText);
// Add health bar
var healthBarBg = LK.getAsset('fortress', {
width: 200,
height: 20,
anchorX: 0.5,
anchorY: 0
});
healthBarBg.tint = 0x666666;
healthBarBg.x = 0;
healthBarBg.y = 90;
LK.gui.top.addChild(healthBarBg);
var healthBarFill = LK.getAsset('fortress', {
width: 200,
height: 20,
anchorX: 0,
anchorY: 0
});
healthBarFill.tint = 0x00FF00;
healthBarFill.x = -100;
healthBarFill.y = 90;
LK.gui.top.addChild(healthBarFill);
// Add combo display text
comboText = new Text2('COMBO: 0x1.0', {
size: 32,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
comboText.x = 0;
comboText.y = 130;
LK.gui.top.addChild(comboText);
// Add shield button
var shieldButton = new Text2('Escudo (Listo)', {
size: 24,
fill: 0x00FFFF
});
shieldButton.anchor.set(0.5, 1);
shieldButton.x = 0;
shieldButton.y = -100;
LK.gui.bottom.addChild(shieldButton);
shieldButton.down = function () {
fortress.activateShield();
};
var enemiesEnteredText = new Text2('Enemigos Entraron: ' + enemiesEntered + '/' + maxEnemiesAllowed, {
size: 28,
fill: 0xFFFFFF
});
enemiesEnteredText.anchor.set(0.5, 0);
enemiesEnteredText.x = 0;
enemiesEnteredText.y = 100;
LK.gui.top.addChild(enemiesEnteredText);
// Unit selection buttons
var archerButton = new Text2('Arquero (10)', {
size: 28,
fill: 0x00FF00
});
archerButton.anchor.set(0.5, 1);
archerButton.x = -200;
archerButton.y = -50;
LK.gui.bottom.addChild(archerButton);
var spearmanButton = new Text2('Lancero (15)', {
size: 28,
fill: 0x0080FF
});
spearmanButton.anchor.set(0.5, 1);
spearmanButton.x = 0;
spearmanButton.y = -50;
LK.gui.bottom.addChild(spearmanButton);
var cavalryButton = new Text2('Caballería (25)', {
size: 28,
fill: 0xFF00FF
});
cavalryButton.anchor.set(0.5, 1);
cavalryButton.x = 200;
cavalryButton.y = -50;
LK.gui.bottom.addChild(cavalryButton);
// Button press handlers
archerButton.down = function () {
selectedUnitType = 'archer';
updateButtonColors();
};
spearmanButton.down = function () {
selectedUnitType = 'spearman';
updateButtonColors();
};
cavalryButton.down = function () {
selectedUnitType = 'cavalry';
updateButtonColors();
};
function updateButtonColors() {
archerButton.fill = selectedUnitType === 'archer' ? 0xFFFFFF : 0x00FF00;
spearmanButton.fill = selectedUnitType === 'spearman' ? 0xFFFFFF : 0x0080FF;
cavalryButton.fill = selectedUnitType === 'cavalry' ? 0xFFFFFF : 0xFF00FF;
}
updateButtonColors();
// Game input
game.down = function (x, y, obj) {
if (gameState === 'menu' || gameState === 'cinematic') {
// Block all game input during menu or cinematic
return; //{oF_new}
} //{oH_new}
if (gameOver) return;
// Disable unit placement during nuclear Quick Time Event
if (nuclearDefenseActive) {
return;
}
var unitCost = 0;
if (selectedUnitType === 'archer') {
unitCost = 10;
} else if (selectedUnitType === 'spearman') {
unitCost = 15;
} else if (selectedUnitType === 'cavalry') {
unitCost = 25;
} else {
return; // Invalid unit type
}
if (coins >= unitCost && unitCost > 0) {
var newUnit = new DefensiveUnit(selectedUnitType);
newUnit.x = x;
newUnit.y = y;
defensiveUnits.push(newUnit);
game.addChild(newUnit);
coins = Math.max(0, coins - unitCost);
LK.getSound('deploy').play();
// Track unit counts for secret boss condition
if (selectedUnitType === 'archer') {
archerCount++;
} else if (selectedUnitType === 'spearman') {
spearmanCount++;
} else if (selectedUnitType === 'cavalry') {
cavalryCount++;
}
// Check if we have exactly 3 archers and 1 spearman with no cavalry
if (archerCount === 3 && spearmanCount === 1 && cavalryCount === 0 && !trackingActive && !secretBossSpawned) {
trackingActive = true;
enemiesKilledByTrackedUnits = 0;
}
// If we deploy any other units or wrong counts, disable tracking
if (trackingActive && (archerCount !== 3 || spearmanCount !== 1 || cavalryCount > 0)) {
trackingActive = false;
enemiesKilledByTrackedUnits = 0; // Reset kill count when tracking stops
}
}
};
// Spawn enemies
function spawnEnemy() {
var enemy;
// Spawn boss on wave 10
if (currentWave >= bossWave && !bossSpawned) {
enemy = new Boss();
bossSpawned = true;
} else {
var enemyType = currentWave > 3 && Math.random() < 0.3 ? 'strongEnemy' : 'enemy';
enemy = new Enemy(enemyType);
}
// Spawn from random edge, avoiding fortress area
var side = Math.floor(Math.random() * 4);
if (side === 0) {
// Top - avoid fortress center area
enemy.x = Math.random() < 0.5 ? Math.random() * 700 : Math.random() * 700 + 1348;
enemy.y = -50;
} else if (side === 1) {
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
} else if (side === 2) {
// Bottom - avoid fortress center area
enemy.x = Math.random() < 0.5 ? Math.random() * 700 : Math.random() * 700 + 1348;
enemy.y = 2782;
} else {
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
}
// Initialize spawn time for auto-disappear functionality
enemy.spawnTime = LK.ticks;
enemies.push(enemy);
game.addChild(enemy);
}
game.update = function () {
// Don't run game logic when in menu or cinematic
if (gameState === 'menu' || gameState === 'cinematic') {
return;
}
// Check win condition - boss defeated
if (gameWon) {
LK.showYouWin();
return;
}
// Check lose conditions
if (gameOver || enemiesEntered >= maxEnemiesAllowed) {
LK.showGameOver();
return;
}
// Update shield cooldown
if (shieldCooldown > 0) {
shieldCooldown--;
}
// Update heal cooldown and button appearance
if (healCooldown > 0) {
healCooldown--;
}
// Update time distortion cooldown
if (timeDistortionCooldown > 0) {
timeDistortionCooldown--;
}
// Create Time Distortion button when player has 5+ archer units and at least wave 3
var archerUnitsCount = 0;
for (var archer_i = 0; archer_i < defensiveUnits.length; archer_i++) {
if (defensiveUnits[archer_i].unitType === 'archer') {
archerUnitsCount++;
}
}
if (archerUnitsCount >= 5 && currentWave >= 3 && !timeDistortionButton) {
timeDistortionButton = new Text2('DISTORSIÓN TEMPORAL', {
size: 20,
fill: 0x00FFFF
});
timeDistortionButton.anchor.set(0.5, 1);
timeDistortionButton.x = -200;
timeDistortionButton.y = -150;
LK.gui.bottom.addChild(timeDistortionButton);
timeDistortionButton.down = function () {
if (timeDistortionCooldown <= 0 && !timeDistortionActive) {
// Activate time distortion at fortress location
timeDistortionActive = true;
timeDistortionCooldown = timeDistortionMaxCooldown;
timeDistortionInstance = new TimeDistortion();
timeDistortionInstance.x = fortress.x;
timeDistortionInstance.y = fortress.y;
game.addChild(timeDistortionInstance);
// Visual and audio feedback
LK.effects.flashScreen(0x00FFFF, 500);
LK.getSound('Poder').play();
}
};
}
// Update time distortion button appearance
if (timeDistortionButton) {
if (timeDistortionCooldown > 0) {
var secondsLeft = Math.ceil(timeDistortionCooldown / 60);
timeDistortionButton.setText('DISTORSIÓN (' + secondsLeft + 's)');
timeDistortionButton.fill = 0x666666;
} else if (timeDistortionActive) {
timeDistortionButton.setText('DISTORSIÓN ACTIVA');
timeDistortionButton.fill = 0x00FF00;
} else {
timeDistortionButton.setText('DISTORSIÓN TEMPORAL');
timeDistortionButton.fill = 0x00FFFF;
}
}
// Update time distortion instance
if (timeDistortionActive && timeDistortionInstance) {
timeDistortionInstance.update();
if (!timeDistortionInstance.active) {
timeDistortionActive = false;
if (typeof timeDistortionInstance.destroy === "function") {
timeDistortionInstance.destroy();
}
timeDistortionInstance = null;
}
}
// Remove time distortion button if archer count drops below 5
if (timeDistortionButton && archerUnitsCount < 5) {
timeDistortionButton.destroy();
timeDistortionButton = null;
}
// Update healing button if it exists (only when secret boss is active)
if (healButton && secretBossSpawned) {
if (healCooldown > 0) {
var secondsLeft = Math.ceil(healCooldown / 60);
if (typeof healButton.setText === "function") {
healButton.setText('CURAR (' + secondsLeft + 's)');
healButton.fill = 0x666666;
} else if (healButton.healText && typeof healButton.healText.setText === "function") {
healButton.healText.setText('CURAR (' + secondsLeft + 's)');
healButton.healText.fill = 0x666666;
}
} else {
if (typeof healButton.setText === "function") {
healButton.setText('CURAR');
healButton.fill = 0xFFFFFF;
} else if (healButton.healText && typeof healButton.healText.setText === "function") {
healButton.healText.setText('CURAR');
healButton.healText.fill = 0xFFFFFF;
}
}
}
// Remove healButton if secret boss is defeated or game is reset
if ((!secretBossSpawned || gameOver || gameWon) && healButton) {
healButton.destroy();
healButton = null;
}
// Update combo system
comboSystem.update();
// Update UI
coinsText.setText('Monedas: ' + coins);
waveText.setText('Oleada: ' + currentWave);
healthText.setText('Fortaleza: ' + fortressCurrentHealth + '/' + fortressMaxHealth);
enemiesEnteredText.setText('Enemigos Entraron: ' + enemiesEntered + '/' + maxEnemiesAllowed);
LK.setScore(enemiesKilled);
// Update combo display
if (comboText) {
if (comboSystem.comboLevel > 0) {
comboText.setText('COMBO: ' + comboSystem.comboCount + 'x' + comboSystem.comboMultiplier.toFixed(1));
// Color intensity increases with combo level
var comboColors = [0xFFFF00, 0xFFCC00, 0xFF9900, 0xFF6600, 0xFF3300, 0xFF0000];
comboText.fill = comboColors[Math.min(comboSystem.comboLevel - 1, 5)];
// Scale effect based on combo
tween(comboText, {
scaleX: 1.0 + comboSystem.comboLevel * 0.1,
scaleY: 1.0 + comboSystem.comboLevel * 0.1
}, {
duration: 100,
easing: tween.easeOut
});
} else {
comboText.setText('COMBO: 0x1.0');
comboText.fill = 0xFFFF00;
comboText.scaleX = 1.0;
comboText.scaleY = 1.0;
}
}
// Update health bar
var healthPercent = fortressCurrentHealth / fortressMaxHealth;
healthBarFill.width = 200 * healthPercent;
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00FF00;
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xFFFF00;
} else {
healthBarFill.tint = 0xFF0000;
}
// Update shield button
if (shieldCooldown > 0) {
var secondsLeft = Math.ceil(shieldCooldown / 60);
shieldButton.setText('Escudo (' + secondsLeft + 's)');
shieldButton.fill = 0x666666;
} else {
shieldButton.setText('Escudo (Listo)');
shieldButton.fill = 0x00FFFF;
}
// Spawn enemies for current wave - only if in desert scenario
if (currentScenario === 'desert' && enemiesSpawned < enemiesInWave && LK.ticks % spawnDelay === 0) {
spawnEnemy();
enemiesSpawned++;
}
// Check if wave is complete
if (enemiesSpawned >= enemiesInWave && enemies.length === 0) {
if (waveDelay > 0) {
waveDelay--;
} else {
// Start next wave
currentWave++;
enemiesInWave = Math.min(5 + currentWave * 2, 20);
enemiesSpawned = 0;
waveDelay = 180;
spawnDelay = Math.max(30, 60 - currentWave * 2);
}
}
// Update defensive units
for (var i = 0; i < defensiveUnits.length; i++) {
defensiveUnits[i].update();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Auto-disappear enemies after they've been alive for too long (except bosses)
if (!enemy.isBoss && !enemy.isMiniBoss && !enemy.isSecretBoss) {
// Initialize spawn time if not set
if (enemy.spawnTime === undefined) {
enemy.spawnTime = LK.ticks;
}
// Auto-disappear after 30 seconds (1800 ticks at 60fps)
if (LK.ticks - enemy.spawnTime > 1800) {
enemy.markForDestroy = true;
}
}
if (enemy.markForDestroy) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Check if we're in boss mode (any boss or mini boss exists)
var inBossMode = false;
for (var j = 0; j < enemies.length; j++) {
if (enemies[j].isBoss || enemies[j].isMiniBoss || enemies[j].isSecretBoss) {
inBossMode = true;
break;
}
}
// Check for alerta warning when 5 enemies enter fortress (only if not in boss mode)
if (enemiesEntered === 5 && LK.ticks - lastAlarmTime >= alarmCooldown && !inBossMode) {
lastAlarmTime = LK.ticks;
// Play danger sound effect
LK.getSound('alerta').play();
// Create alerta overlay that appears quickly and fades out - same size as trollface
var alertaOverlay = LK.getAsset('Alerta', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 15
});
alertaOverlay.x = 1024;
alertaOverlay.y = 1366;
game.addChild(alertaOverlay);
// Quick flash effect - instantly visible then fade out
alertaOverlay.alpha = 1.0;
tween(alertaOverlay, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
alertaOverlay.destroy();
}
});
}
// Check for trollface trigger every 10 enemies killed (10, 20, 30, etc.) (only if not in boss mode)
if (enemiesKilled > 0 && enemiesKilled % 10 === 0 && !trollfaceShown && !inBossMode) {
trollfaceShown = true;
// Create trollface overlay that starts small and expands
trollfaceOverlay = LK.getAsset('Trollface', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0
});
trollfaceOverlay.x = 1024;
trollfaceOverlay.y = 1366;
game.addChild(trollfaceOverlay);
// Play trollface sound effect when appearing
LK.getSound('trollface').play();
// Tornado expanding effect when appearing
tween(trollfaceOverlay, {
scaleX: 20,
scaleY: 15,
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeOut
});
// Show trollface for 1 second to match shorter sound, then animate it away
LK.setTimeout(function () {
if (trollfaceOverlay) {
// Play trollface sound effect when disappearing
LK.getSound('trollface').play();
// Swirling and shrinking animation - shorter to match sound
tween(trollfaceOverlay, {
rotation: Math.PI * 4,
// 2 full rotations for faster animation
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (trollfaceOverlay) {
trollfaceOverlay.destroy();
trollfaceOverlay = null;
}
}
});
}
}, 1000);
}
// Check for boss spawn every 10 enemies killed
if (enemiesKilled >= lastBossSpawnKillCount + 10) {
lastBossSpawnKillCount = enemiesKilled;
// Spawn main boss only once (first time reaching 10 kills) and only if not already spawned
if (enemiesKilled === 10 && !bossSpawned) {
var mainBoss = new Boss();
mainBoss.x = 1024; // Center top
mainBoss.y = -100;
// Start with dramatic entrance - completely invisible and small
mainBoss.scaleX = 0.0;
mainBoss.scaleY = 0.0;
mainBoss.alpha = 0.0;
enemies.push(mainBoss);
game.addChild(mainBoss);
bossSpawned = true; // Mark boss as spawned
// ============================================================================
// COMPREHENSIVE BOSS ENTRANCE ANIMATION SYSTEM
// This section creates an epic, multi-layered entrance sequence for the ogre boss
// featuring dramatic visual effects, sound design, and choreographed animations
// that build tension and create an memorable boss encounter experience.
// ============================================================================
// PHASE 1: DRAMATIC WARNING AND ENVIRONMENT PREPARATION
// Create ominous atmosphere with dark screen overlay and warning text
LK.effects.flashScreen(0x000000, 800); // Extended dark flash for dramatic buildup
var warningText = new Text2('¡EL JEFE OGRO SE ACERCA!', {
size: 120,
fill: 0xFF0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
warningText.alpha = 0;
game.addChild(warningText);
// Dramatic warning text entrance with pulsing intensity animation
tween(warningText, {
alpha: 1.0,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Secondary pulse for emphasis
tween(warningText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Third pulse with red flash
LK.effects.flashObject(warningText, 0xFF0000, 500);
}
});
}
});
// PHASE 2: ENVIRONMENTAL DISTURBANCE AND MUSIC TRANSITION
LK.setTimeout(function () {
// Warning text dramatic exit with shrinking and fading
tween(warningText, {
alpha: 0,
scaleX: 0,
scaleY: 0,
rotation: Math.PI
}, {
duration: 600,
easing: tween.easeIn,
onFinish: function onFinish() {
warningText.destroy();
}
});
// Dramatic boss music entrance with fade-in crescendo
LK.playMusic('Bossogro', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
// PHASE 3: GROUND TREMORS AND SEISMIC ACTIVITY SIMULATION
LK.setTimeout(function () {
// Intensifying ground shake sequence with multiple impact waves
for (var shake = 0; shake < 5; shake++) {
LK.setTimeout(function () {
// Varied screen flash colors for realistic ground disturbance
var shakeColors = [0x8B4513, 0x654321, 0x3E2723, 0x5D4037];
LK.effects.flashScreen(shakeColors[Math.floor(Math.random() * shakeColors.length)], 250);
// Multiple ground impact explosion effects with randomized positioning
for (var impact = 0; impact < 7; impact++) {
var groundShake = new Explosion(300 + Math.random() * 1448,
// Wider spread across entire screen
fortress.y + (Math.random() - 0.5) * 400 // Varied vertical positioning around fortress
);
// Vary explosion sizes for realistic seismic effect
tween(groundShake, {
scaleX: 0.8 + Math.random() * 1.4,
scaleY: 0.8 + Math.random() * 1.4
}, {
duration: 400,
easing: tween.easeOut
});
game.addChild(groundShake);
}
}, shake * 200); // Faster succession for building intensity
}
// PHASE 4: EPIC BOSS MATERIALIZATION SEQUENCE
LK.setTimeout(function () {
// Boss visibility activation with mystical appearance effect
mainBoss.alpha = 1.0;
// MULTI-STAGE DRAMATIC ENTRANCE CHOREOGRAPHY
// Stage 1: Emergence from underground with elastic bounce
tween(mainBoss, {
scaleX: 2.2,
scaleY: 2.2,
y: mainBoss.y + 80,
rotation: 0.1
}, {
duration: 1500,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Stage 2: Intimidation roar with massive size increase
tween(mainBoss, {
scaleX: 3.2,
scaleY: 3.2,
rotation: -0.1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Stage 3: Final settling with authoritative presence
tween(mainBoss, {
scaleX: 2.0,
scaleY: 2.0,
rotation: 0,
y: mainBoss.y - 30
}, {
duration: 800,
easing: tween.bounceOut
});
// Create intimidation aura effect around boss
for (var aura = 0; aura < 6; aura++) {
var auraRing = new Explosion(mainBoss.x, mainBoss.y);
tween(auraRing, {
scaleX: 2.5 + aura * 0.5,
scaleY: 2.5 + aura * 0.5,
alpha: 0.3
}, {
duration: 1000 + aura * 200,
easing: tween.easeOut
});
game.addChild(auraRing);
}
}
});
}
});
// PHASE 5: ENVIRONMENTAL DEVASTATION EFFECTS
// Massive ground impact at boss epicenter
var massiveImpact = new Explosion(mainBoss.x, mainBoss.y + 200);
tween(massiveImpact, {
scaleX: 5.0,
scaleY: 5.0
}, {
duration: 1000,
easing: tween.easeOut
});
game.addChild(massiveImpact);
// PHASE 6: CHROMATIC LIGHT SHOW AND SCREEN EFFECTS
// Cascading color explosion sequence
var flashColors = [0xFF0000, 0xFF4500, 0xFFAA00, 0xFF8800, 0xFF6600];
for (var colorFlash = 0; colorFlash < flashColors.length; colorFlash++) {
(function (color, delay) {
LK.setTimeout(function () {
LK.effects.flashScreen(color, 600);
}, delay);
})(flashColors[colorFlash], colorFlash * 300);
}
// PHASE 7: DEBRIS FIELD AND ATMOSPHERIC PARTICLES
// Extended debris cloud system with varied timing
for (var debris = 0; debris < 12; debris++) {
LK.setTimeout(function () {
var debrisEffect = new Explosion(mainBoss.x + (Math.random() - 0.5) * 600,
// Wider debris field
mainBoss.y + Math.random() * 400);
// Randomized debris characteristics
tween(debrisEffect, {
scaleX: 0.5 + Math.random() * 1.5,
scaleY: 0.5 + Math.random() * 1.5,
rotation: Math.random() * Math.PI * 2
}, {
duration: 600 + Math.random() * 400,
easing: tween.easeOut
});
game.addChild(debrisEffect);
}, debris * 80 + Math.random() * 120); // Staggered timing with randomization
}
// PHASE 8: AUDIO CLIMAX AND FINAL PRESENCE ESTABLISHMENT
// Boss entrance roar with echo effect simulation
LK.getSound('jefesecreto').play();
LK.setTimeout(function () {
// Secondary roar for echo effect
LK.getSound('jefesecreto').play();
}, 400);
}, 1200); // Synchronized timing with ground tremors
}, 1000); // Coordinated with music transition
}, 1400); // Allows warning text full dramatic impact
// ============================================================================
// END OF COMPREHENSIVE BOSS ENTRANCE ANIMATION SYSTEM
// ============================================================================
}
// Only spawn mini bosses if we haven't reached the limit of 20
if (totalMiniBossesSpawned < maxMiniBossesToSpawn) {
// Spawn horde of mini bosses (4 mini bosses each time)
// Spawn mini boss from top left
var miniBoss1 = new MiniBoss();
miniBoss1.x = 200;
miniBoss1.y = -50;
enemies.push(miniBoss1);
game.addChild(miniBoss1);
totalMiniBossesSpawned++;
// Spawn mini boss from top right
var miniBoss2 = new MiniBoss2();
miniBoss2.x = 1800;
miniBoss2.y = -50;
enemies.push(miniBoss2);
game.addChild(miniBoss2);
totalMiniBossesSpawned++;
// Spawn mini boss from left side
var miniBoss3 = new MiniBoss();
miniBoss3.x = -50;
miniBoss3.y = Math.random() * 1000 + 500;
enemies.push(miniBoss3);
game.addChild(miniBoss3);
totalMiniBossesSpawned++;
// Spawn mini boss from right side
var miniBoss4 = new MiniBoss2();
miniBoss4.x = 2098;
miniBoss4.y = Math.random() * 1000 + 500;
enemies.push(miniBoss4);
game.addChild(miniBoss4);
totalMiniBossesSpawned++;
// Play special sound effect
LK.getSound('jefesecreto').play();
// Visual effect for boss appearance
LK.effects.flashScreen(0xFF8800, 800);
}
}
// Check for secret boss spawn condition
if (secretBossConditionMet && !secretBossSpawned) {
secretBossSpawned = true;
trackingActive = false; // Stop tracking once boss spawns
// Clear all existing enemies when secret boss appears
for (var j = enemies.length - 1; j >= 0; j--) {
var existingEnemy = enemies[j];
existingEnemy.destroy();
enemies.splice(j, 1);
}
// Spawn secret boss
var secretBoss = new SecretBoss();
// Spawn from a dramatic location (top center)
secretBoss.x = 1024;
secretBoss.y = -100;
enemies.push(secretBoss);
game.addChild(secretBoss);
// Create healing button when secret boss appears - same design as shield button
healButton = new Text2('CURAR (Listo)', {
size: 24,
fill: 0x00FF00
});
healButton.anchor.set(0.5, 1);
healButton.x = 200; // Position next to shield button
healButton.y = -100;
LK.gui.bottom.addChild(healButton);
// Add healing button functionality
healButton.down = function () {
if (healCooldown <= 0) {
// Heal fortress for 11 points
var healAmount = 11;
fortressCurrentHealth = Math.min(fortressCurrentHealth + healAmount, fortressMaxHealth);
fortress.health = fortressCurrentHealth;
// Set cooldown
healCooldown = healMaxCooldown;
// Play heal sound
LK.getSound('heal').play();
// Visual effect on fortress
LK.effects.flashObject(fortress, 0x00FF00, 800);
// Visual effect on button
tween(healButton, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(healButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
};
// Play special sound effect
LK.getSound('jefesecreto').play();
// Start secret boss music
LK.playMusic('Secretboos');
// Visual effect for secret boss appearance
LK.effects.flashScreen(0xFF00FF, 1000);
}
// Spawn scenario cube every 20 seconds
if (LK.ticks - lastCubeSpawn >= cubeSpawnInterval && !scenarioChangeActive) {
lastCubeSpawn = LK.ticks;
cubeSpawnInterval = 1200; // 20 seconds at 60fps
var cube = new ScenarioCube();
// Spawn in safe area away from fortress and away from top left UI
var spawnX,
spawnY,
attempts = 0;
do {
spawnX = Math.random() * 1500 + 274;
spawnY = Math.random() * 1500 + 300;
attempts++;
// Avoid top left 0-200 x 0-200 area (UI), and avoid fortress
} while ((Math.sqrt(Math.pow(spawnX - fortress.x, 2) + Math.pow(spawnY - fortress.y, 2)) < 300 || spawnX < 200 && spawnY < 200) && attempts < 20);
cube.x = spawnX;
cube.y = spawnY;
scenarioCubes.push(cube);
game.addChild(cube);
}
// Update scenario cubes
for (var i = scenarioCubes.length - 1; i >= 0; i--) {
var cube = scenarioCubes[i];
cube.update();
if (cube.markForDestroy) {
cube.destroy();
scenarioCubes.splice(i, 1);
}
}
// Spawn airplane occasionally in alternate scenario only - only if no airplane exists
if (currentScenario === 'alternate') {
var airplaneExists = false;
for (var k = 0; k < enemies.length; k++) {
if (enemies[k].speed !== undefined && enemies[k].direction !== undefined) {
airplaneExists = true;
break;
}
}
if (!airplaneExists && LK.ticks % (Math.floor(Math.random() * 300) + 300) === 0) {
var airplane = new Avion();
game.addChild(airplane);
// Store airplanes in enemies array for easy cleanup
enemies.push(airplane);
}
}
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
projectile.update();
if (projectile.markForDestroy) {
projectile.destroy();
projectiles.splice(i, 1);
}
}
// Nuclear Defense System and Missile rain variables are now defined at the top of Game Code section
// Trigger Nuclear Defense System (every 30 seconds after wave 5, not during boss fights)
if (!nuclearDefenseActive && currentWave >= 5 && !inBossMode && !secretBossSpawned && LK.ticks - lastNuclearAttackTime >= nuclearAttackCooldown && gameState === 'playing') {
lastNuclearAttackTime = LK.ticks;
nuclearDefenseActive = true;
// Clear any existing cubes
for (var ndc_i = nuclearDefenseCubes.length - 1; ndc_i >= 0; ndc_i--) {
if (nuclearDefenseCubes[ndc_i] && typeof nuclearDefenseCubes[ndc_i].destroy === "function") {
nuclearDefenseCubes[ndc_i].destroy();
}
nuclearDefenseCubes.splice(ndc_i, 1);
}
// Spawn 4 nuclear defense cubes in different corners/areas
var cubePositions = [{
x: 300,
y: 300
},
// Top left area
{
x: 1748,
y: 300
},
// Top right area
{
x: 300,
y: 2000
},
// Bottom left area
{
x: 1748,
y: 2000
} // Bottom right area
];
for (var pos_i = 0; pos_i < cubePositions.length; pos_i++) {
var nuclearCube = new NuclearDefenseCube();
nuclearCube.x = cubePositions[pos_i].x;
nuclearCube.y = cubePositions[pos_i].y;
nuclearDefenseCubes.push(nuclearCube);
game.addChild(nuclearCube);
}
// Play warning sound
LK.getSound('alerta').play();
// Show warning message
var warningText = new Text2('¡ALERTA NUCLEAR! ¡TOCA LOS CUADROS!', {
size: 80,
fill: 0xFF0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 200;
game.addChild(warningText);
// Animate warning text
tween(warningText, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
warningText.destroy();
}
});
}
// Update nuclear defense cubes
for (var ndc_j = nuclearDefenseCubes.length - 1; ndc_j >= 0; ndc_j--) {
var nuclearCube = nuclearDefenseCubes[ndc_j];
if (nuclearCube) {
nuclearCube.update();
if (nuclearCube.markForDestroy) {
nuclearCube.destroy();
nuclearDefenseCubes.splice(ndc_j, 1);
}
}
}
// Check if all cubes are cleared to end nuclear defense phase
if (nuclearDefenseActive && nuclearDefenseCubes.length === 0) {
nuclearDefenseActive = false;
}
// Randomly trigger missile rain (1/1200 chance per frame, not during boss/secret boss)
if (!missileRainActive && !inBossMode && !secretBossSpawned && Math.random() < 1 / 1200 && gameState === 'playing') {
missileRainActive = true;
missileRainTimer = 0;
if (missileRainInstance && typeof missileRainInstance.destroy === "function") {
missileRainInstance.destroy();
}
missileRainInstance = new MissileRain();
game.addChild(missileRainInstance);
}
// Update missile rain if active
if (missileRainActive && missileRainInstance) {
missileRainInstance.update();
if (!missileRainInstance.active) {
missileRainActive = false;
if (typeof missileRainInstance.destroy === "function") {
missileRainInstance.destroy();
}
missileRainInstance = null;
}
}
// Update explosions - find and update all explosion objects
var allChildren = game.children.slice();
for (var i = allChildren.length - 1; i >= 0; i--) {
var child = allChildren[i];
if (child.markForDestroy) {
child.destroy();
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1903,14 +1903,18 @@
});
shopButton.anchor.set(0.5, 0.5);
shopButton.x = 600;
shopButton.y = 1300;
+ // Create a properly sized hitArea for the shop button
+ shopButton.hitArea = new Rectangle(-150, -60, 300, 120); //{jl_new}
game.addChild(shopButton);
menuElements.push(shopButton);
- shopButton.down = function () {
- if (gameState === 'menu' && shopState === 'menu') {
+ shopButton.down = function (x, y, obj) {
+ // Only trigger if the click is on the button itself
+ if (obj === shopButton && gameState === 'menu' && shopState === 'menu') {
+ //{jn_new}
initShop();
- }
+ } //{jo_new}
};
// Start button with defined clickable area
var startButton = new Text2('JUGAR', {
size: 90,
@@ -1954,10 +1958,14 @@
}
startTwinkle();
startButton.interactive = true;
startButton.hitArea = new Rectangle(-150, -60, 300, 120);
- startButton.down = function () {
- initCinematic();
+ startButton.down = function (x, y, obj) {
+ // Only trigger if the click is on the button itself
+ if (obj === startButton && gameState === 'menu' && shopState === 'menu') {
+ //{jV_new}
+ initCinematic();
+ } //{jW_new}
};
}
// Shop initialization function
function initShop() {
@@ -2563,17 +2571,12 @@
}
updateButtonColors();
// Game input
game.down = function (x, y, obj) {
- if (gameState === 'menu') {
- // Start the cinematic when tapping on menu
- initCinematic();
- return;
- }
- if (gameState === 'cinematic') {
- // Skip cinematic if tapped during dialogue
- return;
- }
+ if (gameState === 'menu' || gameState === 'cinematic') {
+ // Block all game input during menu or cinematic
+ return; //{oF_new}
+ } //{oH_new}
if (gameOver) return;
// Disable unit placement during nuclear Quick Time Event
if (nuclearDefenseActive) {
return;
Una lanza para el guerrero. In-Game asset. 2d. High contrast. No shadows
Flecha. In-Game asset. 2d. High contrast. No shadows
Trollface. In-Game asset. 2d. High contrast. No shadows
Personaje aterrador. In-Game asset. 2d. High contrast. No shadows
Ogro. In-Game asset. 2d. High contrast. No shadows
Ogro músculoso y gigante. In-Game asset. 2d. High contrast. No shadows
Lucky block. In-Game asset. 2d. High contrast. No shadows
Torres gemelas. In-Game asset. 2d. High contrast. No shadows
Avión de color gris sin ruedas 8 bit. In-Game asset. 2d. High contrast. No shadows
Explosión efecto. In-Game asset. 2d. High contrast. No shadows
Cuadrado con signo de !. In-Game asset. 2d. High contrast. No shadows
Imagien bde un jefe terrorífico humanoide de color negro. In-Game asset. 2d. High contrast. No shadows