User prompt
No esta funcionando bien la creación de muros, para ello debes crear un contador de distancia, agreaglo temporalmente en las estditicas de info del perosnaje, pone un muro y se reincia el conteo
User prompt
Aumenta la distancua de los muros en 600
User prompt
Earth Warrior; Vida 20 – Daño 1 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120 Earth Warrior2; Vida 40 – Daño 4 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120 Earth Warrior3; Vida 50 – Daño 6 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120, Crea muros, de 10 de vida Earth Warrior4; Vida 80– Daño 8 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120, crea muros, de 20 de vida, y es inmune al daño si es inferior o igual a 10 Earth Warrior5; Vida 100 – Daño 10 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120, arrastra a los enemigos para atrás y cuando esta muy cerca de la torre, se destruye y se vuelve un muro de 250 de vida. Cada segundo de arrastre genera el daño base Los muros se cren asi se coge una distancia inicial de 0 a 200 y luego cada 200 de distancia se genera un muro. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Los enemgios impactados con la ola tienen un efeto de aprticula, este asset se llamara, salpicadura, profavor apra ponerle una mejro apariencia por separado
User prompt
Aaa, okey la solucion es esta, crea una avriable llamada activar_moviento sera una boleana por cada guerro, si esta dentro de rango diga false y si esta fuera del rango true, despues dice que no se puede mover si esta false, listo,
User prompt
iNTENTANUEMENTE CORREGIR
User prompt
El guerro 5 no se detiene cuando entran en su rango de disparo proyectiles, recuerdo que el guerro5 del agau tiene dos habilidades, 1 lanzar un poreyctil y otra lanzar una super ola
User prompt
El guerro 5 del agua, no esta haceidno daño con sus olas a los enemgos y los esta atravesando,
User prompt
Las explosiones del guerro nivel 4 agua y guerro nivel 3 agua, solo curan no hacen daño a los enemigos
User prompt
se esta hacciendo mas de 6 de daño las miniolas,
User prompt
Las miniolas del guerro 4 no estan haciedno daño
User prompt
El guerro 3 del eugo esta haciendo 18 de daño en el primer ataca ya que 6 de base, mas la quemadura, pues esta quemadura le uita 6 de vida cada segundo, hasta 3s, entonces en total el golpe deberia hacer 12 de daño
User prompt
El guerrro 3 del fuego deberia ahcer una explosion cuando ataca
User prompt
No atacan, se detienen pero no atcan, no reproduce el audio que me cofirma el ataque
User prompt
No atacan los guerreros de fuego no hacen daño, corrige eso, porque cuerpo cuerpo no están haciedno su ataque, primero averigua y depsuees corrige
User prompt
Corrigelo porfa
User prompt
Los guerreros de fuego no esta atacando cuero a cuerpo no hacen el daño, deben atacar cuero a cuerpo y ahcer el daño
User prompt
los muros los invocan 300 uidades mas adelante
User prompt
Generame la iamgen del muro, este actuara como un solidoq eu eimpide a los enemgiso pero no a los aliados
User prompt
Earth Warrior; Vida 20 – Daño 1 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120 Earth Warrior2; Vida 40 – Daño 4 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120 Earth Warrior3; Vida 50 – Daño 6 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120, Crea muros, de 10 de vida Earth Warrior4; Vida 80– Daño 8 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120, crea muros, de 20 de vida, y es inmune al daño si es inferior o igual a 10 Earth Warrior5; Vida 100 – Daño 10 – Velocidad 1.8 – Alcance 200– Velocidad de Ataque 120, arrastra a los enemigos para atrás y cuando esta muy cerca de la torre, se destruye y se vuelve un muro de 250 de vida. Cada segundo de arrastre genera el daño base Los muros se cren asi se coge una distancia inicial de 0 a 200 y luego cada 200 de distancia se genera un muro.
User prompt
las montañas son tilegraground
User prompt
Entonces sera 3 capas, capa fondo, donde esta el cielo 100% Capa de fondo_50, sera donde pongamos montañas lejanas con 50% capa fondo_25, sera donde pongamos montañas ya arboles mediamente cercana 25% capa de articulos_fodno, sera detras de las torres y los personajes, pero encima de la tierra, posicionada en la parte superior de la aimagen, habran arboles, arbsutsos y flores, rocas 100% capa fondo superior, sera donde pongamos unos arbustos, flores, rocas etc, en la parte inferior del piso de la iamgen 100%
User prompt
Pero que esta varriable sea idepedietne por cada guerrero
User prompt
activala si no tienen enemigos al frente dentro de su rango de ataque si es cuero a cuerpo a distancia, y si estan dentro desactivala
User prompt
crea un varaible movimiento, si esta desactiva no se pueden mover y si estan activan se meuven por la por defecto en false
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ElementalNote = Container.expand(function (element, x, y) {
var self = Container.call(this);
var noteGraphics = self.attachAsset(element + 'Note', {
anchorX: 0.5,
anchorY: 0.5
});
self.element = element;
self.x = x;
self.y = y;
var label = new Text2(element.toUpperCase(), {
size: 30,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
self.isDisabled = false;
self.down = function (x, y, obj) {
// Check if button is disabled
if (self.isDisabled) {
return;
}
// Disable button
self.isDisabled = true;
notePressed(self.element);
// Play sound effect with controlled volume when pressed directly
// Access current global soundValue instead of captured value
var currentSoundValue = typeof soundValue !== 'undefined' ? soundValue : 0.8;
if (self.element === 'fire') {
var fireSound = LK.getSound('Nota_Fire');
fireSound.volume = currentSoundValue * 0.5;
fireSound.play();
} else if (self.element === 'water') {
var waterSound = LK.getSound('Nota_Water');
waterSound.volume = currentSoundValue;
waterSound.play();
} else if (self.element === 'earth') {
var earthSound = LK.getSound('Nota_Earth');
earthSound.volume = currentSoundValue;
earthSound.play();
} else if (self.element === 'wind') {
var windSound = LK.getSound('Nota_Wind');
windSound.volume = currentSoundValue;
windSound.play();
} else if (self.element === 'light') {
var lightSound = LK.getSound('Nota_Light');
lightSound.volume = currentSoundValue;
lightSound.play();
} else {
var summonSound = LK.getSound('summon');
summonSound.volume = currentSoundValue;
summonSound.play();
}
// Visual feedback - make smaller on press and change to green
tween(noteGraphics, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0x00ff00
}, {
duration: 100,
onFinish: function onFinish() {
// Return to normal size and restore color quickly
tween(noteGraphics, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
// Only re-enable button if we have enough mana and haven't reached limit
LK.setTimeout(function () {
// Check if we still have enough mana and haven't reached the counter limit
if (temporaryNoteCounter < currentMana) {
self.isDisabled = false;
}
}, 0); // Re-enable conditionally after color animation
}
});
}
});
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyUnit', {
anchorX: 0.5,
anchorY: 0.5,
width: 280,
height: 280
});
self.health = 80;
self.maxHealth = 80;
self.damage = 1;
self.speed = 1.5;
self.aumento_velocidad = 0;
self.attackCooldown = 0;
// Physics properties
self.velocityY = 0;
self.onGround = false;
self.gravity = 0.5;
// Beat effect properties
self.baseY = 0;
self.beatEffectTimer = 0;
// Health bar
var healthBar = LK.getAsset('healthBar', {
width: 100,
height: 12
});
healthBar.anchor.set(0.5, 0.5);
healthBar.y = -80;
self.addChild(healthBar);
self.healthBar = healthBar;
// Stats text below enemy
var statsText = new Text2('', {
size: 48,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
statsText.anchor.set(0.5, 0.5);
statsText.y = 120; // Position below the enemy
self.addChild(statsText);
self.statsText = statsText;
// Initialize miniola_colision property
self.miniola_colision = false;
// Function to update stats display
self.updateStatsDisplay = function () {
var totalSpeed = self.speed + self.aumento_velocidad;
var statsString = self.health + '-' + self.damage + '-' + totalSpeed;
self.statsText.setText(statsString);
};
// Initialize stats display
self.updateStatsDisplay();
self.update = function () {
// Set base Y position for beat effect
if (self.baseY === 0) {
self.baseY = 2186; // Ground level
}
// Apply beat effect if active
if (self.beatEffectTimer > 0) {
self.beatEffectTimer--;
// Get current audio level and calculate rotation strength based on sensitivity difference
var audioLevel = getGameMusicLevel();
var sensitivityDifference = Math.max(0, audioLevel - musicBeatThreshold);
if (sensitivityDifference > 0) {
var rotationAmount = Math.sin((120 - self.beatEffectTimer) * 0.3) * sensitivityDifference * 0.785;
enemyGraphics.rotation = rotationAmount;
} else {
enemyGraphics.rotation = 0; // No rotation when no difference
}
} else {
enemyGraphics.rotation = 0; // Reset rotation when effect ends
// Apply gravity
if (!self.onGround) {
self.velocityY += self.gravity;
self.y += self.velocityY;
}
// Ground collision
var groundY = 2186;
if (self.y >= groundY) {
self.y = groundY;
self.baseY = groundY; // Update base position
self.velocityY = 0;
self.onGround = true;
} else {
self.onGround = false;
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Move towards player tower (speed is controlled by combat state)
var totalSpeed = self.speed + self.aumento_velocidad;
self.x -= totalSpeed;
// Check for warriors to attack and combat engagement
var inCombat = false;
for (var i = 0; i < warriors.length; i++) {
var warrior = warriors[i];
// Use half width for enemy and warrior colliders but keep full height
var enemyColliderWidth = 280 * 0.5; // Half of enemy width
var warriorColliderWidth = 288 * 0.5; // Half of warrior width
var distance = Math.sqrt(Math.pow(self.x - warrior.x, 2) + Math.pow(self.y - warrior.y, 2));
if (distance < 250) {
// Mark as in combat to stop movement
inCombat = true;
if (self.attackCooldown <= 0) {
self.attack(warrior);
// Play combat sound when fighting with warrior
playRandomCombatSound();
// Attack animation - flash red and scale up
tween(enemyGraphics, {
tint: 0xff0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xffffff,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
}
break;
}
}
// Check if enemy is at the tower x position - stop movement to focus on tower attack
var atTowerPosition = Math.abs(self.x - enemyTower.x) <= 50;
// Stop movement if in combat or at tower position, otherwise resume normal movement
if (inCombat || atTowerPosition) {
self.speed = 0;
} else {
self.speed = 1.5;
}
// Check collision with player tower and destroy enemy - use half width for enemy collider
var towerColliderRadius = 700; // Fixed collider size, not scaled with tower
var enemyColliderWidth = 280 * 0.5; // Half of enemy width
var enemyColliderHeight = 280; // Full enemy height
var towerDistance = Math.sqrt(Math.pow(self.x - playerTower.x, 2) + Math.pow(self.y - playerTower.y, 2));
if (towerDistance < towerColliderRadius) {
if (self.attackCooldown <= 0) {
self.attackPlayerTower();
}
// Destroy enemy when it touches the tower
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
}
// Check if enemy is off-screen and destroy
if (self.x < -500 || self.x > 4500 || self.y > 3500) {
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
return; // Exit update to prevent further execution
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent;
};
self.attack = function (target) {
self.attackCooldown = 80;
if (target === playerTower) {
self.attackPlayerTower();
} else {
target.takeDamage(self.damage);
}
};
self.attackPlayerTower = function () {
self.attackCooldown = 80;
playerTowerHealth -= self.damage;
// Play random tower damage sound
var towerSounds = ['sonido_torre_1', 'sonido_torre_2', 'sonido_torre_3', 'sonido_torre_4'];
var randomIndex = Math.floor(Math.random() * towerSounds.length);
var sound = LK.getSound(towerSounds[randomIndex]);
sound.volume = soundValue;
sound.play();
// Create escombros particles when tower takes damage - quantity based on damage
var particleCount = self.damage * 12; // Multiply particle count by damage
for (var escombrosIndex = 0; escombrosIndex < particleCount; escombrosIndex++) {
// 360-degree explosion pattern
var angle = escombrosIndex / particleCount * Math.PI * 2; // Distribute evenly in 360 degrees
var force = (200 + Math.random() * 300) * 4; // Quadruple the force
var velocityX = Math.cos(angle) * force;
var velocityY = Math.sin(angle) * force;
var escombrosParticle = game.addChild(LK.getAsset('escombro_torre_jugador', {
anchorX: 0.5,
anchorY: 0.5,
x: playerTower.x,
y: playerTower.y - 800,
width: (60 + Math.random() * 40) * 5,
height: (60 + Math.random() * 40) * 5,
rotation: Math.random() * Math.PI * 2
}));
escombrosParticle.alpha = 0.9;
escombrosParticle.tint = 0x8B4513; // Brown color for debris
// Add gravity and physics properties
escombrosParticle.velocityX = velocityX * 0.02; // Scale down for smooth movement
escombrosParticle.velocityY = velocityY * 0.02;
escombrosParticle.gravity = 0.8; // Gravity effect
// Animate escombros particles with physics
tween(escombrosParticle, {
y: playerTower.y + 200 + escombrosParticle.velocityY * 100,
x: playerTower.x + escombrosParticle.velocityX * 100,
alpha: 0,
rotation: escombrosParticle.rotation + Math.PI * 4,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
escombrosParticle.destroy();
}
});
}
if (playerTowerHealth <= 0) {
LK.showGameOver();
}
updateTowerHealthBars();
};
self.takeBurnDamage = function (initialDamage, duration, burnDamage) {
// Apply initial damage
self.takeDamage(initialDamage);
// Don't apply burn if enemy is already dead
if (self.health <= 0) return;
// Start burn sound loop - store sound instance for stopping later
var burnSound = LK.getSound('burn_sound');
burnSound.volume = soundValue * 0.8;
self.burnSoundInstance = burnSound;
burnSound.play();
// Set up sound looping
var soundLoopTimer = LK.setInterval(function () {
if (self.health > 0 && self.burnSoundInstance) {
self.burnSoundInstance.play();
}
}, 1000); // Loop every second
// Add red tint at 80% opacity when burned
tween(enemyGraphics, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
// Keep 80% red tint during burn
var redTint = 0xff3333; // 80% red color
tween(enemyGraphics, {
tint: redTint
}, {
duration: 100
});
}
});
// Apply burn effect over time
var burnTicks = duration / 1000 * 60; // Convert duration to ticks (60fps)
var burnInterval = 60; // Damage every second
var ticksPerBurn = 0;
var _burnEffect = function burnEffect() {
ticksPerBurn++;
if (ticksPerBurn >= burnInterval) {
if (self.health > 0) {
self.takeDamage(burnDamage);
// Visual burn effect
tween(self.children[0], {
tint: 0xff4400
}, {
duration: 200,
onFinish: function onFinish() {
tween(self.children[0], {
tint: 0xff3333
}, {
duration: 200
});
}
});
}
ticksPerBurn = 0;
burnTicks -= burnInterval;
}
if (burnTicks > 0 && self.health > 0) {
LK.setTimeout(_burnEffect, 16); // ~60fps
} else {
// Burn effect ended, stop sound loop and restore normal color
LK.clearInterval(soundLoopTimer);
self.burnSoundInstance = null;
tween(enemyGraphics, {
tint: 0xffffff
}, {
duration: 500
});
}
};
_burnEffect();
};
self.takeDamage = function (damage) {
self.health -= damage;
// Update stats display to show current health
self.updateStatsDisplay();
if (self.health <= 0) {
// Play enemy death sound
var sound = LK.getSound('enemy_death');
sound.volume = soundValue;
sound.play();
// Death animation - fade out and scale down
tween(enemyGraphics, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
LK.setScore(LK.getScore() + 10);
scoreText.setText('Score: ' + LK.getScore());
// 50% chance to drop mana if not at max capacity
if (Math.random() < 0.5 && currentMana < maxMana) {
// Create mana drop at enemy position
var manaDrop = game.addChild(LK.getAsset('manaOrb', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
}));
// Visual effect - pulsing and floating up
tween(manaDrop, {
scaleX: 3.0,
scaleY: 3.0,
y: self.y - 100
}, {
duration: 800,
easing: tween.easeOut
});
// Add mana after short delay and destroy drop
LK.setTimeout(function () {
currentMana = Math.min(currentMana + 1, maxMana);
updateManaDisplay();
// Flash effect on collection
tween(manaDrop, {
alpha: 0,
scaleX: 4,
scaleY: 4
}, {
duration: 300,
onFinish: function onFinish() {
manaDrop.destroy();
}
});
}, 600);
}
}
};
return self;
});
var Meteorito = Container.expand(function () {
var self = Container.call(this);
var meteoritoGraphics = self.attachAsset('meteorito_elemental', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6.0,
scaleY: 6.0
});
self.speed = 20;
self.rotationSpeed = 0.1;
// Store the base scale to prevent shrinking
self.baseScale = 6.0;
// Rainbow cycling effect for mixed element meteorite
meteoritoGraphics.tint = 0xffffff;
// Add rainbow cycling animation
var rainbowColors = [0xff4400, 0x1e90ff, 0x8b4513, 0x44ff44, 0xffff00];
var colorIndex = 0;
var colorTimer = 0;
self.updateRainbow = function () {
colorTimer++;
if (colorTimer >= 10) {
// Change color every 10 frames
colorTimer = 0;
colorIndex = (colorIndex + 1) % rainbowColors.length;
meteoritoGraphics.tint = rainbowColors[colorIndex];
}
};
// Meteorite maintains full opacity (no alpha animation)
meteoritoGraphics.alpha = 1.0;
self.update = function () {
// Calculate target position (center of map at ground level)
var targetX = 1920; // Center of the game map (3840/2)
var targetY = 2186; // Ground level
// Calculate direction vector toward target
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Move diagonally toward target - double speed
if (distance > self.speed) {
// Normalize direction and apply double speed
var directionX = deltaX / distance;
var directionY = deltaY / distance;
self.x += directionX * self.speed;
self.y += directionY * self.speed;
} else {
// Reached target position - explode
self.explode();
return;
}
// Update rainbow effect
self.updateRainbow();
// Remove if off-screen
if (self.y > 3000) {
self.destroy();
var index = meteoritos.indexOf(self);
if (index > -1) {
meteoritos.splice(index, 1);
}
}
};
self.explode = function () {
// Generate random color for explosion
var randomColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff, 0xff8000, 0x8000ff, 0x80ff00, 0xff0080];
var explosionColor = randomColors[Math.floor(Math.random() * randomColors.length)];
// Create explosion effect
var explosion = game.addChild(LK.getAsset('explosion_fuego', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
width: 400,
height: 400
}));
explosion.tint = explosionColor;
explosion.alpha = 0.9;
// Animate massive explosion with enormous scale
tween(explosion, {
scaleX: 40.0,
scaleY: 40.0,
alpha: 0
}, {
duration: 2500,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Create massive particle explosion
for (var i = 0; i < 64; i++) {
var angle = i / 64 * Math.PI * 2;
var distance = 1600 + Math.random() * 2400;
var particleEndX = self.x + Math.cos(angle) * distance;
var particleEndY = self.y + Math.sin(angle) * distance;
// Generate random color for each particle
var particleColor = randomColors[Math.floor(Math.random() * randomColors.length)];
var particle = game.addChild(LK.getAsset('explosion_fuego', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
width: 240 + Math.random() * 360,
height: 240 + Math.random() * 360
}));
particle.tint = particleColor;
particle.alpha = 0.9;
tween(particle, {
x: particleEndX,
y: particleEndY,
alpha: 0,
scaleX: 0.05,
scaleY: 0.05
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Hide apocalyptic notes and reset counter when meteorite explodes (before explosion starts)
ocultar_notas_apocalitica();
// Deal massive damage to all enemies on the map
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
enemy.takeDamage(1000000000000000000); // Deal 1 quintillion damage to guarantee destruction
}
// Show message
showCombinationMessage('¡METEORITO ELEMENTAL - DEVASTACIÓN TOTAL!');
// Flash screen effect with longer duration for massive impact
LK.effects.flashScreen(explosionColor, 2000);
// Clear element list first, then call function to create new random meteorite combination
elementList = [];
// Play the meteorite melody instantly when exploding
playMelodySequenceWithIntervals(['fire', 'water', 'earth', 'wind', 'light'], [0, 200, 200, 200, 200]);
crea_combinacion_meteorito();
// Remove meteorite
self.destroy();
var index = meteoritos.indexOf(self);
if (index > -1) {
meteoritos.splice(index, 1);
}
};
return self;
});
var Nube = Container.expand(function () {
var self = Container.call(this);
// Create cloud with random uniform scale to maintain proportions
var uniformScale = 0.5 + Math.random() * 1.5; // Random scale between 50% and 200%
var cloudGraphics = self.attachAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: uniformScale,
scaleY: uniformScale,
alpha: 0.4 + Math.random() * 0.5 // Random opacity between 40% and 90%
});
// Set cloud to white/light gray color
cloudGraphics.tint = 0xF0F0F0;
// Random cloud speed (slower clouds for depth) - will be adjusted by height layer
self.speed = 0.5 + Math.random() * 1.0; // Speed between 0.5 and 1.5
// Adjust speed based on scale to simulate depth (smaller clouds move slower)
self.baseSpeed = self.speed;
// Store initial Y for floating animation
self.initialY = 0; // Will be set when cloud is positioned
// Method to start floating animation after positioning
self.startFloating = function () {
if (self.initialY === 0) {
self.initialY = self.y; // Store the manually set position
}
var floatAmount = 20 + Math.random() * 30;
var floatDuration = 3000 + Math.random() * 2000;
tween(self, {
y: self.initialY + floatAmount
}, {
duration: floatDuration,
yoyo: true,
repeat: -1,
easing: tween.easeInOut
});
};
self.update = function () {
// Adjust speed based on scale for depth effect (smaller = slower, further away)
self.speed = self.baseSpeed * (self.scaleX * 0.7 + 0.3); // Scale speed between 30% and 100%
// Move cloud to the right
self.x += self.speed;
// Remove clouds that have moved off-screen to the right
if (self.x > 4000 + cloudGraphics.width) {
self.destroy();
var index = clouds.indexOf(self);
if (index > -1) {
clouds.splice(index, 1);
}
}
};
return self;
});
var Warrior = Container.expand(function (element, tier) {
var self = Container.call(this);
var assetName = element + 'Warrior_nivel_' + tier;
var warriorGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
width: 288,
height: 288
});
self.element = element;
self.tier = tier;
// Base stats - same as enemies
var baseDamage = 1;
var baseHealth = 5;
// Set elemental-specific stats based on tier
if (element === 'fire') {
if (tier === 1) {
self.maxHealth = 5;
self.damage = 6;
self.speed = 2.2;
self.attackCooldown = 100;
} else if (tier === 2) {
self.maxHealth = 10;
self.damage = 6;
self.speed = 2.4;
self.attackCooldown = 50;
} else if (tier === 3) {
self.maxHealth = 15;
self.damage = 18;
self.speed = 2.6;
self.attackCooldown = 100;
self.burnDuration = 3000; // 3 seconds
self.burnDamage = 6;
self.canBurn = true;
} else if (tier === 4) {
self.maxHealth = 20;
self.damage = 24;
self.speed = 2.8;
self.attackCooldown = 60;
self.canAreaDamage = true;
self.areaRange = 400;
self.burnDuration = 5000; // 5 seconds
self.burnDamage = 8;
self.canBurn = true;
} else if (tier === 5) {
self.maxHealth = 25;
self.damage = 50;
self.speed = 3.0;
self.attackCooldown = 60;
self.canActivateFireMode = true;
self.fireModeActive = false;
}
} else if (element === 'water') {
if (tier === 1) {
self.maxHealth = 5;
self.damage = 1;
self.speed = 1.8;
self.attackCooldown = 120;
} else if (tier === 2) {
self.maxHealth = 10;
self.damage = 2;
self.speed = 2.0;
self.attackCooldown = 120;
self.selfHealRate = 2; // Heals 2 HP per second
self.selfHealTimer = 0;
} else if (tier === 3) {
self.maxHealth = 15;
self.damage = 4;
self.speed = 2.2;
self.attackCooldown = 120;
self.selfHealRate = 3.5; // Heals 3.5 HP per second
self.selfHealTimer = 0;
self.auraRange = 500;
self.auraDamageBonus = 4;
self.explosionTimer = 0;
self.explosionInterval = 120; // Every 2 seconds
} else if (tier === 4) {
self.maxHealth = 20;
self.damage = 6;
self.speed = 2.4;
self.attackCooldown = 120;
self.selfHealRate = 4; // Heals 4 HP per second
self.selfHealTimer = 0;
self.selfHealRate = 5; // Heals 5 HP per second
self.selfHealTimer = 0;
self.auraRange = 800;
self.auraDamageBonus = 10;
self.explosionTimer = 0;
self.explosionInterval = 120; // Every 2 seconds
} else if (tier === 5) {
self.maxHealth = 25;
self.damage = 8;
self.speed = 2.5;
self.attackCooldown = 120;
self.selfHealRate = 5; // Heals 5 HP per second
self.selfHealTimer = 0;
self.waveTimer = 0;
self.waveInterval = 300; // Every 5 seconds
}
self.canHeal = true;
self.healCooldown = 0;
self.isRanged = true;
self.projectiles = [];
} else if (element === 'earth') {
self.maxHealth = baseHealth + 50; // +50 health bonus
self.damage = baseDamage;
self.speed = 1.5;
} else if (element === 'light') {
self.maxHealth = baseHealth;
self.damage = baseDamage;
self.speed = 2.5;
self.isRanged = true;
self.canAreaDamage = true;
self.projectiles = [];
} else if (element === 'wind') {
self.maxHealth = baseHealth;
self.damage = baseDamage;
self.speed = 2.8;
self.isFlying = true;
self.isRanged = true;
self.projectiles = [];
} else {
// Default stats for any other element
self.maxHealth = baseHealth;
self.damage = baseDamage;
self.speed = 2;
}
self.health = self.maxHealth;
self.aumento_velocidad = 0;
// Attack cooldown will be set by elemental stats above
if (!self.attackCooldown) {
self.attackCooldown = 0; // Default fallback
}
self.baseCooldown = self.attackCooldown || 60; // Store base cooldown for resets
self.target = null;
self.isBeingDestroyed = false; // Flag to prevent multiple destruction attempts
self.activar_movimiento = true; // Boolean to control if warrior can move
// Physics properties
self.velocityY = 0;
self.onGround = false;
self.gravity = 0.5;
// Beat effect properties
self.baseY = 0;
self.beatEffectTimer = 0;
// Set warrior size based on tier level - using scale multipliers for visible differences
var tierScale = 1.0; // Base scale for tier 1
if (tier === 1) {
tierScale = 1.0; // Tier 1: normal size (288px)
} else if (tier === 2) {
tierScale = 1.17; // Tier 2: 17% bigger (338px)
} else if (tier === 3) {
tierScale = 1.35; // Tier 3: 35% bigger (388px)
} else if (tier === 4) {
tierScale = 1.52; // Tier 4: 52% bigger (438px)
} else if (tier === 5) {
tierScale = 1.69; // Tier 5: 69% bigger (488px)
}
// Store the tier scale for later reference
self.tierScale = tierScale;
// Apply tier-based scaling immediately and permanently
warriorGraphics.scaleX = tierScale;
warriorGraphics.scaleY = tierScale;
// Apply a simple bounce effect that preserves the tier scale
var bounceScale = tierScale * 1.1;
tween(warriorGraphics, {
scaleX: bounceScale,
scaleY: bounceScale
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Ensure we return to the exact tier scale, not a reference that might change
tween(warriorGraphics, {
scaleX: self.tierScale,
scaleY: self.tierScale
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
// Health bar
var healthBar = LK.getAsset('warriorHealthBar', {
width: 120,
height: 16
});
healthBar.anchor.set(0.5, 0.5);
healthBar.y = -100;
self.addChild(healthBar);
self.healthBar = healthBar;
// Stats text below warrior
var statsText = new Text2('', {
size: 48,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
statsText.anchor.set(0.5, 0.5);
statsText.y = 120; // Position below the warrior
self.addChild(statsText);
self.statsText = statsText;
// Function to update stats display
self.updateStatsDisplay = function () {
var attackSpeed = self.baseCooldown || 60;
var range = self.isRanged ? self.element === 'wind' ? 600 : 600 : 250;
var totalSpeed = self.speed + (self.aumento_velocidad || 0);
var auraInfo = '';
if (self.waterAuraCount && self.waterAuraCount > 0) {
var speedReduction = self.waterAuraCount * 10;
auraInfo = ' [Aura:' + speedReduction + '%]';
}
var statsString = self.health + '-' + self.damage + '-' + totalSpeed + '-' + range + '-' + attackSpeed + auraInfo;
self.statsText.setText(statsString);
};
// Initialize stats display
self.updateStatsDisplay();
self.update = function () {
// Set base Y position for beat effect
if (self.baseY === 0) {
if (self.isFlying) {
self.baseY = 1800; // Flying height
} else {
self.baseY = 2186; // Ground level
}
}
// Apply beat effect if active
if (self.beatEffectTimer > 0) {
self.beatEffectTimer--;
// Get current audio level and calculate rotation strength based on sensitivity difference
var audioLevel = getGameMusicLevel();
var sensitivityDifference = Math.max(0, audioLevel - musicBeatThreshold);
if (sensitivityDifference > 0) {
var rotationAmount = Math.sin((120 - self.beatEffectTimer) * 0.3) * sensitivityDifference * 0.785;
warriorGraphics.rotation = rotationAmount;
} else {
warriorGraphics.rotation = 0; // No rotation when no difference
}
} else {
warriorGraphics.rotation = 0; // Reset rotation when effect ends
// Apply gravity only to non-flying units
if (!self.isFlying && !self.onGround) {
self.velocityY += self.gravity;
self.y += self.velocityY;
}
// Ground collision for non-flying units
var groundY = 2186;
if (!self.isFlying && self.y >= groundY) {
self.y = groundY;
self.baseY = groundY; // Update base position
self.velocityY = 0;
self.onGround = true;
} else if (!self.isFlying) {
self.onGround = false;
}
// Flying units hover at a specific height
if (self.isFlying) {
self.y = 1800; // Fly above ground level
self.baseY = 1800; // Update base position
}
}
// Move towards enemy tower only if movement is enabled
if (!self.target && self.activar_movimiento) {
var totalSpeed = self.speed + (self.aumento_velocidad || 0);
self.x += totalSpeed;
}
// Attack logic
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Update heal cooldown for water warriors
if (self.canHeal && self.healCooldown > 0) {
self.healCooldown--;
}
// Water warrior self-healing (tier 2+)
if (self.element === 'water' && self.tier >= 2 && self.selfHealTimer !== undefined) {
self.selfHealTimer++;
if (self.selfHealTimer >= 60) {
// Every second (60 frames at 60fps)
if (self.health < self.maxHealth) {
self.health = Math.min(self.health + self.selfHealRate, self.maxHealth);
// Self-healing visual effect
tween(warriorGraphics, {
tint: 0x00ff00
}, {
duration: 300,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff
}, {
duration: 300
});
}
});
// Add healing particles for tier 2 water warrior self-healing
if (self.tier === 2) {
for (var p = 0; p < 6; p++) {
var particle = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + (Math.random() - 0.5) * 80,
y: self.y + (Math.random() - 0.5) * 80,
width: 120 + Math.random() * 80,
height: 120 + Math.random() * 80
}));
particle.alpha = 0.8;
tween(particle, {
y: self.y - 100 - Math.random() * 50,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
}
self.selfHealTimer = 0;
}
}
// Water warrior aura effects (tier 3+)
if (self.element === 'water' && self.tier >= 3 && self.auraRange !== undefined) {
// Apply aura damage bonus and attack speed reduction to nearby allies
for (var j = 0; j < warriors.length; j++) {
var ally = warriors[j];
if (ally !== self && ally.element !== 'water') {
var allyDistance = Math.sqrt(Math.pow(self.x - ally.x, 2) + Math.pow(self.y - ally.y, 2));
if (allyDistance < self.auraRange) {
// Count number of water tier 3+ warriors affecting this ally
var waterAuraCount = 0;
for (var k = 0; k < warriors.length; k++) {
var waterWarrior = warriors[k];
if (waterWarrior.element === 'water' && waterWarrior.tier >= 3) {
var waterDistance = Math.sqrt(Math.pow(waterWarrior.x - ally.x, 2) + Math.pow(waterWarrior.y - ally.y, 2));
if (waterDistance < waterWarrior.auraRange) {
waterAuraCount++;
}
}
}
// Only apply speed changes if aura count has changed
var previousAuraCount = ally.waterAuraCount || 0;
if (waterAuraCount !== previousAuraCount) {
// Initialize originalBaseCooldown if not set
if (!ally.originalBaseCooldown) {
ally.originalBaseCooldown = ally.baseCooldown || 60;
}
// Calculate cumulative speed reduction: each aura reduces by 10%
var speedReduction = waterAuraCount * 10; // 10% per aura
var finalSpeedMultiplier = Math.max(0.1, (100 - speedReduction) / 100); // Minimum 0.1 (10% attack speed)
// Apply the speed reduction to original base cooldown (multiply to reduce cooldown = attack faster)
ally.baseCooldown = Math.floor(ally.originalBaseCooldown * finalSpeedMultiplier);
ally.waterAuraCount = waterAuraCount;
ally.auraAffected = waterAuraCount > 0;
ally.auraDamageBonus = waterAuraCount > 0 ? self.auraDamageBonus : 0;
} else {
// Keep existing values without recalculation
ally.waterAuraCount = waterAuraCount;
ally.auraAffected = waterAuraCount > 0;
ally.auraDamageBonus = waterAuraCount > 0 ? self.auraDamageBonus : 0;
}
// Create continuous particles for allies under aura effect (without tinting)
if (waterAuraCount > 0) {
// Create continuous particles (7.5x larger)
if (LK.ticks % 30 === 0) {
// Every 0.5 seconds
for (var p = 0; p < 3; p++) {
var particle = game.addChild(LK.getAsset('particulas_delfin', {
anchorX: 0.5,
anchorY: 0.5,
x: ally.x + (Math.random() - 0.5) * 80,
y: ally.y + (Math.random() - 0.5) * 80,
width: (30 + Math.random() * 15) * 7.5,
height: (30 + Math.random() * 15) * 7.5
}));
particle.alpha = 0.8;
particle.tint = 0xff22aa; // More intense pink color for dolphin particles
tween(particle, {
y: ally.y - 100 - Math.random() * 40,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
}
// Visual feedback when aura count changes
if (previousAuraCount !== waterAuraCount && waterAuraCount > 0) {
// Blue glow effect when gaining aura
tween(ally.children[0], {
tint: 0x00aaff
}, {
duration: 300,
onFinish: function onFinish() {
tween(ally.children[0], {
tint: 0xffffff // Back to white instead of pink
}, {
duration: 300
});
}
});
// Create visual particles around affected ally
for (var p = 0; p < 4; p++) {
var particle = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: ally.x + (Math.random() - 0.5) * 60,
y: ally.y + (Math.random() - 0.5) * 60,
width: 40 + Math.random() * 20,
height: 40 + Math.random() * 20
}));
particle.alpha = 0.6;
particle.tint = 0x00aaff; // Blue for speed aura
tween(particle, {
y: ally.y - 80 - Math.random() * 30,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
}
}
}
}
// Water warrior explosion healing (tier 3+)
if (self.element === 'water' && self.tier >= 3 && self.explosionTimer !== undefined) {
self.explosionTimer++;
if (self.explosionTimer >= self.explosionInterval) {
// Every 2 seconds
// Create healing explosion at warrior position
var explosion = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
width: 400,
height: 400
}));
explosion.alpha = 0.7;
explosion.tint = 0x00aaff;
// Animate explosion
tween(explosion, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Heal all allies within 400 units
for (var j = 0; j < warriors.length; j++) {
var ally = warriors[j];
var healDistance = Math.sqrt(Math.pow(self.x - ally.x, 2) + Math.pow(self.y - ally.y, 2));
if (healDistance < 400) {
// Apply aura damage bonus to explosion healing amount
var finalHealAmount = self.damage + (self.auraDamageBonus || 0);
ally.health = Math.min(ally.health + finalHealAmount, ally.maxHealth);
// Healing particles for affected allies
for (var p = 0; p < 6; p++) {
var particle = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: ally.x + (Math.random() - 0.5) * 80,
y: ally.y + (Math.random() - 0.5) * 80,
width: 60 + Math.random() * 40,
height: 60 + Math.random() * 40
}));
particle.alpha = 0.8;
tween(particle, {
y: ally.y - 100 - Math.random() * 50,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
}
self.explosionTimer = 0;
}
}
// Water warrior healing wave (tier 5)
if (self.element === 'water' && self.tier === 5 && self.waveTimer !== undefined) {
self.waveTimer++;
if (self.waveTimer >= self.waveInterval) {
// Every 5 seconds
// Create healing wave from player tower to end of map
var wave = game.addChild(LK.getAsset('ola', {
anchorX: 0.0,
anchorY: 0.5,
x: playerTower.x,
y: playerTower.y - 200,
width: 800,
height: 1000
}));
wave.tint = 0x00ffff;
// Store wave damage for collision detection
wave.finalWaveDamage = self.damage + (self.auraDamageBonus || 0);
// Track which enemies have been hit by this wave
wave.hitEnemies = [];
// Add wave update method for collision detection
wave.update = function () {
// Check collision with enemies for damage
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
// Check if enemy hasn't been hit by this wave yet
if (wave.hitEnemies.indexOf(enemy) === -1) {
// Check collision between wave and enemy - use wave center for better detection
var waveCenterX = wave.x + wave.width * 0.5; // Center of wave
var waveCenterY = wave.y; // Center Y position
var waveDistance = Math.sqrt(Math.pow(waveCenterX - enemy.x, 2) + Math.pow(waveCenterY - enemy.y, 2));
if (waveDistance < 300) {
// Enemy is hit by wave - mark immediately to prevent multiple hits
wave.hitEnemies.push(enemy);
// Deal damage to enemy
enemy.takeDamage(wave.finalWaveDamage);
// Create explosion effect at impact
var explosion = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: enemy.x,
y: enemy.y,
width: 200,
height: 200
}));
explosion.alpha = 0.7;
explosion.tint = 0x00aaff;
// Animate explosion
tween(explosion, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
}
}
}
// Check collision with warriors for speed boost
for (var w = 0; w < warriors.length; w++) {
var warrior = warriors[w];
// Check if warrior hasn't been hit by this wave yet
if (wave.hitEnemies.indexOf(warrior) === -1) {
// Check collision between wave and warrior - use wave center for better detection
var waveCenterX = wave.x + wave.width * 0.5; // Center of wave
var waveDistance = Math.sqrt(Math.pow(waveCenterX - warrior.x, 2) + Math.pow(wave.y - warrior.y, 2));
if (waveDistance < 300) {
// Warrior is hit by wave
wave.hitEnemies.push(warrior);
// Increase speed only if not already boosted by tier 5 water warrior wave
if (!warrior.tier5WaveSpeedBoosted) {
warrior.aumento_velocidad = (warrior.aumento_velocidad || 0) + 2;
warrior.tier5WaveSpeedBoosted = true;
// Visual effect for speed boost
tween(warrior.children[0], {
tint: 0x00ffff
}, {
duration: 500,
onFinish: function onFinish() {
tween(warrior.children[0], {
tint: 0xffffff
}, {
duration: 500
});
}
});
warrior.updateStatsDisplay();
}
}
}
}
};
// Animate wave across the map
tween(wave, {
x: 4500,
// Move to end of map
scaleX: 2.0
}, {
duration: 3000,
easing: tween.linear,
onFinish: function onFinish() {
wave.destroy();
}
});
// Heal all allies to full health immediately
for (var j = 0; j < warriors.length; j++) {
warriors[j].health = warriors[j].maxHealth;
}
showCombinationMessage('¡TSUNAMI CURATIVO ACTIVADO!');
self.waveTimer = 0;
}
}
// Water warriors heal nearby allies
if (self.canHeal && self.healCooldown <= 0) {
self.healCooldown = 120; // 2 seconds
// Heal nearby warriors
for (var j = 0; j < warriors.length; j++) {
var ally = warriors[j];
if (ally !== self) {
var allyDistance = Math.sqrt(Math.pow(self.x - ally.x, 2) + Math.pow(self.y - ally.y, 2));
if (allyDistance < 600 && ally.health < ally.maxHealth) {
// Apply aura damage bonus to healing amount
var finalHealAmount = self.damage + (self.auraDamageBonus || 0);
ally.health = Math.min(ally.health + finalHealAmount, ally.maxHealth);
// Healing effect
tween(ally.children[0], {
tint: 0x00ff88
}, {
duration: 200,
onFinish: function onFinish() {
tween(ally.children[0], {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Create healing particles
for (var particleIndex = 0; particleIndex < 8; particleIndex++) {
var particle = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: ally.x + (Math.random() - 0.5) * 100,
y: ally.y + (Math.random() - 0.5) * 100,
width: 140 + Math.random() * 100,
height: 140 + Math.random() * 100
}));
particle.alpha = 0.8;
// Animate particles upward and fade out
tween(particle, {
y: ally.y - 150 - Math.random() * 50,
x: ally.x + (Math.random() - 0.5) * 200,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
}
}
}
// Check for enemies to attack and combat engagement
var inCombat = false;
var attackRange = self.isRanged ? 600 : 250;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
// Use half width for warrior and enemy colliders but keep full height
var warriorColliderWidth = 288 * 0.5; // Half of warrior width
var enemyColliderWidth = 280 * 0.5; // Half of enemy width
var distance = Math.sqrt(Math.pow(self.x - enemy.x, 2) + Math.pow(self.y - enemy.y, 2));
if (distance < attackRange) {
// Mark as in combat to stop movement for all ranged units including water warriors
inCombat = true;
// Attack logic based on warrior type
if (self.attackCooldown <= 0) {
if (self.element === 'water') {
// Water warriors only do ranged attacks
if (self.isRanged) {
self.attack(enemy);
// Attack animation - flash blue and scale up while preserving tier scale
var attackScale = self.tierScale * 1.4;
tween(warriorGraphics, {
tint: 0x00ffff,
scaleX: attackScale,
scaleY: attackScale
}, {
duration: 300,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
scaleX: self.tierScale,
scaleY: self.tierScale
}, {
duration: 300
});
}
});
}
} else if (self.isRanged) {
// Other ranged warriors (light, wind)
self.attack(enemy);
// Attack animation - flash blue and scale up while preserving tier scale
var attackScale = self.tierScale * 1.4;
tween(warriorGraphics, {
tint: 0x00ffff,
scaleX: attackScale,
scaleY: attackScale
}, {
duration: 300,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
scaleX: self.tierScale,
scaleY: self.tierScale
}, {
duration: 300
});
}
});
} else {
// Melee warriors (fire, earth) - attack directly
self.attack(enemy);
// Attack animation - flash red for fire warriors and scale up while preserving tier scale
var attackTint = self.element === 'fire' ? 0xff4400 : 0x8b4513; // Fire red or earth brown
var attackScale = self.tierScale * 1.4;
tween(warriorGraphics, {
tint: attackTint,
scaleX: attackScale,
scaleY: attackScale
}, {
duration: 300,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
scaleX: self.tierScale,
scaleY: self.tierScale
}, {
duration: 300
});
}
});
}
}
// Break out of loop for all ranged units except wind warriors to stop movement
if (self.isRanged && self.element !== 'wind') {
break;
} else if (!self.isRanged) {
break;
}
}
}
// Check if warrior is at the tower x position - stop movement to focus on tower attack
var atTowerPosition = Math.abs(self.x - playerTower.x) <= 50;
// Update projectiles for ranged units
if (self.isRanged) {
for (var p = self.projectiles.length - 1; p >= 0; p--) {
var proj = self.projectiles[p];
proj.x += proj.speedX;
proj.y += proj.speedY;
var projectileDestroyed = false;
// Water warrior projectiles can heal allies
if (self.element === 'water') {
// Check collision with allies first
for (var w = 0; w < warriors.length; w++) {
var ally = warriors[w];
if (ally !== self) {
// Use half width for ally collider but keep full height
var allyColliderWidth = 288 * 0.5; // Half of ally width
var allyDistance = Math.sqrt(Math.pow(proj.x - ally.x, 2) + Math.pow(proj.y - ally.y, 2));
if (allyDistance < 50) {
// Hit ally
if (ally.health < ally.maxHealth) {
// Heal ally if not at full health (heal amount equals water warrior's damage plus aura bonus)
var finalHealAmount = self.damage + (self.auraDamageBonus || 0);
ally.health = Math.min(ally.health + finalHealAmount, ally.maxHealth);
// Healing effect
tween(ally.children[0], {
tint: 0x00ff88
}, {
duration: 200,
onFinish: function onFinish() {
tween(ally.children[0], {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Create healing particles
for (var particleIndex = 0; particleIndex < 8; particleIndex++) {
var particle = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: ally.x + (Math.random() - 0.5) * 100,
y: ally.y + (Math.random() - 0.5) * 100,
width: 140 + Math.random() * 100,
height: 140 + Math.random() * 100
}));
particle.alpha = 0.8;
// Animate particles upward and fade out
tween(particle, {
y: ally.y - 150 - Math.random() * 50,
x: ally.x + (Math.random() - 0.5) * 200,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
proj.destroy();
self.projectiles.splice(p, 1);
projectileDestroyed = true;
break;
}
// If ally is at full health, projectile passes through
}
}
}
}
// Check collision with enemies only if projectile wasn't destroyed by healing
if (!projectileDestroyed) {
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
// Use half width for enemy collider but keep full height
var enemyColliderWidth = 280 * 0.5; // Half of enemy width
var projDistance = Math.sqrt(Math.pow(proj.x - enemy.x, 2) + Math.pow(proj.y - enemy.y, 2));
if (projDistance < 80) {
// Increased collision radius for better detection
// Hit enemy
if (self.canAreaDamage) {
// Create lightning explosion visual effect at projectile impact point
var explosion = game.addChild(LK.getAsset('efecto_electricidad', {
anchorX: 0.5,
anchorY: 0.5,
x: proj.x,
y: proj.y,
width: 80,
height: 80
}));
explosion.alpha = 0.9;
// Animate explosion - scale up and fade out
tween(explosion, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Create electric particles expanding from explosion center
for (var particleIndex = 0; particleIndex < 12; particleIndex++) {
var angle = particleIndex / 12 * Math.PI * 2; // Distribute evenly in circle
var distance = 150 + Math.random() * 100;
var particleEndX = proj.x + Math.cos(angle) * distance;
var particleEndY = proj.y + Math.sin(angle) * distance;
var electricParticle = game.addChild(LK.getAsset('efecto_electricidad', {
anchorX: 0.5,
anchorY: 0.5,
x: proj.x,
y: proj.y,
width: 20 + Math.random() * 20,
height: 20 + Math.random() * 20
}));
electricParticle.alpha = 0.8;
// Animate particles expanding outward and fading
tween(electricParticle, {
x: particleEndX,
y: particleEndY,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 300 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function onFinish() {
electricParticle.destroy();
}
});
}
// Lightning area damage - increased damage for area effect
for (var ae = 0; ae < enemies.length; ae++) {
var areaEnemy = enemies[ae];
var areaDistance = Math.sqrt(Math.pow(proj.x - areaEnemy.x, 2) + Math.pow(proj.y - areaEnemy.y, 2));
if (areaDistance < 600) {
areaEnemy.takeDamage(1); // Set damage to 1 for area effect
}
}
} else {
// Water warriors use base damage only for projectiles, no aura bonus
if (self.element === 'water') {
enemy.takeDamage(self.damage);
} else {
// Apply aura damage bonus if affected by water warrior aura
var finalDamage = self.damage + (self.auraDamageBonus || 0);
enemy.takeDamage(finalDamage);
}
}
proj.destroy();
self.projectiles.splice(p, 1);
projectileDestroyed = true;
break;
}
}
}
// Remove projectiles that go off screen only if not already destroyed
if (!projectileDestroyed && (proj.x > 4500 || proj.x < -500 || proj.y > 3500 || proj.y < -500)) {
proj.destroy();
self.projectiles.splice(p, 1);
}
}
}
// Set activar_movimiento based on combat state and element type
if (inCombat && self.element !== 'wind') {
// Stop movement for all elements except wind when in combat range
self.activar_movimiento = false;
} else if (!inCombat) {
// Allow movement when not in combat
self.activar_movimiento = true;
}
// Apply movement based on activar_movimiento flag
if (!self.activar_movimiento || atTowerPosition) {
self.speed = 0;
} else {
// Resume normal movement with base speed
var baseSpeed = 2;
if (self.element === 'fire') {
baseSpeed = 2.2;
} else if (self.element === 'water') {
baseSpeed = 1.8;
} else if (self.element === 'earth') {
baseSpeed = 1.5;
} else if (self.element === 'light') {
baseSpeed = 2.5;
} else if (self.element === 'wind') {
baseSpeed = 2.8;
}
self.speed = baseSpeed;
}
// Check collision with enemy tower - use separate x and y collision detection for flying units
var towerColliderRadius = 700; // Fixed collider size, not scaled with tower
var warriorColliderWidth = 288 * 0.5; // Half of warrior width
var warriorColliderHeight = 288; // Full warrior height
var towerDistance = Math.sqrt(Math.pow(self.x - enemyTower.x, 2) + Math.pow(self.y - enemyTower.y, 2));
var xDistance = Math.abs(self.x - enemyTower.x);
var yDistance = Math.abs(self.y - enemyTower.y);
// Debug collision for wind warriors
if (self.element === 'wind') {
collisionDebugText.setText('Wind Warrior - XDist: ' + Math.round(xDistance) + ' YDist: ' + Math.round(yDistance) + ' Pos: (' + Math.round(self.x) + ',' + Math.round(self.y) + ')');
}
// Use different collision detection for flying units vs ground units
var collisionDetected = false;
if (self.isFlying) {
// For flying units, use x-distance only (ignore y difference)
collisionDetected = xDistance < towerColliderRadius;
} else {
// For ground units, use traditional distance-based collision
collisionDetected = towerDistance < towerColliderRadius;
}
if (collisionDetected && !self.isBeingDestroyed) {
// Debug when collision happens
if (self.element === 'wind') {
collisionDebugText.setText('WIND COLLISION! XDist: ' + Math.round(xDistance) + ' Damage: ' + self.damage);
}
// Deal damage to tower first - always attack regardless of cooldown when touching tower
self.attackTower();
// Mark as being destroyed to prevent multiple collision detections
self.isBeingDestroyed = true;
// Remove from warriors array immediately
var index = warriors.indexOf(self);
if (index > -1) {
warriors.splice(index, 1);
}
// Warrior self-destructs when touching the tower - immediate destruction
self.destroy();
return; // Exit update to prevent further execution after destruction
}
// Check projectile collision with enemy tower for ranged units - tower is invulnerable to projectiles
if (self.isRanged) {
for (var p = self.projectiles.length - 1; p >= 0; p--) {
var proj = self.projectiles[p];
var projTowerDistance = Math.sqrt(Math.pow(proj.x - enemyTower.x, 2) + Math.pow(proj.y - enemyTower.y, 2));
if (projTowerDistance < 700) {
// Fixed collider radius
// Projectile hit the tower but tower is invulnerable - just destroy projectile
proj.destroy();
self.projectiles.splice(p, 1);
}
}
}
// Check if warrior is off-screen and destroy
if (self.x < -500 || self.x > 4500 || self.y > 3500) {
self.destroy();
var index = warriors.indexOf(self);
if (index > -1) {
warriors.splice(index, 1);
}
return; // Exit update to prevent further execution
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBar.scaleX = healthPercent;
self.healthBar.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
self.attack = function (target) {
self.attackCooldown = self.baseCooldown || 60; // Use tier-based cooldown
if (target === enemyTower) {
self.attackTower();
} else if (self.isRanged) {
// Special mini-wave attack for tier 4 water warriors
if (self.element === 'water' && self.tier === 4) {
// Create mini-wave that travels 800 units with larger size (same as tier 5)
var miniWave = game.addChild(LK.getAsset('ola', {
anchorX: 0.0,
anchorY: 0.5,
x: self.x - 400,
y: self.y,
width: 800,
height: 500
}));
miniWave.tint = 0x00ffff;
miniWave.alpha = 0.8;
// Store wave damage for collision detection
var finalWaveDamage = self.damage + (self.auraDamageBonus || 0);
miniWave.finalWaveDamage = finalWaveDamage;
// Track which enemies and allies have been hit by this wave
miniWave.hitEnemies = [];
miniWave.healedAllies = [];
// Add wave update method for collision detection
miniWave.update = function () {
// Check collision with enemies - only once per enemy per wave
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
// Check if enemy hasn't been hit by this specific wave yet
if (miniWave.hitEnemies.indexOf(enemy) === -1) {
// Check collision between wave and enemy - use thin collider positioned at center of image
var waveCenterX = miniWave.x + miniWave.width * 0.5; // Center of wave image
var waveCenterY = miniWave.y; // Center Y position
var waveDistance = Math.sqrt(Math.pow(waveCenterX - enemy.x, 2) + Math.pow(waveCenterY - enemy.y, 2));
if (waveDistance < 50) {
// Thin collision radius of 50 units for precise detection
// Enemy is hit by wave - mark immediately to prevent multiple hits
miniWave.hitEnemies.push(enemy);
// Always deal damage when hit by mini-wave - use base damage only (6)
enemy.takeDamage(6); // Fixed damage of 6 for mini-waves
// Set miniola_colision to true and update enemy stats
enemy.miniola_colision = true;
enemy.updateStatsDisplay();
// Set immunity timer for 1 second using setTimeout
LK.setTimeout(function () {
enemy.miniola_colision = false;
enemy.updateStatsDisplay();
}, 1000);
// Create explosion effect at impact
var explosion = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: enemy.x,
y: enemy.y,
width: 200,
height: 200
}));
explosion.alpha = 0.7;
explosion.tint = 0x00aaff;
// Animate explosion
tween(explosion, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
}
}
}
// Check collision with allies for healing
for (var w = 0; w < warriors.length; w++) {
var ally = warriors[w];
// Check if ally hasn't been healed by this wave yet
if (miniWave.healedAllies.indexOf(ally) === -1) {
// Check collision between wave and ally - use thin collider positioned at center of image
var waveCenterX = miniWave.x + miniWave.width * 0.5; // Center of wave image
var waveCenterY = miniWave.y; // Center Y position
var allyDistance = Math.sqrt(Math.pow(waveCenterX - ally.x, 2) + Math.pow(waveCenterY - ally.y, 2));
if (allyDistance < 50) {
// Thin collision radius of 50 units for precise detection
// Ally is healed by wave - mark immediately to prevent multiple heals
miniWave.healedAllies.push(ally);
// Heal ally if not at full health
if (ally.health < ally.maxHealth) {
// Heal for exactly 10 (6 base + 4 bonus)
ally.health = Math.min(ally.health + 10, ally.maxHealth);
// Healing effect
tween(ally.children[0], {
tint: 0x00ff88
}, {
duration: 200,
onFinish: function onFinish() {
tween(ally.children[0], {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Create healing particles
for (var particleIndex = 0; particleIndex < 6; particleIndex++) {
var particle = game.addChild(LK.getAsset('particulas_curacion', {
anchorX: 0.5,
anchorY: 0.5,
x: ally.x + (Math.random() - 0.5) * 80,
y: ally.y + (Math.random() - 0.5) * 80,
width: 80 + Math.random() * 40,
height: 80 + Math.random() * 40
}));
particle.alpha = 0.8;
tween(particle, {
y: ally.y - 100 - Math.random() * 50,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
}
}
}
};
// Animate wave across 800 units distance
tween(miniWave, {
x: self.x + 800,
scaleX: 1.5
}, {
duration: 1500,
easing: tween.linear,
onFinish: function onFinish() {
miniWave.destroy();
}
});
self.projectiles.push(miniWave);
// Play water projectile sound
playRandomProjectileSound(self.element);
return; // Exit after creating mini-wave
} else {
// Regular projectiles for other ranged units
var projectileSize = 120; // Larger projectiles for better visibility (doubled from 60)
var projectileAsset = self.element === 'light' ? 'proyectil_electricidad' : 'projectile';
var projectile = game.addChild(LK.getAsset(projectileAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y - 20,
// Start slightly above warrior
width: projectileSize,
height: projectileSize
}));
// Calculate direction to target
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var speed = 10; // Increased speed for better gameplay
projectile.speedX = dx / distance * speed;
projectile.speedY = dy / distance * speed;
// Set projectile appearance based on element
if (self.element === 'light') {
projectile.alpha = 0.9; // Slightly transparent for glow effect
// Add pulsing effect for lightning
tween(projectile, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
yoyo: true,
repeat: -1
});
} else if (self.element === 'wind') {
projectile.tint = 0x44ff44; // Green for wind
projectile.alpha = 0.8;
// Add spinning effect for wind
tween(projectile, {
rotation: Math.PI * 2
}, {
duration: 500,
repeat: -1
});
} else if (self.element === 'water') {
projectile.tint = 0x1e90ff; // Sea blue for water (DodgerBlue)
projectile.alpha = 0.85;
// Add wobbling effect for water
tween(projectile, {
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 200,
yoyo: true,
repeat: -1
});
}
self.projectiles.push(projectile);
// Auto-destroy projectile after 5 seconds to prevent map clutter
tween(projectile, {
alpha: projectile.alpha // Dummy property to track time
}, {
duration: 5000,
// 5 seconds
onFinish: function onFinish() {
// Find and remove projectile from array
var index = self.projectiles.indexOf(projectile);
if (index > -1) {
self.projectiles.splice(index, 1);
}
// Destroy the projectile
projectile.destroy();
}
});
// Play element-specific projectile sound
playRandomProjectileSound(self.element);
return; // Exit after creating projectile to prevent melee sound
}
} else {
// Melee combat - deal damage directly to target
var finalDamage = self.damage + (self.auraDamageBonus || 0);
target.takeDamage(finalDamage);
// Fire warriors with burn ability (tier 3+)
if (self.element === 'fire' && self.canBurn && target.takeBurnDamage) {
target.takeBurnDamage(0, self.burnDuration, self.burnDamage); // No initial damage since we already dealt damage above
}
// Fire tier 4 warriors have area damage with fire explosion visual effect
if (self.element === 'fire' && self.canAreaDamage) {
// Create fire explosion visual effect at target position
var explosion = game.addChild(LK.getAsset('explosion_fuego', {
anchorX: 0.5,
anchorY: 0.5,
x: target.x,
y: target.y,
width: 120,
height: 120
}));
explosion.alpha = 0.9;
explosion.tint = 0xff4400; // Fire color
// Animate explosion - scale up and fade out
tween(explosion, {
scaleX: 5.0,
scaleY: 5.0,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Create fire particles expanding from explosion center
for (var particleIndex = 0; particleIndex < 16; particleIndex++) {
var angle = particleIndex / 16 * Math.PI * 2; // Distribute evenly in circle
var distance = 200 + Math.random() * 150;
var particleEndX = target.x + Math.cos(angle) * distance;
var particleEndY = target.y + Math.sin(angle) * distance;
var fireParticle = game.addChild(LK.getAsset('explosion_fuego', {
anchorX: 0.5,
anchorY: 0.5,
x: target.x,
y: target.y,
width: 30 + Math.random() * 30,
height: 30 + Math.random() * 30
}));
fireParticle.alpha = 0.7;
fireParticle.tint = 0xff6600; // Orange fire color
// Animate particles expanding outward and fading
tween(fireParticle, {
x: particleEndX,
y: particleEndY,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 600 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
fireParticle.destroy();
}
});
}
for (var ae = 0; ae < enemies.length; ae++) {
var areaEnemy = enemies[ae];
var areaDistance = Math.sqrt(Math.pow(target.x - areaEnemy.x, 2) + Math.pow(target.y - areaEnemy.y, 2));
if (areaDistance < 400 && areaEnemy !== target) {
if (areaEnemy.takeBurnDamage) {
areaEnemy.takeBurnDamage(self.damage * 0.5, self.burnDuration, self.burnDamage);
}
}
}
}
// Play sword attack sound for melee attacks
sonidoEspadas();
}
};
self.attackTower = function () {
self.attackCooldown = 60;
enemyTowerHealth -= self.damage;
// Play random tower damage sound
var towerSounds = ['sonido_torre_1', 'sonido_torre_2', 'sonido_torre_3', 'sonido_torre_4'];
var randomIndex = Math.floor(Math.random() * towerSounds.length);
var sound = LK.getSound(towerSounds[randomIndex]);
sound.volume = soundValue;
sound.play();
// Create escombros particles when enemy tower takes damage - quantity based on damage
var particleCount = self.damage * 12; // Multiply particle count by damage
for (var escombrosIndex = 0; escombrosIndex < particleCount; escombrosIndex++) {
// 360-degree explosion pattern
var angle = escombrosIndex / particleCount * Math.PI * 2; // Distribute evenly in 360 degrees
var force = (200 + Math.random() * 300) * 4; // Quadruple the force
var velocityX = Math.cos(angle) * force;
var velocityY = Math.sin(angle) * force;
var escombrosParticle = game.addChild(LK.getAsset('escombros_torre_enemiga', {
anchorX: 0.5,
anchorY: 0.5,
x: enemyTower.x,
y: enemyTower.y - 800,
width: (60 + Math.random() * 40) * 5,
height: (60 + Math.random() * 40) * 5,
rotation: Math.random() * Math.PI * 2
}));
escombrosParticle.alpha = 0.9;
escombrosParticle.tint = 0x696969; // Dark gray color for enemy debris
// Add gravity and physics properties
escombrosParticle.velocityX = velocityX * 0.02; // Scale down for smooth movement
escombrosParticle.velocityY = velocityY * 0.02;
escombrosParticle.gravity = 0.8; // Gravity effect
// Animate escombros particles with physics
tween(escombrosParticle, {
y: enemyTower.y + 200 + escombrosParticle.velocityY * 100,
x: enemyTower.x + escombrosParticle.velocityX * 100,
alpha: 0,
rotation: escombrosParticle.rotation + Math.PI * 4,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
escombrosParticle.destroy();
}
});
}
if (enemyTowerHealth <= 0) {
LK.showYouWin();
}
updateTowerHealthBars();
};
self.takeDamage = function (damage) {
self.health -= damage;
// Update stats display to show current health
self.updateStatsDisplay();
if (self.health <= 0) {
// Mark as being destroyed to prevent multiple destruction attempts
self.isBeingDestroyed = true;
// Death animation - fade out and scale down from current tier scale
var deathScale = self.tierScale * 0.1;
tween(warriorGraphics, {
alpha: 0,
scaleX: deathScale,
scaleY: deathScale,
rotation: -Math.PI * 2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
// Only remove from warriors array if not already removed by collision detection
if (!self.isBeingDestroyed || self.isBeingDestroyed) {
var index = warriors.indexOf(self);
if (index > -1) {
warriors.splice(index, 1);
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50,
width: 3840,
height: 1080
});
/****
* Game Code
****/
function _typeof3(o) {
"@babel/helpers - typeof";
return _typeof3 = "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;
}, _typeof3(o);
}
function _typeof2(o) {
"@babel/helpers - typeof";
return _typeof2 = "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;
}, _typeof2(o);
}
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);
}
var warriors = [];
var enemies = [];
var meteoritos = [];
var globalFireModeActive = false;
var fireModeTimer = 0;
var playerTowerHealth = 30;
var enemyTowerHealth = 10;
var enemySpawnTimer = 0;
var isDragging = false;
var lastMouseX = 0;
var cameraX = 0;
var maxCameraX = 1792; // 3840 - 2048 = max scroll distance
var currentMana = 5;
var maxMana = 5;
var manaRegenTimer = 0;
var miniola_colision = false;
// Combination system variables
var currentCombination = [];
var combinationTimer = 0;
var combinationCooldown = 0;
var maxCombinationLength = 10;
var combinationWindowTime = 60; // 1 second at 60fps
var combinationResetTime = 60; // 1 second at 60fps
var temporaryNoteCounter = 0; // Helper counter for tracking notes (1-5)
// Apocalipsis system variables
var tiempoDeApocalipsis = 0; // Timer for tracking idle time without note presses (10 seconds = 600 frames)
var apocalipsisThreshold = 600; // 10 seconds at 60fps
// Element list system for meteorite invocation
var elementList = [];
var maxElementList = 5;
// Timing interval tracking variables
var noteTimingIntervals = []; // Store time intervals between note presses
var lastNoteTime = 0; // Timestamp of last note press
var isFirstNote = true; // Track if this is the first note in a sequence
// Touch position tracking variables
var initialTouchX = 0;
var initialTouchY = 0;
var currentTouchX = 0;
var currentTouchY = 0;
// Music beat detection variables
var musicBeatThreshold = 0; // Default sensitivity threshold set to 0 - will be controlled by sensitivity button
var lastBeatTime = 0;
var beatCooldown = 15; // Reduced cooldown for more frequent detections (0.25 seconds at 60fps)
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
// Create mana display
var manaText = new Text2('Mana: 5/5', {
size: 40,
fill: 0x00FFFF
});
manaText.anchor.set(0, 0);
manaText.x = 1100;
manaText.y = 100;
LK.gui.topLeft.addChild(manaText);
// Create mana orbs visual display
var manaOrbs = [];
for (var i = 0; i < maxMana; i++) {
var orb = LK.getAsset('manaOrbShape', {
width: 40,
height: 40
});
orb.anchor.set(0.5, 0.5);
orb.x = 1100 + i * 50;
orb.y = 160;
LK.gui.topLeft.addChild(orb);
manaOrbs.push(orb);
}
// Settings panel state
var settingsPanelVisible = false;
var settingsBars = [];
// Settings values (0.0 to 1.0 range)
var musicValue = 0.8;
var soundValue = 0.8;
var sensitivityValue = 0.5;
// Create settings button below mana bar
var settingsButton = LK.getAsset('settingsIcon', {
width: 120,
height: 120
});
settingsButton.anchor.set(0.5, 0.5);
settingsButton.x = 1200; // Move slightly to the right
settingsButton.y = 250; // Move down a bit more
settingsButton.alpha = 0.8;
LK.gui.topLeft.addChild(settingsButton);
// Create music volume text input
var musicVolumeInput = new Text2('Volumen Música: 80', {
size: 30,
fill: 0xFFFFFF
});
musicVolumeInput.anchor.set(0.5, 0.5);
musicVolumeInput.x = 1200;
musicVolumeInput.y = 380;
musicVolumeInput.alpha = 0;
LK.gui.topLeft.addChild(musicVolumeInput);
// Store all settings elements
settingsBars = [musicVolumeInput];
// Function to update music volume
function updateMusicVolume(value) {
// Parse and validate the input value
var volumeNumber = parseInt(value);
if (isNaN(volumeNumber)) {
volumeNumber = 80;
}
volumeNumber = Math.max(0, Math.min(100, volumeNumber));
musicValue = volumeNumber / 100;
musicVolumeInput.setText('Volumen Música: ' + volumeNumber);
// Apply music volume changes immediately
LK.stopMusic();
LK.playMusic('Music', {
volume: musicValue
});
}
// Music volume input interaction
musicVolumeInput.down = function (x, y, obj) {
// Simple interaction for now - could be enhanced with actual text input
var currentVolume = Math.round(musicValue * 100);
var newVolume = (currentVolume + 10) % 110; // Cycle through 0-100 by 10s
updateMusicVolume(newVolume);
};
settingsButton.down = function (x, y, obj) {
// Play settings click sound with centralized control like music - stop and restart with current volume
LK.getSound('settings_click').stop(); // Stop any currently playing instance
var settingsSound = LK.getSound('settings_click');
settingsSound.volume = soundValue * 0.7; // Apply current soundValue with 70% modifier
settingsSound.play();
// Visual feedback with bounce effect
tween(settingsButton, {
scaleX: 0.85,
scaleY: 0.85,
alpha: 0.6,
rotation: Math.PI * 0.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(settingsButton, {
scaleX: 1.05,
scaleY: 1.05,
alpha: 0.9,
rotation: 0
}, {
duration: 150,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(settingsButton, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8
}, {
duration: 100
});
}
});
}
});
// Toggle settings panel with staggered animations
if (settingsPanelVisible) {
// Hide settings panel with staggered fade out
settingsPanelVisible = false;
for (var i = 0; i < settingsBars.length; i++) {
var delay = i * 30; // Stagger each element by 30ms
tween(settingsBars[i], {
alpha: 0,
y: settingsBars[i].y - 20,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
delay: delay,
easing: tween.easeInOut
});
}
} else {
// Show settings panel with bouncy entrance
settingsPanelVisible = true;
for (var i = 0; i < settingsBars.length; i++) {
var delay = i * 40; // Stagger each element by 40ms
var targetY = settingsBars[i].y;
settingsBars[i].y = targetY - 30;
settingsBars[i].scaleX = 0.6;
settingsBars[i].scaleY = 0.6;
tween(settingsBars[i], {
alpha: 1,
y: targetY,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
delay: delay,
easing: tween.elasticOut
});
}
}
};
// Create collision debug text in center of game
var collisionDebugText = new Text2('Collision Debug', {
size: 60,
fill: 0xFFFF00
});
collisionDebugText.anchor.set(0.5, 0.5);
collisionDebugText.x = 1024; // Center of screen width (2048/2)
collisionDebugText.y = 1366; // Center of screen height (2732/2)
game.addChild(collisionDebugText);
// Create audio debug text to show real-time values
var audioDebugText = new Text2('Audio: 0.00 | Threshold: 0.15 | Diff: 0.00', {
size: 40,
fill: 0x00FFFF
});
audioDebugText.anchor.set(0.5, 0.5);
audioDebugText.x = 1024; // Center of screen width
audioDebugText.y = 1200; // Above collision debug text
game.addChild(audioDebugText);
// Create touch position debug text
var touchDebugText = new Text2('Touch Info: Initial(0,0) Current(0,0)', {
size: 40,
fill: 0xFF00FF
});
touchDebugText.anchor.set(0.5, 0.5);
touchDebugText.x = 1024; // Center of screen width
touchDebugText.y = 1500; // Below collision debug text
game.addChild(touchDebugText);
// Create combination message text
var combinationMessageText = new Text2('', {
size: 60,
fill: 0xFFFF00
});
combinationMessageText.anchor.set(0.5, 0.5);
combinationMessageText.x = 1024; // Center of screen width
combinationMessageText.y = 800; // Above other debug texts
combinationMessageText.alpha = 0;
game.addChild(combinationMessageText);
// Create temporary note counter info text
var tempCounterInfoText = new Text2('Notas presionadas: 0', {
size: 40,
fill: 0x00FF00
});
tempCounterInfoText.anchor.set(0.5, 0.5);
tempCounterInfoText.x = 1024; // Center of screen width
tempCounterInfoText.y = 600; // Above combination message text
game.addChild(tempCounterInfoText);
// Create element list display text
var elementListText = new Text2('Lista de Elementos: []', {
size: 45,
fill: 0xFFD700
});
elementListText.anchor.set(0.5, 0.5);
elementListText.x = 1024; // Center of screen width
elementListText.y = 400; // Above temp counter text
game.addChild(elementListText);
// Create timing intervals info text
var timingIntervalsText = new Text2('Intervalos: []', {
size: 35,
fill: 0xFFAA00
});
timingIntervalsText.anchor.set(0.5, 0.5);
timingIntervalsText.x = 1024; // Center of screen width
timingIntervalsText.y = 500; // Above temp counter text
game.addChild(timingIntervalsText);
// Create sky background - always behind everything
var skyBackground = game.addChildAt(LK.getAsset('cielo', {
anchorX: 0.0,
anchorY: 0.0,
x: 0,
y: 0,
width: 3840,
height: 2732
}), 0); // Add at index 0 to be behind everything
// Create tiled ground floor
var groundTiles = [];
var tileSize = 592.704; // Size of each ground tile (increased by 5% more)
var groundY = 2732; // Position at bottom of screen
var groundHeight = 728.6; // Extend height to fill bottom gap (tileSize + 136 pixels)
var numTiles = Math.ceil(3840 / tileSize) + 2; // Cover full width plus extra for seamless tiling
for (var i = 0; i < numTiles; i++) {
var groundTile = game.addChild(LK.getAsset('ground', {
anchorX: 0.0,
anchorY: 1.0,
x: i * tileSize,
y: groundY,
width: tileSize,
height: groundHeight
}));
groundTiles.push(groundTile);
}
// Create red overlay for fire mode (initially hidden)
var fireOverlay = game.addChild(LK.getAsset('healthBar', {
anchorX: 0.0,
anchorY: 0.0,
x: 0,
y: 0,
width: 3840,
height: 2732
}));
fireOverlay.tint = 0xff0000; // Red color
fireOverlay.alpha = 0; // Initially hidden
// Create towers (horizontal layout)
var playerTower = game.addChild(LK.getAsset('playerTower', {
anchorX: 0.5,
anchorY: 1.0,
x: 250,
y: 2559,
width: 1200,
height: 1728
}));
var enemyTower = game.addChild(LK.getAsset('enemyTower', {
anchorX: 0.5,
anchorY: 1.0,
x: 3590,
y: 2559,
width: 1200,
height: 1728
}));
// Tower health bars
var playerTowerHealthBar = LK.getAsset('playerTowerHealthBar', {
width: 1200,
height: 160
});
playerTowerHealthBar.anchor.set(0.5, 0.5);
playerTowerHealthBar.x = playerTower.x;
playerTowerHealthBar.y = playerTower.y - 1840;
game.addChild(playerTowerHealthBar);
var enemyTowerHealthBar = LK.getAsset('enemyTowerHealthBar', {
width: 1200,
height: 160
});
enemyTowerHealthBar.anchor.set(0.5, 0.5);
enemyTowerHealthBar.x = enemyTower.x;
enemyTowerHealthBar.y = enemyTower.y - 1840;
game.addChild(enemyTowerHealthBar);
// Create elemental notes (horizontal layout at top left) - show all elements
var elements = ['fire', 'water', 'earth', 'wind', 'light'];
var notes = [];
for (var i = 0; i < elements.length; i++) {
var note = new ElementalNote(elements[i], 0, 0);
LK.gui.topLeft.addChild(note);
// Make buttons smaller
note.scaleX = 0.4;
note.scaleY = 0.4;
// Position buttons horizontally in upper left with proper spacing (moved 50% right total)
note.x = 234 + i * 140; // Start at x:234 (moved from 180), space buttons 140 pixels apart
note.y = 120; // Fixed y position in upper area
notes.push(note);
}
// Create five apocalyptic note images below the elemental notes
var casillas = [];
for (var i = 0; i < 5; i++) {
var casilla = LK.getAsset('nota_apocalitica', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5
});
casilla.x = 409 + i * 70; // Moved left 25 units (from 434 to 409)
casilla.y = 220; // Moved down 20 units (from 200 to 220)
LK.gui.topLeft.addChild(casilla);
casillas.push(casilla);
}
// Create camera control buttons
var leftButton = LK.getAsset('leftCameraButton', {
width: 100,
height: 100
});
leftButton.anchor.set(0.5, 0.5);
leftButton.alpha = 0.5; // 50% transparency
LK.gui.left.addChild(leftButton);
var leftButtonText = new Text2('<', {
size: 60,
fill: 0xffffff
});
leftButtonText.anchor.set(0.5, 0.5);
leftButton.addChild(leftButtonText);
var rightButton = LK.getAsset('rightCameraButton', {
width: 100,
height: 100
});
rightButton.anchor.set(0.5, 0.5);
rightButton.alpha = 0.5; // 50% transparency
LK.gui.right.addChild(rightButton);
var rightButtonText = new Text2('>', {
size: 60,
fill: 0xffffff
});
rightButtonText.anchor.set(0.5, 0.5);
rightButton.addChild(rightButtonText);
function notePressed(element) {
// Reset apocalypse timer when any note is pressed
tiempoDeApocalipsis = 0;
// If this is the start of a new combination, clear previous timing data
if (currentCombination.length === 0) {
noteTimingIntervals = [];
isFirstNote = true;
lastNoteTime = 0;
}
// Record timing for interval tracking
var currentTime = Date.now();
if (isFirstNote) {
// First note - record time and initialize with 0 interval
lastNoteTime = currentTime;
isFirstNote = false;
noteTimingIntervals = [0]; // Initialize with 0 for first note
} else {
// Calculate interval since last note
var interval = currentTime - lastNoteTime;
noteTimingIntervals.push(interval);
lastNoteTime = currentTime;
}
// Update timing intervals display
var intervalsDisplay = noteTimingIntervals.length > 0 ? 'Intervalos: [' + noteTimingIntervals.map(function (interval) {
return Math.round(interval) + 'ms';
}).join(', ') + ']' : 'Intervalos: []';
timingIntervalsText.setText(intervalsDisplay);
// Element list is now managed separately by crea_combinacion_meteorito function
// Do not add pressed notes to element list
// Increment temporary counter
temporaryNoteCounter++;
// Add element to current combination
addToCombination(element);
// Check if current combination exactly matches the required meteorite sequence
if (currentCombination.length === 5) {
var hasMatchingCombination = true;
for (var i = 0; i < 5; i++) {
if (currentCombination[i] !== elementList[i]) {
hasMatchingCombination = false;
break;
}
}
if (hasMatchingCombination) {
// Current combination matches the required meteorite notes - invoke meteorite and set mana to zero
currentMana = 0;
updateManaDisplay();
// Summon meteorite
summonMeteorito();
showCombinationMessage('¡METEORITO INVOCADO CON 5 ELEMENTOS!');
// Reset combination
resetCombination();
temporaryNoteCounter = 0;
enableNoteButtons();
return;
}
}
// Disable buttons if temporary counter equals or exceeds available mana
if (temporaryNoteCounter >= currentMana) {
disableAllNoteButtons();
}
// Only process immediately if we've reached max combination length
if (currentCombination.length >= maxCombinationLength) {
processCombination();
}
}
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = enemyTower.x - 300;
enemy.y = 2186; // Spawn on ground level
enemy.onGround = true; // Start on ground
game.addChild(enemy);
enemies.push(enemy);
}
function summonMeteorito() {
var meteorito = new Meteorito();
meteorito.x = 0; // Start at x=0
meteorito.y = 0; // Start at y=0
game.addChild(meteorito);
meteoritos.push(meteorito);
}
function updateTowerHealthBars() {
var playerHealthPercent = Math.max(0, playerTowerHealth / 30);
var enemyHealthPercent = Math.max(0, enemyTowerHealth / 10);
playerTowerHealthBar.scaleX = playerHealthPercent;
enemyTowerHealthBar.scaleX = enemyHealthPercent;
// Scale towers based on health - minimum scale of 0.3 (30%), maximum 1.0 (100%)
var playerTowerScale = 0.3 + playerHealthPercent * 0.7; // 0.3 to 1.0 range
var enemyTowerScale = 0.3 + enemyHealthPercent * 0.7; // 0.3 to 1.0 range
// Apply scaling to towers
tween.stop(playerTower, {
scaleX: true,
scaleY: true
});
tween.stop(enemyTower, {
scaleX: true,
scaleY: true
});
tween(playerTower, {
scaleX: playerTowerScale,
scaleY: playerTowerScale
}, {
duration: 500,
easing: tween.easeInOut
});
tween(enemyTower, {
scaleX: enemyTowerScale,
scaleY: enemyTowerScale
}, {
duration: 500,
easing: tween.easeInOut
});
}
function updateManaDisplay() {
// Update text
manaText.setText('Mana: ' + currentMana + '/' + maxMana);
// Update orb visuals
for (var i = 0; i < manaOrbs.length; i++) {
if (i < currentMana) {
manaOrbs[i].alpha = 1.0; // Full opacity for available mana
manaOrbs[i].tint = 0x00FFFF; // Cyan color
} else {
manaOrbs[i].alpha = 0.3; // Low opacity for depleted mana
manaOrbs[i].tint = 0x666666; // Gray color
}
}
// Update note button states based on mana and current combination length
var requiredMana = currentCombination.length + 1; // Mana needed to add one more note
for (var i = 0; i < notes.length; i++) {
if (currentMana < requiredMana) {
notes[i].alpha = 0.5; // Grayed out when not enough mana
notes[i].isDisabled = true;
} else {
notes[i].alpha = 1.0; // Normal when mana available
notes[i].isDisabled = false;
}
}
}
function playRandomCombatSound() {
var combatSounds = ['combatir_1', 'combatir_2', 'combatir_3', 'combatir_4'];
var randomIndex = Math.floor(Math.random() * combatSounds.length);
var sound = LK.getSound(combatSounds[randomIndex]);
sound.volume = soundValue;
sound.play();
}
function sonidoEspadas() {
var sound = LK.getSound('attack');
sound.volume = soundValue;
sound.play();
}
function playRandomProjectileSound(element) {
var projectileSounds = [];
if (element === 'water') {
projectileSounds = ['sonido_proyectil_agua_1', 'sonido_proyectil_agua_2', 'sonido_proyectil_agua_3', 'sonido_proyectil_agua_4'];
} else if (element === 'wind') {
projectileSounds = ['sonido_proyectil_viento_1', 'sonido_proyectil_viento_2', 'sonido_proyectil_viento_3', 'sonido_proyectil_viento_4'];
} else if (element === 'light') {
projectileSounds = ['sonido_proyectil_energia_1', 'sonido_proyectil_energia_2', 'sonido_proyectil_energia_3', 'sonido_proyectil_energia_4'];
}
if (projectileSounds.length > 0) {
var randomIndex = Math.floor(Math.random() * projectileSounds.length);
var sound = LK.getSound(projectileSounds[randomIndex]);
sound.volume = soundValue;
sound.play();
}
}
function disableAllNoteButtons() {
for (var i = 0; i < notes.length; i++) {
notes[i].isDisabled = true;
notes[i].alpha = 0.5; // Visual feedback
}
}
function enableNoteButtons() {
// Re-enable buttons only if we have enough mana
updateManaDisplay();
}
function addToCombination(element) {
currentCombination.push(element);
combinationTimer = combinationWindowTime;
combinationCooldown = combinationResetTime;
// Show current combination
showCombinationMessage('Combinación: [' + currentCombination.join(', ') + ']');
}
function processCombination() {
if (currentCombination.length === 0) {
return;
}
// Store combination and timing intervals for melody playback before reset
var combinationForMelody = currentCombination.slice(); // Create a copy
var timingIntervalsForMelody = noteTimingIntervals.slice(); // Create a copy of intervals
// Check if combination is valid
if (isValidCombination(currentCombination)) {
// Execute the combination
executeCombination(currentCombination);
// Play melody after successful summoning with preserved intervals
playMelodySequenceWithIntervals(combinationForMelody, timingIntervalsForMelody);
} else {
// Show invalid combination message
showCombinationMessage('Combinación no existente');
}
// Reset combination only (element list is managed by crea_combinacion_meteorito)
// elementList is not reset here - only when meteorite is successfully invoked
resetCombination();
// Re-enable buttons after 1 second (invocation phase)
LK.setTimeout(function () {
temporaryNoteCounter = 0; // Reset helper counter after invocation phase
enableNoteButtons();
}, 1000);
}
function isValidCombination(combination) {
// Single element combinations are valid
if (combination.length === 1) {
var element = combination[0];
return element === 'fire' || element === 'water' || element === 'earth' || element === 'wind' || element === 'light';
}
// Check for meteorite combination first (exactly fire, water, earth, wind, light sequence)
if (combination.length === 5) {
var requiredSequence = ['fire', 'water', 'earth', 'wind', 'light'];
var isMeteorite = true;
for (var i = 0; i < combination.length; i++) {
if (combination[i] !== requiredSequence[i]) {
isMeteorite = false;
break;
}
}
if (isMeteorite) {
return true; // Perfect meteorite sequence match
}
// If not meteorite sequence, check if all elements are the same for tier 5
var firstElement = combination[0];
for (var i = 0; i < combination.length; i++) {
if (combination[i] !== firstElement) {
return false;
}
}
// Valid elements for multi-note combinations
return firstElement === 'fire' || firstElement === 'water' || firstElement === 'earth' || firstElement === 'wind' || firstElement === 'light';
}
// Multiple element combinations (2-4 notes of same element)
if (combination.length >= 2 && combination.length <= 4) {
var firstElement = combination[0];
// Check if all elements are the same
for (var i = 0; i < combination.length; i++) {
if (combination[i] !== firstElement) {
return false;
}
}
// Valid elements for multi-note combinations
return firstElement === 'fire' || firstElement === 'water' || firstElement === 'earth' || firstElement === 'wind' || firstElement === 'light';
}
return false;
}
function executeCombination(combination) {
// Check if we have enough mana for this combination
if (currentMana < combination.length) {
showCombinationMessage('No hay suficiente mana');
return;
}
// Consume mana based on combination length
currentMana -= combination.length;
updateManaDisplay();
if (combination.length === 1) {
// Single element summon
var element = combination[0];
summonWarrior(element, 1);
showCombinationMessage('¡' + element.toUpperCase() + ' nivel 1 invocado!');
} else if (combination.length >= 2 && combination.length <= 4) {
// Multiple element combination - create higher tier warrior (2-4 notes)
var element = combination[0]; // All elements should be the same
var level = combination.length;
summonWarrior(element, level);
showCombinationMessage('¡' + element.toUpperCase() + ' nivel ' + level + ' invocado!');
} else if (combination.length === 5) {
// Check if it's the meteorite sequence
var requiredSequence = ['fire', 'water', 'earth', 'wind', 'light'];
var isMeteorite = true;
for (var i = 0; i < combination.length; i++) {
if (combination[i] !== requiredSequence[i]) {
isMeteorite = false;
break;
}
}
if (isMeteorite) {
// Meteorite combination - summon destructive meteorite with mixed elements
summonMeteorito();
showCombinationMessage('¡METEORITO ELEMENTAL INVOCADO!');
} else {
// Regular 5-note same element combination
var element = combination[0];
summonWarrior(element, 5);
showCombinationMessage('¡' + element.toUpperCase() + ' nivel 5 invocado!');
}
}
}
function summonWarrior(element, tier) {
// Default tier to 1 if not specified
if (tier === undefined) {
tier = 1;
}
// Create elemental warrior based on the element and tier
var warrior = new Warrior(element, tier);
warrior.x = playerTower.x + 300;
warrior.y = 2186; // Spawn on ground level
warrior.onGround = true; // Start on ground
// Add elemental-specific visual effects on spawn
var warriorGraphics = warrior.children[0]; // Get the warrior graphics
if (element === 'water') {
// Water splash effect - blue particles
var summonScale = warrior.tierScale * 1.5;
tween(warriorGraphics, {
tint: 0x0066ff,
scaleX: summonScale,
scaleY: summonScale
}, {
duration: 300,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
scaleX: warrior.tierScale,
scaleY: warrior.tierScale
}, {
duration: 200
});
}
});
} else if (element === 'earth') {
// Earth rumble effect - brown particles
var originalY = warriorGraphics.y;
tween(warriorGraphics, {
tint: 0x8b4513,
y: originalY - 50
}, {
duration: 200,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
y: originalY
}, {
duration: 200
});
}
});
} else if (element === 'fire') {
// Fire burst effect - red/orange flames
var summonScale = warrior.tierScale * 1.3;
tween(warriorGraphics, {
tint: 0xff4400,
scaleX: summonScale,
scaleY: summonScale,
rotation: Math.PI * 0.1
}, {
duration: 250,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
scaleX: warrior.tierScale,
scaleY: warrior.tierScale,
rotation: 0
}, {
duration: 150
});
}
});
} else if (element === 'light') {
// Lightning effect - bright yellow flash
var summonScale = warrior.tierScale * 1.2;
tween(warriorGraphics, {
tint: 0xffff00,
alpha: 1.5,
scaleX: summonScale,
scaleY: summonScale
}, {
duration: 150,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
alpha: 1.0,
scaleX: warrior.tierScale,
scaleY: warrior.tierScale
}, {
duration: 100
});
}
});
} else if (element === 'wind') {
// Wind swirl effect - green spiral
var summonScale = warrior.tierScale * 1.1;
tween(warriorGraphics, {
tint: 0x44ff44,
rotation: Math.PI * 2,
scaleX: summonScale,
scaleY: summonScale
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(warriorGraphics, {
tint: 0xffffff,
rotation: 0,
scaleX: warrior.tierScale,
scaleY: warrior.tierScale
}, {
duration: 200
});
}
});
}
game.addChild(warrior);
warriors.push(warrior);
var sound = LK.getSound('summon');
sound.volume = soundValue;
sound.play();
// Add jump effect to all units when any warrior is summoned
// Make all warriors jump
for (var i = 0; i < warriors.length; i++) {
var jumpWarrior = warriors[i];
// Store current Y position if not already stored
if (jumpWarrior.baseY === 0) {
jumpWarrior.baseY = jumpWarrior.y;
}
// Apply jump tween - go up then back down
tween(jumpWarrior, {
y: jumpWarrior.baseY - 100
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(jumpWarrior, {
y: jumpWarrior.baseY
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
// Make all enemies jump
for (var i = 0; i < enemies.length; i++) {
var jumpEnemy = enemies[i];
// Store current Y position if not already stored
if (jumpEnemy.baseY === 0) {
jumpEnemy.baseY = jumpEnemy.y;
}
// Apply jump tween - go up then back down
tween(jumpEnemy, {
y: jumpEnemy.baseY - 100
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(jumpEnemy, {
y: jumpEnemy.baseY
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
function playMelodySequenceWithIntervals(combination, intervals) {
// Wait 1 second before starting melody playback to differentiate from invocation
LK.setTimeout(function () {
// Play notes sequentially using cumulative timing
var cumulativeDelay = 0;
for (var i = 0; i < combination.length; i++) {
var element = combination[i];
// First note plays immediately (0ms), subsequent notes use intervals
var delay = i === 0 ? 0 : cumulativeDelay;
// Use setTimeout with closure to preserve the element value
(function (noteElement, currentDelay) {
LK.setTimeout(function () {
// Play the appropriate elemental note sound with controlled volume
if (noteElement === 'fire') {
var fireSound = LK.getSound('Nota_Fire');
fireSound.volume = soundValue;
fireSound.play();
} else if (noteElement === 'water') {
var waterSound = LK.getSound('Nota_Water');
waterSound.volume = soundValue;
waterSound.play();
} else if (noteElement === 'earth') {
var earthSound = LK.getSound('Nota_Earth');
earthSound.volume = soundValue;
earthSound.play();
} else if (noteElement === 'wind') {
var windSound = LK.getSound('Nota_Wind');
windSound.volume = soundValue;
windSound.play();
} else if (noteElement === 'light') {
var lightSound = LK.getSound('Nota_Light');
lightSound.volume = soundValue;
lightSound.play();
} else {
var summonSound = LK.getSound('summon');
summonSound.volume = soundValue;
summonSound.play();
}
}, currentDelay);
})(element, delay);
// Add interval for next note (skip first note since it's 0)
if (i < intervals.length && i > 0) {
cumulativeDelay += intervals[i];
} else if (i === 0 && intervals.length > 1) {
// For first note, set cumulative delay to the second interval
cumulativeDelay = intervals[1];
}
}
}, 500); // 0.5 second delay before melody playback
}
function playMelodySequence(combination) {
// Wait 1 second before starting melody playback to differentiate from invocation
LK.setTimeout(function () {
// Play each note in the combination using recorded timing intervals
var cumulativeDelay = 0;
for (var i = 0; i < combination.length; i++) {
var element = combination[i];
var delay = cumulativeDelay;
// Use setTimeout with closure to preserve the element value
(function (noteElement, currentDelay) {
LK.setTimeout(function () {
// Play the appropriate elemental note sound with controlled volume
if (noteElement === 'fire') {
var fireSound = LK.getSound('Nota_Fire');
fireSound.volume = soundValue;
fireSound.play();
} else if (noteElement === 'water') {
var waterSound = LK.getSound('Nota_Water');
waterSound.volume = soundValue;
waterSound.play();
} else if (noteElement === 'earth') {
var earthSound = LK.getSound('Nota_Earth');
earthSound.volume = soundValue;
earthSound.play();
} else if (noteElement === 'wind') {
var windSound = LK.getSound('Nota_Wind');
windSound.volume = soundValue;
windSound.play();
} else if (noteElement === 'light') {
var lightSound = LK.getSound('Nota_Light');
lightSound.volume = soundValue;
lightSound.play();
} else {
var summonSound = LK.getSound('summon');
summonSound.volume = soundValue;
summonSound.play();
}
}, currentDelay);
})(element, delay);
// Update cumulative delay for next note
if (i < noteTimingIntervals.length) {
cumulativeDelay += noteTimingIntervals[i];
} else if (i > 0) {
// Fallback to 200ms if no interval recorded
cumulativeDelay += 200;
}
}
}, 1000); // 1 second delay before melody playback
}
function updateElementListDisplay() {
var listDisplay = 'Lista de Elementos: [' + elementList.map(function (el) {
return el.toUpperCase();
}).join(', ') + '] (' + elementList.length + '/' + maxElementList + ')';
elementListText.setText(listDisplay);
}
function resetCombination() {
currentCombination = [];
combinationTimer = 0;
combinationCooldown = 0;
temporaryNoteCounter = 0; // Reset helper counter
// Don't reset timing intervals here - they should persist until new combination starts
// Only reset when a new note is pressed
// Update display only when actually clearing intervals
}
function showCombinationMessage(message) {
combinationMessageText.setText(message);
combinationMessageText.alpha = 1.0;
// Fade out message after 2 seconds
tween(combinationMessageText, {
alpha: 0
}, {
duration: 2000
});
}
function changeGroundTexture(assetName) {
// Change ground texture for all tiles
for (var g = 0; g < groundTiles.length; g++) {
var oldTile = groundTiles[g];
// Find the correct index to insert the new tile behind all existing ground tiles
var insertIndex = 0;
// Count existing ground tiles to place new tile behind them
for (var childIndex = 0; childIndex < game.children.length; childIndex++) {
var child = game.children[childIndex];
// Check if this child is a ground tile by comparing properties
if (child.anchor && child.anchor.x === 0.0 && child.anchor.y === 1.0 && child.y === 2732) {
insertIndex = childIndex + 1; // Place after this ground tile
}
}
var newTile = game.addChildAt(LK.getAsset(assetName, {
anchorX: 0.0,
anchorY: 1.0,
x: oldTile.x,
y: oldTile.y,
width: oldTile.width,
height: oldTile.height
}), insertIndex);
// Add tween to smoothly transition between textures
newTile.alpha = 0;
tween(newTile, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
oldTile.destroy();
}
});
groundTiles[g] = newTile;
}
}
game.down = function (x, y, obj) {
// Handle initial touch in game layer directly
// Store initial touch position for debug
initialTouchX = x;
initialTouchY = y;
currentTouchX = x;
currentTouchY = y;
if (touchDebugText && typeof touchDebugText.setText === 'function') {
touchDebugText.setText('Touch Info: Initial(' + Math.round(x) + ',' + Math.round(y) + ') Current(' + Math.round(x) + ',' + Math.round(y) + ')');
}
if (obj.event && obj.event.button === 2) {
// Right mouse button
isDragging = true;
lastMouseX = x;
obj.event.preventDefault(); // Prevent context menu
}
};
leftButton.down = function (x, y, obj) {
// Move camera left
cameraX -= 100;
cameraX = Math.max(0, Math.min(cameraX, maxCameraX));
game.x = -cameraX;
// Visual feedback
tween(leftButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(leftButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
};
rightButton.down = function (x, y, obj) {
// Move camera right
cameraX += 100;
cameraX = Math.max(0, Math.min(cameraX, maxCameraX));
game.x = -cameraX;
// Visual feedback
tween(rightButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(rightButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
};
game.up = function (x, y, obj) {
if (obj.event && obj.event.button === 2) {
// Right mouse button
isDragging = false;
}
};
game.move = function (x, y, obj) {
if (isDragging) {
var deltaX = lastMouseX - x;
cameraX += deltaX;
cameraX = Math.max(0, Math.min(cameraX, maxCameraX));
game.x = -cameraX;
lastMouseX = x;
}
// Update current touch position for debug (game coordinates)
currentTouchX = x;
currentTouchY = y;
// Update debug text with both initial and current positions
if (touchDebugText && typeof touchDebugText.setText === 'function') {
touchDebugText.setText('Game Move - Initial(' + Math.round(initialTouchX) + ',' + Math.round(initialTouchY) + ') Current(' + Math.round(currentTouchX) + ',' + Math.round(currentTouchY) + ')');
}
};
// Add GUI move handler for touch tracking
LK.gui.topLeft.move = function (x, y, obj) {
// Update current touch position for debug (GUI coordinates)
currentTouchX = x;
currentTouchY = y;
// Update debug text with both initial and current positions
if (touchDebugText && typeof touchDebugText.setText === 'function') {
touchDebugText.setText('GUI Move - Initial(' + Math.round(initialTouchX) + ',' + Math.round(initialTouchY) + ') Current(' + Math.round(currentTouchX) + ',' + Math.round(currentTouchY) + ')');
}
};
// Cloud system for background decoration
var clouds = [];
var cloudSpawnTimer = 0;
function createCloud() {
var cloud = new Nube();
cloud.x = -200; // Start off-screen left
// Create clouds randomly between y=0 and y=1000 with depth layering
cloud.y = Math.random() * 2000; // Random position between y=0 and y=2000
cloud.startFloating(); // Start floating animation after position is set
// Determine if cloud is background (behind game) or foreground (in front of game)
var isBackground = Math.random() < 0.6; // 60% chance to be background
if (isBackground) {
// Background clouds - behind game elements, more transparent
// Scale already randomized in Nube constructor, apply additional uniform background scaling
var additionalScale = 0.5 + Math.random() * 0.6; // Apply additional 50-110% scaling
cloud.scaleX *= additionalScale;
cloud.scaleY *= additionalScale;
cloud.alpha = 0.4 + Math.random() * 0.5; // Random opacity between 40% and 90%
cloud.children[0].tint = 0xE0E0E0; // Slightly darker for background effect
// Add background clouds before other game elements
game.addChildAt(cloud, 0); // Add at index 0 to be behind everything
} else {
// Foreground clouds - in front of game elements, more visible
// Scale already randomized in Nube constructor, apply additional uniform foreground scaling
var additionalScale = 0.8 + Math.random() * 0.8; // Apply additional 80-160% scaling
cloud.scaleX *= additionalScale;
cloud.scaleY *= additionalScale;
cloud.alpha = 0.4 + Math.random() * 0.5; // Random opacity between 40% and 90%
cloud.children[0].tint = 0xF8F8F8; // Brighter for foreground effect
// Add foreground clouds on top of game elements
game.addChild(cloud); // Add normally to be in front
}
// Vary speed based on position for depth effect
if (cloud.y < 600) {
// Higher clouds move slower (distance effect)
cloud.baseSpeed = cloud.baseSpeed * 0.5;
} else if (cloud.y > 1400) {
// Lower clouds move faster (proximity effect)
cloud.baseSpeed = cloud.baseSpeed * 1.5;
}
clouds.push(cloud);
}
function updateClouds() {
// Note: Cloud movement is now handled by the Nube class update method
// Spawn new clouds periodically
cloudSpawnTimer++;
if (cloudSpawnTimer >= 300 + Math.random() * 600) {
// Every 5-15 seconds
createCloud();
cloudSpawnTimer = 0;
}
}
// Create initial clouds
for (var i = 0; i < 24; i++) {
// Doubled number for better coverage
var cloud = new Nube();
cloud.x = Math.random() * 4000; // Random initial position across screen
// Create clouds randomly between y=0 and y=1000 with depth layering
cloud.y = Math.random() * 2000; // Random position between y=0 and y=2000
cloud.startFloating(); // Start floating animation after position is set
// Determine if cloud is background (behind game) or foreground (in front of game)
var isBackground = Math.random() < 0.6; // 60% chance to be background
if (isBackground) {
// Background clouds - behind game elements, more transparent
// Scale already randomized in Nube constructor, apply additional uniform background scaling
var additionalScale = 0.5 + Math.random() * 0.6; // Apply additional 50-110% scaling
cloud.scaleX *= additionalScale;
cloud.scaleY *= additionalScale;
cloud.alpha = 0.4 + Math.random() * 0.5; // Random opacity between 40% and 90%
cloud.children[0].tint = 0xE0E0E0; // Slightly darker for background effect
// Add background clouds before other game elements
game.addChildAt(cloud, 0); // Add at index 0 to be behind everything
} else {
// Foreground clouds - in front of game elements, more visible
// Scale already randomized in Nube constructor, apply additional uniform foreground scaling
var additionalScale = 0.8 + Math.random() * 0.8; // Apply additional 80-160% scaling
cloud.scaleX *= additionalScale;
cloud.scaleY *= additionalScale;
cloud.alpha = 0.4 + Math.random() * 0.5; // Random opacity between 40% and 90%
cloud.children[0].tint = 0xF8F8F8; // Brighter for foreground effect
// Add foreground clouds on top of game elements
game.addChild(cloud); // Add normally to be in front
}
// Vary speed based on position for depth effect
if (cloud.y < 600) {
// Higher clouds move slower (distance effect)
cloud.baseSpeed = cloud.baseSpeed * 0.5;
} else if (cloud.y > 1400) {
// Lower clouds move faster (proximity effect)
cloud.baseSpeed = cloud.baseSpeed * 1.5;
}
clouds.push(cloud);
}
// Function to simulate music beat detection based on game timing
function getGameMusicLevel() {
// Simulate music beats based on game ticks and music timing
// Create a beat pattern that varies over time
var beatPattern = Math.sin(LK.ticks * 0.1) * 0.3 + 0.5; // Base sine wave
var strongBeat = Math.sin(LK.ticks * 0.05) * 0.4; // Slower variation for stronger beats
var randomVariation = (Math.random() - 0.5) * 0.2; // Add some randomness
// Combine patterns to create realistic music-like variation
var musicLevel = beatPattern + strongBeat + randomVariation;
// Ensure the value stays within realistic bounds (0.0 to 1.0)
musicLevel = Math.max(0, Math.min(1, musicLevel));
return musicLevel;
}
// Function to initialize element list (lista meteorito)
function initializeElementList() {
elementList = ['fire', 'water', 'earth', 'wind', 'light'];
updateElementListDisplay();
}
// Function to create random meteorite combination
function crea_combinacion_meteorito() {
for (var i = 0; i < 5; i++) {
// Generate random integer between 0.49 and 5.49, then make it integer
var randomNumber = Math.floor(Math.random() * 5) + 1; // This gives us 1-5
var element;
if (randomNumber === 1) {
element = 'fire';
} else if (randomNumber === 2) {
element = 'water';
} else if (randomNumber === 3) {
element = 'earth';
} else if (randomNumber === 4) {
element = 'wind';
} else if (randomNumber === 5) {
element = 'light';
}
elementList.push(element);
}
updateElementListDisplay();
}
// Initialize element list with corresponding notes at game start
crea_combinacion_meteorito();
// Start background music with initial volume from slider
LK.playMusic('Music', {
volume: musicValue
});
// Timer for apocalyptic note revelation (every 10 seconds = 600 frames at 60fps)
var revelacionTimer = 0;
game.update = function () {
// Music beat detection and character synchronization
var audioLevel = getGameMusicLevel();
// Calculate sensitivity difference for debug display
var sensitivityDifference = Math.max(0, audioLevel - musicBeatThreshold);
// Update audio debug text in real-time
if (audioDebugText && typeof audioDebugText.setText === 'function') {
audioDebugText.setText('Audio: ' + audioLevel.toFixed(3) + ' | Threshold: ' + musicBeatThreshold.toFixed(2) + ' | Diff: ' + sensitivityDifference.toFixed(3));
}
// Update revelacion timer and call function every 10 seconds
revelacionTimer++;
if (revelacionTimer >= 600) {
// 10 seconds at 60fps
revelacion_nota_apocalitica();
revelacionTimer = 0;
}
// Enhanced beat detection with multiple triggers
var beatDetected = false;
// Primary beat detection - only when audio level reaches 1
if (audioLevel >= 1.0 && LK.ticks - lastBeatTime > beatCooldown) {
beatDetected = true;
}
// Remove fallback timer-based beat detection to prevent constant particle spam
if (beatDetected) {
// Beat detected - activate effect on all characters
lastBeatTime = LK.ticks;
// Activate effect on warriors
for (var i = 0; i < warriors.length; i++) {
warriors[i].beatEffectTimer = 120; // 2 seconds of sine wave effect
}
// Activate effect on enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].beatEffectTimer = 120; // 2 seconds of sine wave effect
}
// Activate particle effects on towers instead of scaling
// Create particles around player tower in cone shape
for (var p = 0; p < 24; p++) {
// Calculate cone angle - wider at the top, narrower at bottom
var angle = (Math.random() - 0.5) * Math.PI * 0.5; // 90 degree cone spread
var distance = Math.random() * 300 + 100; // Random distance from center
var startX = playerTower.x + Math.sin(angle) * (distance * 0.3); // Narrow at bottom
var endX = playerTower.x + Math.sin(angle) * distance; // Wide at top
var playerTowerCurrentScale = playerTower.scaleX; // Get current tower scale
var scaledOffsetY = (1728 - 50) * playerTowerCurrentScale; // Scale the Y offset
var particle = game.addChild(LK.getAsset('particula_torre_jugador', {
anchorX: 0.5,
anchorY: 0.5,
x: startX + 100,
y: playerTower.y - scaledOffsetY,
width: 300 + Math.random() * 200,
height: 300 + Math.random() * 200,
rotation: Math.PI
}));
particle.alpha = 0.8;
// Animate particles upward to the sky in cone shape and fade out
tween(particle, {
y: playerTower.y - 2000 - Math.random() * 500,
x: endX + 100,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 3000 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Create particles around enemy tower in cone shape
for (var p = 0; p < 24; p++) {
// Calculate cone angle - wider at the top, narrower at bottom
var angle = (Math.random() - 0.5) * Math.PI * 0.5; // 90 degree cone spread
var distance = Math.random() * 300 + 100; // Random distance from center
var startX = enemyTower.x + Math.sin(angle) * (distance * 0.3); // Narrow at bottom
var endX = enemyTower.x + Math.sin(angle) * distance; // Wide at top
var enemyTowerCurrentScale = enemyTower.scaleX; // Get current tower scale
var scaledOffsetY = (1728 - 50) * enemyTowerCurrentScale; // Scale the Y offset
var particle = game.addChild(LK.getAsset('particula_torre_enemiga', {
anchorX: 0.5,
anchorY: 0.5,
x: startX,
y: enemyTower.y - scaledOffsetY,
width: 300 + Math.random() * 200,
height: 300 + Math.random() * 200,
rotation: Math.PI
}));
particle.alpha = 0.8;
// Animate particles upward to the sky in cone shape and fade out
tween(particle, {
y: enemyTower.y - 2000 - Math.random() * 500,
x: endX,
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 3000 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
// Mana regeneration - every 10 seconds (600 frames at 60fps)
manaRegenTimer++;
if (manaRegenTimer >= 600) {
if (currentMana < maxMana) {
currentMana++;
updateManaDisplay();
}
manaRegenTimer = 0;
}
// Spawn enemies periodically
enemySpawnTimer++;
if (enemySpawnTimer >= 500) {
// Every 8.3 seconds
spawnEnemy();
enemySpawnTimer = 0;
}
// Clean up off-screen warriors
for (var i = warriors.length - 1; i >= 0; i--) {
var warrior = warriors[i];
if (warrior.x > 4000) {
warrior.destroy();
warriors.splice(i, 1);
}
}
// Clean up off-screen enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.x < -200) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update cloud system
updateClouds();
// Update temporary counter info text
tempCounterInfoText.setText('Notas presionadas: ' + temporaryNoteCounter);
// Check if any fire tier 5 warriors exist
var hasTier5FireWarrior = false;
for (var w = 0; w < warriors.length; w++) {
var warrior = warriors[w];
if (warrior.element === 'fire' && warrior.tier === 5) {
hasTier5FireWarrior = true;
break;
}
}
// Activate fire mode if tier 5 fire warrior exists and mode is not active
if (hasTier5FireWarrior && !globalFireModeActive) {
globalFireModeActive = true;
showCombinationMessage('¡MODO FUEGO ACTIVADO!');
// Activate red visual effects
tween(fireOverlay, {
alpha: 0.2
}, {
duration: 500,
easing: tween.easeInOut
});
// Apply red tint to towers
tween(playerTower, {
tint: 0xff6666
}, {
duration: 500,
easing: tween.easeInOut
});
tween(enemyTower, {
tint: 0xff6666
}, {
duration: 500,
easing: tween.easeInOut
});
// Change ground texture to fire ground
changeGroundTexture('tileground');
// Apply red tint to clouds
for (var c = 0; c < clouds.length; c++) {
// Store original tint if not already stored
if (!clouds[c].children[0].originalTint) {
clouds[c].children[0].originalTint = clouds[c].children[0].tint;
}
tween(clouds[c].children[0], {
tint: 0xff8888
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
// Deactivate fire mode if no tier 5 fire warriors exist and mode is active
if (!hasTier5FireWarrior && globalFireModeActive) {
globalFireModeActive = false;
showCombinationMessage('Modo fuego desactivado');
// Fade out red overlay and tints
tween(fireOverlay, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
// Remove red tint from towers
tween(playerTower, {
tint: 0xffffff
}, {
duration: 1000,
easing: tween.easeOut
});
tween(enemyTower, {
tint: 0xffffff
}, {
duration: 1000,
easing: tween.easeOut
});
// Change ground texture back to normal
changeGroundTexture('ground');
// Remove red tint from clouds
for (var c = 0; c < clouds.length; c++) {
tween(clouds[c].children[0], {
tint: clouds[c].children[0].originalTint || 0xF0F0F0
}, {
duration: 1000,
easing: tween.easeOut
});
}
}
// Process global fire mode effects only if active
if (globalFireModeActive) {
// Apply fire damage to all enemies every second
if (LK.ticks % 60 === 0) {
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (enemy.takeBurnDamage) {
enemy.takeBurnDamage(0, 1000, 6); // No initial damage, 1 second burn for 6 damage
}
}
}
}
// Update apocalypse timer
tiempoDeApocalipsis++;
if (tiempoDeApocalipsis >= apocalipsisThreshold) {
// 5 seconds of no note presses - trigger apocalypse music
musicaDelApocalipsis();
tiempoDeApocalipsis = 0; // Reset timer after triggering
}
// Update combination system timers
if (combinationTimer > 0) {
combinationTimer--;
if (combinationTimer <= 0 && currentCombination.length > 0) {
// Time window expired, process current combination
processCombination();
}
}
if (combinationCooldown > 0) {
combinationCooldown--;
if (combinationCooldown <= 0 && currentCombination.length > 0) {
// Reset timeout reached, clear combination
showCombinationMessage('Tiempo agotado - Combinación reiniciada');
resetCombination();
// Re-enable buttons after timeout
enableNoteButtons();
}
}
};
// Variable i for counting revealed apocalyptic notes
var i = 0;
function revelacion_nota_apocalitica() {
// Only reveal if i is less than 5 (cannot have more than i=5)
if (i >= 5) {
return; // Exit if we've already revealed all 5 notes
}
// Get the element from elementList based on current counter i
if (i < elementList.length) {
var element = elementList[i];
// Get the corresponding note image for this element
var noteImageId = element + 'Note';
// Update the apocalyptic note casilla with the element's note image
if (casillas[i]) {
// Remove current asset and add new one
casillas[i].destroy();
// Create new note asset with the element's image
var newCasilla = LK.getAsset(noteImageId, {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5
});
newCasilla.x = 409 + i * 70; // Same positioning as original
newCasilla.y = 220;
LK.gui.topLeft.addChild(newCasilla);
casillas[i] = newCasilla;
}
}
// Increment counter by 1 each time function is called
i++;
}
function ocultar_notas_apocalitica() {
// Reset counter i to 0
i = 0;
// Hide all apocalyptic notes by restoring default lock image
for (var j = 0; j < casillas.length; j++) {
if (casillas[j]) {
// Remove current note image
casillas[j].destroy();
// Create new default lock image
var newCasilla = LK.getAsset('nota_apocalitica', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5
});
newCasilla.x = 409 + j * 70; // Same positioning as original
newCasilla.y = 220;
LK.gui.topLeft.addChild(newCasilla);
casillas[j] = newCasilla;
}
}
}
function musicaDelApocalipsis() {
// Play the meteorite element list with 0.5s intervals between notes
var combinationForMelody = elementList.slice(); // Create a copy of elementList
// Create intervals array with 0.5s (500ms) between each note
var intervalsForMelody = [];
for (var i = 0; i < combinationForMelody.length; i++) {
if (i === 0) {
intervalsForMelody.push(0); // First note plays immediately
} else {
intervalsForMelody.push(500); // 0.5s = 500ms delay between notes
}
}
// Play the melody sequence with the meteorite combination
playMelodySequenceWithIntervals(combinationForMelody, intervalsForMelody);
// Show apocalypse message
showCombinationMessage('¡MÚSICA DEL APOCALIPSIS - MELODÍA DEL METEORITO!');
} ===================================================================
--- original.js
+++ change.js
@@ -783,8 +783,9 @@
}
self.baseCooldown = self.attackCooldown || 60; // Store base cooldown for resets
self.target = null;
self.isBeingDestroyed = false; // Flag to prevent multiple destruction attempts
+ self.activar_movimiento = true; // Boolean to control if warrior can move
// Physics properties
self.velocityY = 0;
self.onGround = false;
self.gravity = 0.5;
@@ -905,10 +906,10 @@
self.y = 1800; // Fly above ground level
self.baseY = 1800; // Update base position
}
}
- // Move towards enemy tower (speed is controlled by combat state)
- if (!self.target) {
+ // Move towards enemy tower only if movement is enabled
+ if (!self.target && self.activar_movimiento) {
var totalSpeed = self.speed + (self.aumento_velocidad || 0);
self.x += totalSpeed;
}
// Attack logic
@@ -1577,29 +1578,34 @@
self.projectiles.splice(p, 1);
}
}
}
- // Stop movement if in combat or at tower position, otherwise resume normal movement
- // Exception: wind warriors (aerial units) continue moving while attacking
- if ((inCombat || atTowerPosition) && self.element !== 'wind') {
+ // Set activar_movimiento based on combat state and element type
+ if (inCombat && self.element !== 'wind') {
+ // Stop movement for all elements except wind when in combat range
+ self.activar_movimiento = false;
+ } else if (!inCombat) {
+ // Allow movement when not in combat
+ self.activar_movimiento = true;
+ }
+ // Apply movement based on activar_movimiento flag
+ if (!self.activar_movimiento || atTowerPosition) {
self.speed = 0;
} else {
- // Only resume movement if not in combat
- if (!inCombat) {
- var baseSpeed = 2;
- if (self.element === 'fire') {
- baseSpeed = 2.2;
- } else if (self.element === 'water') {
- baseSpeed = 1.8;
- } else if (self.element === 'earth') {
- baseSpeed = 1.5;
- } else if (self.element === 'light') {
- baseSpeed = 2.5;
- } else if (self.element === 'wind') {
- baseSpeed = 2.8;
- }
- self.speed = baseSpeed;
+ // Resume normal movement with base speed
+ var baseSpeed = 2;
+ if (self.element === 'fire') {
+ baseSpeed = 2.2;
+ } else if (self.element === 'water') {
+ baseSpeed = 1.8;
+ } else if (self.element === 'earth') {
+ baseSpeed = 1.5;
+ } else if (self.element === 'light') {
+ baseSpeed = 2.5;
+ } else if (self.element === 'wind') {
+ baseSpeed = 2.8;
}
+ self.speed = baseSpeed;
}
// Check collision with enemy tower - use separate x and y collision detection for flying units
var towerColliderRadius = 700; // Fixed collider size, not scaled with tower
var warriorColliderWidth = 288 * 0.5; // Half of warrior width
Generame un guerrero azteca con patrones, estilo pixelar, ademas sera un El lagarto azul de Gorgona humanoide. Va tener una armadura roja con efetos de llamitas pequeñas. In-Game asset. 2d. High contrast. No shadows
Genérame una Rana de dardo venenosa guerra azteca con eso patrones estilo pixelar, con una apariencia maligna. In-Game asset. 2d. High contrast. No shadows
geerame una esmeralda pixelar. In-Game asset. 2d. High contrast. No shadows
Generame una boton con dentro de forma de una nota musical con efectos de agua.. In-Game asset. 2d. High contrast. No shadows
Generame una boton con dentro de forma de una nota musical con efectos de fuego .. In-Game asset. 2d. High contrast. No shadows
Generame una boton con dentro de forma de una nota musical con efectos de energia. In-Game asset. 2d. High contrast. No shadows
Generame una boton con dentro de forma de una nota musical con efectos de viento. In-Game asset. 2d. High contrast. No shadows
Generame una boton con dentro de forma de una nota musical con efectos de tierra. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero voaldor Colibrí esmeralda del Chiribiquete estilo azteca con patrones, estilo pixelar. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero meduza cone fectos de agua, que cura como mago, estilo pixelar, ambeintado a lo azteca. In-Game asset. 2d. High contrast. No shadows
Generame un jaguar guerrero con efectos de energia estilo magico, pixelar, con ambientacion azteca. In-Game asset. 2d. High contrast. No shadows
Proyectil agua pixelar. In-Game asset. 2d. High contrast. No shadows
Luz oscura particulas, moradas. In-Game asset. 2d. High contrast. No shadows
Particula de luz. In-Game asset. 2d. High contrast. No shadows
Generame una piedras corrupta
Genérame una MONO TITÍ guerra azteca con eso patrones estilo pixelar, con una apariencia maligna.. In-Game asset. 2d. High contrast. No shadows
Genérame un Tucan guerra azteca con eso patrones estilo pixelar, con una apariencia maligna. In-Game asset. 2d. High contrast. No shadows
Un signo de más en verde. In-Game asset. 2d. High contrast. No shadows
Un proyectil de electricidad pixelar. In-Game asset. 2d. High contrast. No shadows
Generame una explosion de este proyectil de forma circular
Creame una nubes pixelar. In-Game asset. 2d. High contrast. No shadows
Una tuerca pixelar como boton. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, ademas sera un Tortuga de ciénaga colombiana humanoide. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, ademas sera una iguana humanoide, con efectos de fuego. In-Game asset. 2d. High contrast. No shadows
Agregale efectos de fuego pero en un fondo de alto contraste, mejor dicho solo pono mas rojo y llmas en la espada
Agregale lava y fuego a esta textrua
Creame una explosion de fuego pixelar. In-Game asset. 2d. High contrast. No shadows
agregale un poquito de ver y azul sin perder la identidad de l aimagen, solo cuadrar colores
Generame un guerrero azteca con patrones, estilo pixelar, además será una Pez loro, con efectos de AGUA. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será una Cangrejo violinista, con efectos de AGUA. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será una Delfin Rosado con efectos de AGUA. In-Game asset. 2d. High contrast. No shadows
Generame unm meteorito pixelar elemental con todos los elementos. In-Game asset. 2d. High contrast. No shadows
particulas rosadas, de poder. In-Game asset. 2d. High contrast. No shadows
Haz este candando con los 5 ewlementos, fuego tierra, agua, aire, energia
Creame un cielo pixelar hermoso, sin sol ni nubes, ni montañas, nia rboles. In-Game asset. 2d. High contrast. No shadows
Generame una montañas pixelar en fondo blanco. In-Game asset. 2d. High contrast. No shadows
Generame una montañas de selva pixelar en fondo blanco, cercanas. In-Game asset. 2d. High contrast. No shadows
Generame un muro pixelar de tierra isometrico con aptornes aztecas. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será un animal Tapir, con efectos de tierra, cargando un gran escudo o muro.. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será un animal Anaconda verde, con efectos de tierra, cargando un gran escudo o muro.. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será un animal manati con efectos de tierra, cargando un enrome muro. gigante. In-Game asset. 2d. High contrast. No shadows
uan flor pixelar para plantar, sin matera sola una hermosa flor. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será un Cóndor de los Andes, unidad voladora con alas, con efectos de viento. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será una Mariposa alas de vidrio (Greta oto), unidad voladora con alas, con efectos de viento. Tiene que ser un animal.. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será Murciélago frugívoro, unidad voladora con alas, con efectos de viento. Tiene que ser un animal.. In-Game asset. 2d. High contrast. No shadows
Generame un guerrero azteca con patrones, estilo pixelar, además será Tucán toco , unidad voladora con alas, con efectos de viento. Tiene que ser un animal.. In-Game asset. 2d. High contrast. No shadows
Gotas de agua pixelar. In-Game asset. 2d. High contrast. No shadows
Genrame un muro con mas detalle que se vea superior es decir un nivel mas fuerte.
Generame una particula de espora pixela rt. In-Game asset. 2d. High contrast. No shadows
z de sueño pixelar. In-Game asset. 2d. High contrast. No shadows
Generame una lanza pixelar. In-Game asset. 2d. High contrast. No shadows
Creame un tornado pixelar en un fondo azul, para elimianrlo despues. In-Game asset. 2d. High contrast. No shadows
Hazme el rayo de color amarillo
Creame un boton de este personaje extilo pixelar cuadrado
POnlo trizte el perosnaje y gris el boton
Jugar
Pon una casa
deja todo naranaja
Genérame una Jaguar guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. In-Game asset. 2d. High contrast. No shadows
Genérame una Oso de Anteojos guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. In-Game asset. 2d. High contrast. No shadows
Genérame una Pecari de collar guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. In-Game asset. 2d. High contrast. No shadows
Genérame una Puma guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Tayra guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Nutria Neotropical guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Caiman llanero guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Capibara guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Zorro Cangrejero guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Demonio de Tasmnia guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. POderes, super rojo y rabioso, como un ejfe final. Animal. No tiene arams solo una gran y poderosa mordida. In-Game asset. 2d. High contrast. No shadows
Genérame una olibrí Esmeralda Andina guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Zopilote Rey guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Paujil guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Halcon Murcielago guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Buho de anteojos guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Mariposa monarca guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Chicharra guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una paloma guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad aerea con alas. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Rana de Cristal guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con un arco o cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Iguana Verde guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con un arco o cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Boa de arcoiris guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con un arco o cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Ciempies gigante amazonico guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con un arco o cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Escorpion Colombiano guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con un arco o cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Araña guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con un arco o cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Pez leon guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Serpiente coral guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame una Rana de dardo venenosa guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad a distancia, con cerbatana. Animal. In-Game asset. 2d. High contrast. No shadows
Genérame un hipopotamo guerrero azteca con eso patrones, estilo pixelar, con una apariencia maligna, ojos rojos, rabioso. Unidad cuerpo a cuerpo. Animal.. In-Game asset. 2d. High contrast. No shadows
Flecha maligna, de color rojo, pixelar. In-Game asset. 2d. High contrast. No shadows
Luna llena blanca, pixelar. In-Game asset. 2d. High contrast. No shadows
sol pixelart. In-Game asset. 2d. High contrast. No shadows
Un cielo noche pixelar 16:04 con estrellas. In-Game asset. 2d. High contrast. No shadows
Hazme un boton pixelar azteca, que diga Fin. In-Game asset. 2d. High contrast. No shadows
Nota_Fire
Sound effect
tower_damage
Sound effect
combat
Sound effect
enemy_death
Sound effect
combatir_1
Sound effect
Music
Music
combatir_2
Sound effect
combatir_3
Sound effect
combatir_4
Sound effect
attack
Sound effect
Nota_Water
Sound effect
Nota_Earth
Sound effect
Nota_Wind
Sound effect
Nota_Light
Sound effect
sonido_torre_2
Sound effect
sonido_torre_3
Sound effect
sonido_torre_4
Sound effect
sonido_torre_1
Sound effect
sonido_proyectil_agua_1
Sound effect
sonido_proyectil_agua_2
Sound effect
sonido_proyectil_agua_3
Sound effect
sonido_proyectil_agua_4
Sound effect
sonido_proyectil_viento_1
Sound effect
sonido_proyectil_viento_2
Sound effect
sonido_proyectil_viento_3
Sound effect
sonido_proyectil_viento_4
Sound effect
sonido_proyectil_energia_1
Sound effect
sonido_proyectil_energia_2
Sound effect
sonido_proyectil_energia_3
Sound effect
sonido_proyectil_energia_4
Sound effect
settings_click
Sound effect
burn_sound
Sound effect
musicId
Music
Level_1_en
Sound effect
Level_1_es
Sound effect
Level_2_en
Sound effect
Level_3_en
Sound effect
Level_4_en
Sound effect
Level_5_en
Sound effect
Level_6_en
Sound effect
Level_7_en
Sound effect
Level_9_en
Sound effect
Level_10_en
Sound effect
Level_11_en
Sound effect
Level_12_en
Sound effect
Level_13_en
Sound effect
Level_14_en
Sound effect
Level_15_en
Sound effect
Level_16_en
Sound effect
Level_17_en
Sound effect
Level_18_en
Sound effect
Level_19_en
Sound effect
Level_20_en
Sound effect
Level_21_en
Sound effect
Level_22_en
Sound effect
Level_23_en
Sound effect
Level_24_en
Sound effect
Level_25_en
Sound effect
Level_26_en
Sound effect
Level_2_es
Sound effect
Level_3_es
Sound effect
Level_4_es
Sound effect
Level_5_es
Sound effect
Level_6_es
Sound effect
Level_7_es
Sound effect
Level_8_es
Sound effect
Level_9_es
Sound effect
Level_10_es
Sound effect
Level_11_es
Sound effect
Level_12_es
Sound effect
Level_13_es
Sound effect
Level_14_es
Sound effect
Level_15_es
Sound effect
Level_16_es
Sound effect
Level_17_es
Sound effect
Level_18_es
Sound effect
Level_19_es
Sound effect
Level_20_es
Sound effect
Level_21_es
Sound effect
Level_22_es
Sound effect
Level_23_es
Sound effect
Level_24_es
Sound effect
Level_25_es
Sound effect
Level_26_es
Sound effect
Level_8_en
Sound effect
ganar
Sound effect
comic1_sound
Sound effect
comic2_sound
Sound effect
comic3_sound
Sound effect
comic4_sound
Sound effect
comic5_sound
Sound effect
comic6_sound
Sound effect
comic7_sound
Sound effect
comic8_sound
Sound effect
comic9_sound
Sound effect
comic10_sound
Sound effect
comic11_sound
Sound effect
music_menu_en
Music
music_menu_es
Music
Music2
Music
Music3
Music
Music4
Music
Music5
Music
Music8
Music
Music7
Music
Nota_Earth2
Sound effect
Nota_Fire2
Sound effect
Nota_Light2
Sound effect
Nota_Water2
Sound effect
Nota_Wind2
Sound effect
explosion_meteorito
Sound effect
muerte_guerrero
Sound effect
MusicVictoria
Music