User prompt
Quiero que el armario sea más gris al cambiar así ma color de Ciudad y quiero que agreges una nueva clase "avión" ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Cada 10 o 5 segundo quiero que aparezca un cuadrado en el mapa que al tocarlo cambie el escenario y la fortaleza y quiero que solo allá un enemigo en ese nuevo escenario ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
y quiero que en la cinematca suene la musica "cinematica"
User prompt
quiero que antes de empezar el juego justo desspues de tocar empezar el juego empieza una evento de sinematica done aparezca el "lancero" y "elcaballero" teniendo un dialogo con texto y que diga caballero:"esta apunto de empezar el conflicto" lancero:"si en guardia" y ahi comenza el juego con normalidad ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
y quiero que mientras este en modo jefe no aparezca ni "trollface" ni la "alarma"
User prompt
quiero que aparezcan solo 20 y luego la partida vuelve a la normalidad
User prompt
y quiero que los enemigos desaparezcan automaticamente
User prompt
claro pero quiero que se teneren una orda de minibosses pero el jefe se genera solo 1 vez
User prompt
no se generan los jefes
User prompt
Y quiero que estos nuevos jefes no llegen al mapa y solo saquen 5 de vida a la torre y quiero que el jefe tenga la misma cantidad de vida que el "jefe secreto' y los "miniboos" menos pero tampoco igual que lo "enemigos"
User prompt
Ahora quiero que suene la música "boosogro"
User prompt
Ahora quiero que le des la respectivas imágenes a "miniboos1" "miniboos2" y a "boosogro"
User prompt
al matar 10 enemigo aparece 1 boos y 2 mini booses
User prompt
quiero ahora hagas que el boos tenga el ataque conmenos daño
User prompt
Quiero que el sonido de troll face dure menos para que coincida con la imagen y el desaparición del mismo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Quiero que el ataque de el jefe no sea Instant death
User prompt
Agregale más vida al medidor de la torre y que el ataque del jefe solo saque 5 puntos cada ataqué
User prompt
Quiero ponerle tiempo de enfriamiento a la alarma
User prompt
Y cuando aparezca el secret Boos los demás enemigos desaparecen
User prompt
Quiero que el secret Boos tenga barra de vida y que no ataque directamente la torre si no que le tire el "poder" pero más grande y con efecto de agrandar y achicar ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Quiero que le agregues su correspondiente música y sonido al secreto Boos
User prompt
Quiero que el "jefesecreto" aparezca al seguír estas instrucciones: desplegar 3 arqueros y un lanzero y estos tienen que matar 5 enemigos solo ellos sin usar otro personaje si no se desactiva la mecánica
User prompt
Pero al ataque no al personaje
User prompt
Quiero que actualices los archivos de música de pantalla de sonido y de fondo
User prompt
Quiero que le pongas el archivo de sonido "espada" a "caballería" lo mismo con "arco" a "arquero" y "ataque" a "lancero" y "poder" a "enemigo"
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
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)
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 () {
// 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;
}
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.floor(self.maxDamage * (1 - self.fatigueLevel));
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
});
}
}
};
self.takeDamage = function (damage) {
// Units can be damaged by enemy Poder attacks
self.fatigueLevel += 0.1; // Extra fatigue from being attacked
self.fatigueLevel = Math.min(self.fatigueLevel, 0.6); // Max 60% damage reduction
// Visual feedback for being hit
LK.effects.flashObject(self, 0xFF0000, 300);
};
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 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 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;
});
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 && 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 && 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;
}
}
}
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 > 300) {
// Move toward fortress when far away
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else if (distance <= 300 && distance > 215) {
// Stay in attack range, don't get too close
// Do nothing, just stay and attack
} else if (distance <= 215) {
// Only attack fortress directly if very close
fortress.takeDamage(self.damage);
enemiesEntered++;
self.markForDestroy = true;
}
};
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;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFFCC00 // Bright 8-bit yellow desert background
});
/****
* Game Code
****/
// Game state management
var gameState = 'menu'; // 'menu' or 'playing'
var menuElements = [];
// Scenario change variables
var scenarioCubes = [];
var lastCubeSpawn = 0;
var cubeSpawnInterval = 300; // 5 seconds at 60fps
var currentScenario = 'desert'; // 'desert' or 'alternate'
var scenarioChangeActive = false;
// 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
// 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;
// Boss spawn tracking variables
var lastBossSpawnKillCount = 0;
var totalMiniBossesSpawned = 0;
var maxMiniBossesToSpawn = 20;
// Menu initialization function
function initMainMenu() {
gameState = '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 = 600;
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 = 700;
game.addChild(subtitleText);
menuElements.push(subtitleText);
// Start button
var startButton = new Text2('TOCAR PARA EMPEZAR', {
size: 90,
fill: 0xFFFF00
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 1024;
startButton.y = 1400;
game.addChild(startButton);
menuElements.push(startButton);
// Instructions
var instructionsText = new Text2('¡Defiende tu fortaleza!\nColoca unidades para detener enemigos\n¡No dejes que entren 10 enemigos!', {
size: 90,
fill: 0xFFFF00
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1000;
game.addChild(instructionsText);
menuElements.push(instructionsText);
// Animate start button with continuous twinkling effect
function startTwinkle() {
if (gameState === 'menu') {
tween(startButton, {
alpha: 0.3,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (gameState === '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();
}
// 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"');
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"');
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;
// Clear arrays
defensiveUnits = [];
enemies = [];
projectiles = [];
scenarioCubes = [];
// Reset scenario variables
currentScenario = 'desert';
scenarioChangeActive = false;
lastCubeSpawn = 0;
cubeSpawnInterval = 300;
// 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);
}
// Change scenario
if (currentScenario === 'desert') {
currentScenario = 'alternate';
game.setBackgroundColor(0x228B22); // Forest green
// Change fortress appearance
fortress.destroy();
fortress = new Fortress();
fortress.x = 1024;
fortress.y = 1366;
game.addChild(fortress);
// Add tint to make it look different
tween(fortress, {
tint: 0x8B4513
}, {
duration: 500,
easing: tween.easeOut
});
} 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 single enemy in new scenario
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 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') {
// Start the cinematic when tapping on menu
initCinematic();
return;
}
if (gameState === 'cinematic') {
// Skip cinematic if tapped during dialogue
return;
}
if (gameOver) return;
var unitCost = selectedUnitType === 'archer' ? 10 : selectedUnitType === 'spearman' ? 15 : 25;
if (coins >= unitCost) {
var newUnit = new DefensiveUnit(selectedUnitType);
newUnit.x = x;
newUnit.y = y;
defensiveUnits.push(newUnit);
game.addChild(newUnit);
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) {
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;
}
}
};
// 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
var side = Math.floor(Math.random() * 4);
if (side === 0) {
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
} else if (side === 1) {
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
} else if (side === 2) {
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2782;
} else {
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
}
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 UI
coinsText.setText('Monedas: ' + coins);
waveText.setText('Oleada: ' + currentWave);
healthText.setText('Fortaleza: ' + fortressCurrentHealth + '/' + fortressMaxHealth);
enemiesEnteredText.setText('Enemigos Entraron: ' + enemiesEntered + '/' + maxEnemiesAllowed);
LK.setScore(enemiesKilled);
// 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
if (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)
if (enemiesKilled === 10) {
var mainBoss = new Boss();
mainBoss.x = 1024; // Center top
mainBoss.y = -100;
enemies.push(mainBoss);
game.addChild(mainBoss);
// Play boss music when main boss spawns
LK.playMusic('Bossogro');
}
// 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);
// 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 5-10 seconds (randomly between 300-600 ticks)
if (LK.ticks - lastCubeSpawn >= cubeSpawnInterval && !scenarioChangeActive) {
lastCubeSpawn = LK.ticks;
cubeSpawnInterval = Math.random() * 300 + 300; // Random between 5-10 seconds
var cube = new ScenarioCube();
// Spawn in safe area away from fortress
var spawnX, spawnY;
do {
spawnX = Math.random() * 1500 + 274;
spawnY = Math.random() * 1500 + 300;
} while (Math.sqrt(Math.pow(spawnX - fortress.x, 2) + Math.pow(spawnY - fortress.y, 2)) < 300);
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);
}
}
// 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);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -851,8 +851,40 @@
}
};
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,
@@ -980,8 +1012,14 @@
****/
// Game state management
var gameState = 'menu'; // 'menu' or 'playing'
var menuElements = [];
+// Scenario change variables
+var scenarioCubes = [];
+var lastCubeSpawn = 0;
+var cubeSpawnInterval = 300; // 5 seconds at 60fps
+var currentScenario = 'desert'; // 'desert' or 'alternate'
+var scenarioChangeActive = false;
// Game variables
var fortress;
var defensiveUnits = [];
var enemies = [];
@@ -1296,16 +1334,76 @@
// Clear arrays
defensiveUnits = [];
enemies = [];
projectiles = [];
+ scenarioCubes = [];
+ // Reset scenario variables
+ currentScenario = 'desert';
+ scenarioChangeActive = false;
+ lastCubeSpawn = 0;
+ cubeSpawnInterval = 300;
// 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);
+ }
+ // Change scenario
+ if (currentScenario === 'desert') {
+ currentScenario = 'alternate';
+ game.setBackgroundColor(0x228B22); // Forest green
+ // Change fortress appearance
+ fortress.destroy();
+ fortress = new Fortress();
+ fortress.x = 1024;
+ fortress.y = 1366;
+ game.addChild(fortress);
+ // Add tint to make it look different
+ tween(fortress, {
+ tint: 0x8B4513
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ } 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 single enemy in new scenario
+ 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, {
@@ -1733,8 +1831,33 @@
LK.playMusic('Secretboos');
// Visual effect for secret boss appearance
LK.effects.flashScreen(0xFF00FF, 1000);
}
+ // Spawn scenario cube every 5-10 seconds (randomly between 300-600 ticks)
+ if (LK.ticks - lastCubeSpawn >= cubeSpawnInterval && !scenarioChangeActive) {
+ lastCubeSpawn = LK.ticks;
+ cubeSpawnInterval = Math.random() * 300 + 300; // Random between 5-10 seconds
+ var cube = new ScenarioCube();
+ // Spawn in safe area away from fortress
+ var spawnX, spawnY;
+ do {
+ spawnX = Math.random() * 1500 + 274;
+ spawnY = Math.random() * 1500 + 300;
+ } while (Math.sqrt(Math.pow(spawnX - fortress.x, 2) + Math.pow(spawnY - fortress.y, 2)) < 300);
+ 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);
+ }
+ }
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
projectile.update();
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