User prompt
que el personage aguante 3 golpes
User prompt
que el juego sea infinito
User prompt
un menu
User prompt
que el menu prinsipal tenga las obciones de obciones jugar y creditos
User prompt
que haya un menu prinsipal
User prompt
que el personage aguanta 3 ataques
User prompt
que el juego sea infinito
User prompt
que los ataques sean un fuego teledirigido y un orbe explosivo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
crea 2 ataques nuevos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que hayan 4 enemigos mas
User prompt
que tenga un sistema de ordas que aumentan la dificultad
User prompt
que haya un refugio que luego de 10000 puntos el personage entre y le de un multiplicador de daño mas un escudo al salir por 6 seg ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
añade una vase que luego de tener sierto puntage el personage entre a resguardarse
User prompt
que el ataque de orbe no se pueda tirar mas de 7 veses por orda
User prompt
que el ataque de orbe tenga un tiempo de 7 seg de recarga
User prompt
que el ataque de orbe tenga una recarga de 7
User prompt
que los enemigos tengan una barra de vida
User prompt
ahora que el proyectil ligrto se active con un boton
User prompt
que cada enemigo tenga distinta cantidad de vida
User prompt
ahora que el ataque de luz tenga solo 12 seg de recarga
User prompt
ahora que el ataque de luz tenga una recarga de 3 segundos y que elimine a todos los enemigos en pantalla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el ataque de fuego valla directamente al enemigo
User prompt
que los ataques del personage se activen con un boton en pantalla
User prompt
que haya una gran bariedad de monstruos
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BerserkerShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('berserkerShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5 + Math.random() * 1;
self.health = 5;
self.maxHealth = 5;
self.monsterType = 'berserker';
self.enraged = false;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
// Enrage when health is low
if (self.health <= self.maxHealth * 0.4 && !self.enraged) {
self.enraged = true;
self.speed *= 2;
shadowGraphics.tint = 0xff0000;
}
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Berserker effect when enraged
if (self.enraged) {
var shake = (Math.random() - 0.5) * 4;
self.x += shake;
self.y += shake;
// Pulsing red effect
var pulse = 1 + Math.sin(LK.ticks * 0.8) * 0.5;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var BomberShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('bomberShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2 + Math.random() * 1;
self.health = 2;
self.maxHealth = 2;
self.monsterType = 'bomber';
self.exploding = false;
self.explosionTimer = 30;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
if (distanceToHero < 100 && !self.exploding) {
self.exploding = true;
shadowGraphics.tint = 0xff4444;
}
if (self.exploding) {
self.explosionTimer--;
var flash = Math.sin(self.explosionTimer * 0.5) > 0 ? 0xff0000 : 0xffff00;
shadowGraphics.tint = flash;
if (self.explosionTimer <= 0) {
// Create explosion effect
for (var i = 0; i < 6; i++) {
var explosionAngle = i / 6 * Math.PI * 2;
var fragment = new Shadow();
fragment.x = self.x + Math.cos(explosionAngle) * 20;
fragment.y = self.y + Math.sin(explosionAngle) * 20;
fragment.speed = 2;
shadows.push(fragment);
game.addChild(fragment);
}
}
} else {
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var FastShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('fastShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3 + Math.random() * 2;
self.health = 1;
self.maxHealth = 1;
self.monsterType = 'fast';
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Add erratic movement
self.x += Math.sin(LK.ticks * 0.2) * 2;
self.y += Math.cos(LK.ticks * 0.15) * 2;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var FireSpell = Container.expand(function () {
var self = Container.call(this);
var spellGraphics = self.attachAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 30; // Half second
self.radius = 80;
self.update = function () {
self.lifetime--;
// Grow the spell
var scale = 1 + (30 - self.lifetime) / 30;
spellGraphics.scaleX = scale;
spellGraphics.scaleY = scale;
spellGraphics.alpha = self.lifetime / 30;
};
return self;
});
var HealerShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('healerShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.8 + Math.random() * 0.5;
self.health = 3;
self.maxHealth = 3;
self.monsterType = 'healer';
self.lastHeal = 0;
self.healCooldown = 120; // 2 seconds
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Healing ability
if (LK.ticks - self.lastHeal > self.healCooldown) {
for (var i = 0; i < shadows.length; i++) {
var otherShadow = shadows[i];
if (otherShadow !== self) {
var distance = Math.sqrt(Math.pow(self.x - otherShadow.x, 2) + Math.pow(self.y - otherShadow.y, 2));
if (distance < 150 && otherShadow.health < otherShadow.maxHealth) {
otherShadow.health = Math.min(otherShadow.maxHealth, otherShadow.health + 1);
LK.effects.flashObject(otherShadow, 0x00ff00, 300);
self.lastHeal = LK.ticks;
break;
}
}
}
}
// Pulsing green effect
var pulse = 1 + Math.sin(LK.ticks * 0.4) * 0.3;
shadowGraphics.tint = 0x44ff44;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.lightPower = 1;
self.fireRate = 60; // Fire every 60 ticks initially
self.lastLightShot = 0;
self.update = function () {
// Hero update method - no automatic firing
};
return self;
});
var LightOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobOffset = Math.random() * Math.PI * 2;
self.baseY = self.y;
self.update = function () {
self.y = self.baseY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10;
};
return self;
});
var LightProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('lightProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 180; // 3 seconds at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
};
return self;
});
var MimicShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('mimicShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.8 + Math.random() * 1.2;
self.health = 2;
self.maxHealth = 2;
self.monsterType = 'mimic';
self.lastCopy = 0;
self.copyCooldown = 240; // 4 seconds
self.copyTarget = null;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Copy nearest enemy abilities
if (LK.ticks - self.lastCopy > self.copyCooldown) {
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < shadows.length; i++) {
var otherShadow = shadows[i];
if (otherShadow !== self && otherShadow.monsterType !== 'mimic') {
var distance = Math.sqrt(Math.pow(self.x - otherShadow.x, 2) + Math.pow(self.y - otherShadow.y, 2));
if (distance < 200 && distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = otherShadow;
}
}
}
if (nearestEnemy) {
self.copyTarget = nearestEnemy.monsterType;
self.lastCopy = LK.ticks;
// Visual feedback
LK.effects.flashObject(self, 0xff00ff, 500);
// Copy some properties
if (nearestEnemy.monsterType === 'fast') {
self.speed = nearestEnemy.speed;
shadowGraphics.tint = 0xffff00;
} else if (nearestEnemy.monsterType === 'tank') {
self.health = Math.min(self.maxHealth + 2, nearestEnemy.health);
shadowGraphics.tint = 0x888888;
} else if (nearestEnemy.monsterType === 'teleporter') {
shadowGraphics.tint = 0x8844ff;
}
}
}
// Rainbow shifting effect
var hue = LK.ticks * 0.05 % 1;
var r = Math.sin(hue * Math.PI * 2) * 127 + 128;
var g = Math.sin((hue + 0.33) * Math.PI * 2) * 127 + 128;
var b = Math.sin((hue + 0.66) * Math.PI * 2) * 127 + 128;
var color = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b);
shadowGraphics.tint = color;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var Shadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 2;
self.health = 2;
self.maxHealth = 2;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var ShielderShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('shielderShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.2 + Math.random() * 0.8;
self.health = 4;
self.maxHealth = 4;
self.monsterType = 'shielder';
self.shieldActive = false;
self.lastShield = 0;
self.shieldCooldown = 180; // 3 seconds
self.shieldDuration = 120; // 2 seconds
self.shieldTimer = 0;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Shield activation when damaged
if (self.health < self.maxHealth && !self.shieldActive && LK.ticks - self.lastShield > self.shieldCooldown) {
self.shieldActive = true;
self.shieldTimer = self.shieldDuration;
self.lastShield = LK.ticks;
shadowGraphics.tint = 0x4444ff;
}
// Shield timer
if (self.shieldActive) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shieldActive = false;
shadowGraphics.tint = 0xffffff;
}
// Pulsing blue effect when shielded
var pulse = 1 + Math.sin(LK.ticks * 0.6) * 0.4;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var SplitterShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('splitterShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5 + Math.random() * 1;
self.health = 3;
self.maxHealth = 3;
self.monsterType = 'splitter';
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Pulsing effect
var pulse = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var TankShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('tankShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5 + Math.random() * 0.5;
self.health = 8;
self.maxHealth = 8;
self.monsterType = 'tank';
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Visual health indicator
var healthPercent = self.health / self.maxHealth;
shadowGraphics.alpha = 0.5 + healthPercent * 0.5;
// Update health bar
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var TeleporterShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('teleporterShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 1;
self.health = 2;
self.maxHealth = 2;
self.monsterType = 'teleporter';
self.lastTeleport = 0;
self.teleportCooldown = 180; // 3 seconds
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
// Teleport if far from hero and cooldown is ready
if (distanceToHero > 300 && LK.ticks - self.lastTeleport > self.teleportCooldown) {
var teleportDistance = 150;
var teleportAngle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x = hero.x - Math.cos(teleportAngle) * teleportDistance;
self.y = hero.y - Math.sin(teleportAngle) * teleportDistance;
self.lastTeleport = LK.ticks;
LK.effects.flashObject(self, 0x8844ff, 300);
} else {
// Normal movement
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Create single cube background
var cube = LK.getAsset('cube', {
anchorX: 0.5,
anchorY: 0.5
});
cube.x = 1024;
cube.y = 1366;
game.addChild(cube);
var hero = game.addChild(new Hero());
hero.x = 1024;
hero.y = 1366;
var shadows = [];
var lightProjectiles = [];
var fireSpells = [];
var lightOrbs = [];
var lastShadowSpawn = 0;
var shadowSpawnRate = 120; // Start spawning every 2 seconds
var waveLevel = 1;
var score = 0;
var lastFireSpell = 0;
var fireSpellCooldown = 90; // 1.5 seconds cooldown at 60fps
var maxActiveFireSpells = 3;
var lastLightAttack = 0;
var lightAttackCooldown = 420; // 7 seconds cooldown at 60fps
var orbsUsedThisWave = 0;
var maxOrbsPerWave = 7;
var waveEnemiesRemaining = 0;
var waveEnemiesTotal = 0;
var waveActive = false;
var waveStartDelay = 0;
var waveDifficultyMultiplier = 1.0;
var shelterActive = false;
var shelterScore = 10000; // Score threshold to activate shelter
var shelterDuration = 300; // 5 seconds at 60fps
var shelterTimer = 0;
var shelterGraphics = null;
var damageBonusActive = false;
var damageBonusTimer = 0;
var damageBonusDuration = 360; // 6 seconds at 60fps
var shieldActive = false;
var shieldTimer = 0;
var shieldDuration = 360; // 6 seconds at 60fps
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(0.5, 0);
waveTxt.y = 70;
LK.gui.top.addChild(waveTxt);
var waveProgressTxt = new Text2('Enemies: 0/0', {
size: 40,
fill: 0x00FFFF
});
waveProgressTxt.anchor.set(0.5, 0);
waveProgressTxt.y = 130;
LK.gui.top.addChild(waveProgressTxt);
// Create fire button
var fireButton = LK.getAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
});
fireButton.x = 200;
fireButton.y = 2500;
game.addChild(fireButton);
// Create light attack button
var lightButton = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8,
alpha: 0.8
});
lightButton.x = 1800;
lightButton.y = 2500;
game.addChild(lightButton);
// Create light projectile button
var lightProjectileButton = LK.getAsset('lightProjectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0,
alpha: 0.8
});
lightProjectileButton.x = 1024;
lightProjectileButton.y = 2500;
game.addChild(lightProjectileButton);
// Fire button press handler
fireButton.down = function (x, y, obj) {
// Fire spell at nearest enemy - check cooldown and limit
var timeSinceLastFire = LK.ticks - lastFireSpell;
if (timeSinceLastFire >= fireSpellCooldown && fireSpells.length < maxActiveFireSpells && shadows.length > 0) {
// Find nearest shadow
var nearestShadow = null;
var nearestDistance = Infinity;
for (var i = 0; i < shadows.length; i++) {
var distance = Math.sqrt(Math.pow(hero.x - shadows[i].x, 2) + Math.pow(hero.y - shadows[i].y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
nearestShadow = shadows[i];
}
}
;
// Light attack button press handler
lightButton.down = function (x, y, obj) {
// Check cooldown and orb usage limit
var timeSinceLastLight = LK.ticks - lastLightAttack;
if (timeSinceLastLight >= lightAttackCooldown && orbsUsedThisWave < maxOrbsPerWave) {
// Destroy all enemies on screen
for (var i = shadows.length - 1; i >= 0; i--) {
var shadow = shadows[i];
// Create light orb for each destroyed shadow
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
// Add score based on monster type
var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
// Flash effect on each enemy before destruction
tween(shadow, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
shadow.destroy();
}
});
shadows.splice(i, 1);
}
// Update score display
scoreTxt.setText('Score: ' + score);
// Play sound effect
LK.getSound('shadowDestroy').play();
// Screen flash effect
LK.effects.flashScreen(0xffffaa, 800);
// Button feedback with cooldown visual
LK.effects.flashObject(lightButton, 0xffffaa, 400);
tween(lightButton, {
alpha: 0.3
}, {
duration: 0
});
tween(lightButton, {
alpha: 0.8
}, {
duration: lightAttackCooldown * 16.67
}); // Convert ticks to ms
// Update cooldown and usage counter
lastLightAttack = LK.ticks;
orbsUsedThisWave++;
}
};
// Light projectile button press handler
lightProjectileButton.down = function (x, y, obj) {
// Fire light projectile
var newProjectile = new LightProjectile();
newProjectile.x = hero.x;
newProjectile.y = hero.y;
// Fire in 8 directions
var directions = 8;
for (var i = 0; i < directions; i++) {
var angle = i / directions * Math.PI * 2;
var projectile = new LightProjectile();
projectile.x = hero.x;
projectile.y = hero.y;
projectile.velocityX = Math.cos(angle) * 8;
projectile.velocityY = Math.sin(angle) * 8;
lightProjectiles.push(projectile);
game.addChild(projectile);
}
// Button feedback
LK.effects.flashObject(lightProjectileButton, 0xffffaa, 200);
};
if (nearestShadow) {
var newFireSpell = new FireSpell();
newFireSpell.x = nearestShadow.x;
newFireSpell.y = nearestShadow.y;
fireSpells.push(newFireSpell);
game.addChild(newFireSpell);
lastFireSpell = LK.ticks;
LK.getSound('fireBlast').play();
// Button feedback
LK.effects.flashObject(fireButton, 0xff4400, 200);
}
}
};
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Keep hero within bounds
if (dragNode.x < 40) dragNode.x = 40;
if (dragNode.x > 2008) dragNode.x = 2008;
if (dragNode.y < 40) dragNode.y = 40;
if (dragNode.y > 2692) dragNode.y = 2692;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Check if touching hero
var heroDistance = Math.sqrt(Math.pow(x - hero.x, 2) + Math.pow(y - hero.y, 2));
if (heroDistance < 60) {
dragNode = hero;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
function startWave() {
waveActive = true;
waveStartDelay = 180; // 3 second delay before spawning
waveEnemiesTotal = Math.min(5 + waveLevel * 2, 30); // Cap at 30 enemies
waveEnemiesRemaining = waveEnemiesTotal;
waveDifficultyMultiplier = 1.0 + (waveLevel - 1) * 0.15; // 15% increase per wave
shadowSpawnRate = Math.max(30, 120 - waveLevel * 8); // Faster spawning each wave
orbsUsedThisWave = 0; // Reset orb usage for new wave
waveTxt.setText('Wave: ' + waveLevel);
waveProgressTxt.setText('Enemies: ' + (waveEnemiesTotal - waveEnemiesRemaining) + '/' + waveEnemiesTotal);
LK.effects.flashScreen(0x00FF00, 500);
}
game.update = function () {
// Wave management
if (!waveActive && shadows.length === 0) {
// Start new wave when no enemies remain
startWave();
}
// Spawn shadows during active wave
if (waveActive && waveEnemiesRemaining > 0 && waveStartDelay <= 0 && LK.ticks - lastShadowSpawn >= shadowSpawnRate) {
var newShadow;
// Choose random monster type based on wave level
var monsterRoll = Math.random();
if (waveLevel < 3) {
// Early waves: mostly basic shadows
if (monsterRoll < 0.7) newShadow = new Shadow();else if (monsterRoll < 0.9) newShadow = new FastShadow();else newShadow = new TankShadow();
} else if (waveLevel < 6) {
// Mid waves: introduce more variety
if (monsterRoll < 0.4) newShadow = new Shadow();else if (monsterRoll < 0.6) newShadow = new FastShadow();else if (monsterRoll < 0.75) newShadow = new TankShadow();else if (monsterRoll < 0.9) newShadow = new SplitterShadow();else newShadow = new TeleporterShadow();
} else if (waveLevel < 10) {
// Late waves: all monster types including dangerous ones
if (monsterRoll < 0.2) newShadow = new Shadow();else if (monsterRoll < 0.35) newShadow = new FastShadow();else if (monsterRoll < 0.5) newShadow = new TankShadow();else if (monsterRoll < 0.65) newShadow = new SplitterShadow();else if (monsterRoll < 0.75) newShadow = new TeleporterShadow();else if (monsterRoll < 0.85) newShadow = new BomberShadow();else if (monsterRoll < 0.92) newShadow = new HealerShadow();else newShadow = new ShielderShadow();
} else {
// Very late waves: all enemy types including new ones
if (monsterRoll < 0.15) newShadow = new Shadow();else if (monsterRoll < 0.25) newShadow = new FastShadow();else if (monsterRoll < 0.35) newShadow = new TankShadow();else if (monsterRoll < 0.45) newShadow = new SplitterShadow();else if (monsterRoll < 0.55) newShadow = new TeleporterShadow();else if (monsterRoll < 0.65) newShadow = new BomberShadow();else if (monsterRoll < 0.75) newShadow = new HealerShadow();else if (monsterRoll < 0.85) newShadow = new ShielderShadow();else if (monsterRoll < 0.93) newShadow = new BerserkerShadow();else newShadow = new MimicShadow();
}
// Spawn from random edge
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top
newShadow.x = Math.random() * 2048;
newShadow.y = -30;
break;
case 1:
// Right
newShadow.x = 2078;
newShadow.y = Math.random() * 2732;
break;
case 2:
// Bottom
newShadow.x = Math.random() * 2048;
newShadow.y = 2762;
break;
case 3:
// Left
newShadow.x = -30;
newShadow.y = Math.random() * 2732;
break;
}
// Apply wave difficulty multiplier
newShadow.speed = (newShadow.speed + waveLevel * 0.3) * waveDifficultyMultiplier;
newShadow.health = Math.ceil(newShadow.health * waveDifficultyMultiplier);
newShadow.maxHealth = newShadow.health;
shadows.push(newShadow);
game.addChild(newShadow);
lastShadowSpawn = LK.ticks;
waveEnemiesRemaining--;
waveProgressTxt.setText('Enemies: ' + (waveEnemiesTotal - waveEnemiesRemaining) + '/' + waveEnemiesTotal);
}
// Wave start delay countdown
if (waveStartDelay > 0) {
waveStartDelay--;
}
// Check if wave is complete
if (waveActive && waveEnemiesRemaining <= 0 && shadows.length === 0) {
waveActive = false;
waveLevel++;
// Wave completion bonus
score += waveLevel * 50;
scoreTxt.setText('Score: ' + score);
LK.effects.flashScreen(0xFFFF00, 800);
}
// Check hero collision with shadows
for (var i = 0; i < shadows.length; i++) {
var shadow = shadows[i];
if (hero.intersects(shadow) && !shelterActive && !shieldActive) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check bomber explosions
if (shadow.monsterType === 'bomber' && shadow.exploding && shadow.explosionTimer <= 0) {
var explosionDistance = Math.sqrt(Math.pow(hero.x - shadow.x, 2) + Math.pow(hero.y - shadow.y, 2));
if (explosionDistance < 120 && !shelterActive && !shieldActive) {
LK.effects.flashScreen(0xff4400, 1000);
LK.showGameOver();
return;
}
// Remove exploded bomber
shadow.destroy();
shadows.splice(i, 1);
i--; // Adjust index after removal
}
}
// Update and check light projectiles
for (var j = lightProjectiles.length - 1; j >= 0; j--) {
var projectile = lightProjectiles[j];
if (projectile.lifetime <= 0 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) {
projectile.destroy();
lightProjectiles.splice(j, 1);
continue;
}
// Check collision with shadows
for (var k = shadows.length - 1; k >= 0; k--) {
if (projectile.intersects(shadows[k])) {
var shadow = shadows[k];
// Check if enemy is shielded
var damage = damageBonusActive ? 2 : 1;
if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
damage = 0; // No damage when shielded
LK.effects.flashObject(shadow, 0x4444ff, 100);
} else {
shadow.health -= damage;
}
var shadowDestroyed = false;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter' && shadow.health <= 0) {
// Create two smaller fast shadows
for (var split = 0; split < 2; split++) {
var miniShadow = new FastShadow();
miniShadow.x = shadow.x + (split === 0 ? -30 : 30);
miniShadow.y = shadow.y + (Math.random() - 0.5) * 60;
miniShadow.speed *= 0.8;
shadows.push(miniShadow);
game.addChild(miniShadow);
}
}
if (shadow.monsterType === 'bomber' && shadow.exploding && shadow.explosionTimer > 0) {
// Bomber was destroyed while exploding, cancel explosion
shadow.exploding = false;
}
// Create light orb
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(k, 1);
shadowDestroyed = true;
var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
// Monster took damage but not destroyed
LK.effects.flashObject(shadow, 0xffffff, 200);
}
projectile.destroy();
lightProjectiles.splice(j, 1);
break;
}
}
}
// Update and check fire spells
for (var l = fireSpells.length - 1; l >= 0; l--) {
var spell = fireSpells[l];
if (spell.lifetime <= 0) {
spell.destroy();
fireSpells.splice(l, 1);
continue;
}
// Check collision with shadows
for (var m = shadows.length - 1; m >= 0; m--) {
var distance = Math.sqrt(Math.pow(spell.x - shadows[m].x, 2) + Math.pow(spell.y - shadows[m].y, 2));
if (distance < spell.radius) {
var shadow = shadows[m];
// Check if enemy is shielded
var damage = damageBonusActive ? 4 : 2; // Fire spells do more damage
if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
damage = Math.ceil(damage / 2); // Reduced damage when shielded
LK.effects.flashObject(shadow, 0x4444ff, 100);
}
shadow.health -= damage;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter') {
// Create two smaller fast shadows
for (var split = 0; split < 2; split++) {
var miniShadow = new FastShadow();
miniShadow.x = shadow.x + (split === 0 ? -30 : 30);
miniShadow.y = shadow.y + (Math.random() - 0.5) * 60;
miniShadow.speed *= 0.8;
shadows.push(miniShadow);
game.addChild(miniShadow);
}
}
if (shadow.monsterType === 'bomber' && shadow.exploding && shadow.explosionTimer > 0) {
// Bomber was destroyed while exploding, cancel explosion
shadow.exploding = false;
}
// Create light orb
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(m, 1);
var scoreValue = shadow.monsterType === 'tank' ? 30 : shadow.monsterType === 'splitter' ? 35 : shadow.monsterType === 'teleporter' ? 25 : shadow.monsterType === 'bomber' ? 40 : shadow.monsterType === 'healer' ? 45 : shadow.monsterType === 'shielder' ? 40 : shadow.monsterType === 'berserker' ? 50 : shadow.monsterType === 'mimic' ? 55 : 15;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
// Monster took damage but not destroyed
LK.effects.flashObject(shadow, 0xff8800, 200);
}
}
}
}
// Check light orb collection
for (var n = lightOrbs.length - 1; n >= 0; n--) {
var orb = lightOrbs[n];
if (hero.intersects(orb)) {
hero.lightPower++;
if (hero.fireRate > 20) {
hero.fireRate -= 2;
}
orb.destroy();
lightOrbs.splice(n, 1);
LK.getSound('collectOrb').play();
// Flash hero with light effect
LK.effects.flashObject(hero, 0xffffaa, 500);
}
}
// Shelter activation check
if (score >= shelterScore && !shelterActive) {
shelterActive = true;
shelterTimer = shelterDuration;
// Create shelter visual
shelterGraphics = LK.getAsset('shelter', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
shelterGraphics.x = hero.x;
shelterGraphics.y = hero.y;
game.addChild(shelterGraphics);
// Visual feedback for shelter activation
LK.effects.flashScreen(0x00ffff, 1000);
LK.effects.flashObject(hero, 0x00ffff, 1000);
// Make hero semi-transparent during shelter
hero.alpha = 0.5;
// Pulsing effect for shelter
tween(shelterGraphics, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(shelterGraphics, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
}
// Shelter timer countdown
if (shelterActive) {
shelterTimer--;
// Move shelter with hero
if (shelterGraphics) {
shelterGraphics.x = hero.x;
shelterGraphics.y = hero.y;
}
if (shelterTimer <= 0) {
shelterActive = false;
hero.alpha = 1.0; // Restore normal visibility
// Remove shelter visual
if (shelterGraphics) {
shelterGraphics.destroy();
shelterGraphics = null;
}
// Activate damage bonus and shield after leaving shelter
damageBonusActive = true;
damageBonusTimer = damageBonusDuration;
shieldActive = true;
shieldTimer = shieldDuration;
// Visual feedback for bonuses
LK.effects.flashScreen(0xff8800, 800);
LK.effects.flashObject(hero, 0xff8800, 1000);
// Increase shelter score threshold for next activation
shelterScore += 10000;
}
}
// Damage bonus timer countdown
if (damageBonusActive) {
damageBonusTimer--;
if (damageBonusTimer <= 0) {
damageBonusActive = false;
}
}
// Shield timer countdown
if (shieldActive) {
shieldTimer--;
if (shieldTimer <= 0) {
shieldActive = false;
}
}
// Victory condition
if (score >= 500) {
LK.showYouWin();
}
};
// Start first wave
startWave(); ===================================================================
--- original.js
+++ change.js
@@ -5,8 +5,57 @@
/****
* Classes
****/
+var BerserkerShadow = Container.expand(function () {
+ var self = Container.call(this);
+ var shadowGraphics = self.attachAsset('berserkerShadow', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 1.5 + Math.random() * 1;
+ self.health = 5;
+ self.maxHealth = 5;
+ self.monsterType = 'berserker';
+ self.enraged = false;
+ // Create health bar
+ var healthBarBg = self.attachAsset('healthBarBg', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarBg.y = -shadowGraphics.height / 2 - 15;
+ var healthBarFill = self.attachAsset('healthBarFill', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarFill.y = -shadowGraphics.height / 2 - 15;
+ self.update = function () {
+ var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
+ // Enrage when health is low
+ if (self.health <= self.maxHealth * 0.4 && !self.enraged) {
+ self.enraged = true;
+ self.speed *= 2;
+ shadowGraphics.tint = 0xff0000;
+ }
+ self.x += Math.cos(angle) * self.speed;
+ self.y += Math.sin(angle) * self.speed;
+ // Berserker effect when enraged
+ if (self.enraged) {
+ var shake = (Math.random() - 0.5) * 4;
+ self.x += shake;
+ self.y += shake;
+ // Pulsing red effect
+ var pulse = 1 + Math.sin(LK.ticks * 0.8) * 0.5;
+ shadowGraphics.scaleX = pulse;
+ shadowGraphics.scaleY = pulse;
+ }
+ // Update health bar
+ var healthPercent = self.health / self.maxHealth;
+ healthBarFill.scaleX = healthPercent;
+ healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
+ };
+ return self;
+});
var BomberShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('bomberShadow', {
anchorX: 0.5,
@@ -115,8 +164,62 @@
spellGraphics.alpha = self.lifetime / 30;
};
return self;
});
+var HealerShadow = Container.expand(function () {
+ var self = Container.call(this);
+ var shadowGraphics = self.attachAsset('healerShadow', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 0.8 + Math.random() * 0.5;
+ self.health = 3;
+ self.maxHealth = 3;
+ self.monsterType = 'healer';
+ self.lastHeal = 0;
+ self.healCooldown = 120; // 2 seconds
+ // Create health bar
+ var healthBarBg = self.attachAsset('healthBarBg', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarBg.y = -shadowGraphics.height / 2 - 15;
+ var healthBarFill = self.attachAsset('healthBarFill', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarFill.y = -shadowGraphics.height / 2 - 15;
+ self.update = function () {
+ var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
+ self.x += Math.cos(angle) * self.speed;
+ self.y += Math.sin(angle) * self.speed;
+ // Healing ability
+ if (LK.ticks - self.lastHeal > self.healCooldown) {
+ for (var i = 0; i < shadows.length; i++) {
+ var otherShadow = shadows[i];
+ if (otherShadow !== self) {
+ var distance = Math.sqrt(Math.pow(self.x - otherShadow.x, 2) + Math.pow(self.y - otherShadow.y, 2));
+ if (distance < 150 && otherShadow.health < otherShadow.maxHealth) {
+ otherShadow.health = Math.min(otherShadow.maxHealth, otherShadow.health + 1);
+ LK.effects.flashObject(otherShadow, 0x00ff00, 300);
+ self.lastHeal = LK.ticks;
+ break;
+ }
+ }
+ }
+ }
+ // Pulsing green effect
+ var pulse = 1 + Math.sin(LK.ticks * 0.4) * 0.3;
+ shadowGraphics.tint = 0x44ff44;
+ shadowGraphics.scaleX = pulse;
+ shadowGraphics.scaleY = pulse;
+ // Update health bar
+ var healthPercent = self.health / self.maxHealth;
+ healthBarFill.scaleX = healthPercent;
+ healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
+ };
+ return self;
+});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
@@ -158,8 +261,81 @@
self.lifetime--;
};
return self;
});
+var MimicShadow = Container.expand(function () {
+ var self = Container.call(this);
+ var shadowGraphics = self.attachAsset('mimicShadow', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 1.8 + Math.random() * 1.2;
+ self.health = 2;
+ self.maxHealth = 2;
+ self.monsterType = 'mimic';
+ self.lastCopy = 0;
+ self.copyCooldown = 240; // 4 seconds
+ self.copyTarget = null;
+ // Create health bar
+ var healthBarBg = self.attachAsset('healthBarBg', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarBg.y = -shadowGraphics.height / 2 - 15;
+ var healthBarFill = self.attachAsset('healthBarFill', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarFill.y = -shadowGraphics.height / 2 - 15;
+ self.update = function () {
+ var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
+ self.x += Math.cos(angle) * self.speed;
+ self.y += Math.sin(angle) * self.speed;
+ // Copy nearest enemy abilities
+ if (LK.ticks - self.lastCopy > self.copyCooldown) {
+ var nearestEnemy = null;
+ var nearestDistance = Infinity;
+ for (var i = 0; i < shadows.length; i++) {
+ var otherShadow = shadows[i];
+ if (otherShadow !== self && otherShadow.monsterType !== 'mimic') {
+ var distance = Math.sqrt(Math.pow(self.x - otherShadow.x, 2) + Math.pow(self.y - otherShadow.y, 2));
+ if (distance < 200 && distance < nearestDistance) {
+ nearestDistance = distance;
+ nearestEnemy = otherShadow;
+ }
+ }
+ }
+ if (nearestEnemy) {
+ self.copyTarget = nearestEnemy.monsterType;
+ self.lastCopy = LK.ticks;
+ // Visual feedback
+ LK.effects.flashObject(self, 0xff00ff, 500);
+ // Copy some properties
+ if (nearestEnemy.monsterType === 'fast') {
+ self.speed = nearestEnemy.speed;
+ shadowGraphics.tint = 0xffff00;
+ } else if (nearestEnemy.monsterType === 'tank') {
+ self.health = Math.min(self.maxHealth + 2, nearestEnemy.health);
+ shadowGraphics.tint = 0x888888;
+ } else if (nearestEnemy.monsterType === 'teleporter') {
+ shadowGraphics.tint = 0x8844ff;
+ }
+ }
+ }
+ // Rainbow shifting effect
+ var hue = LK.ticks * 0.05 % 1;
+ var r = Math.sin(hue * Math.PI * 2) * 127 + 128;
+ var g = Math.sin((hue + 0.33) * Math.PI * 2) * 127 + 128;
+ var b = Math.sin((hue + 0.66) * Math.PI * 2) * 127 + 128;
+ var color = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b);
+ shadowGraphics.tint = color;
+ // Update health bar
+ var healthPercent = self.health / self.maxHealth;
+ healthBarFill.scaleX = healthPercent;
+ healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
+ };
+ return self;
+});
var Shadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('shadow', {
anchorX: 0.5,
@@ -189,8 +365,64 @@
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
+var ShielderShadow = Container.expand(function () {
+ var self = Container.call(this);
+ var shadowGraphics = self.attachAsset('shielderShadow', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 1.2 + Math.random() * 0.8;
+ self.health = 4;
+ self.maxHealth = 4;
+ self.monsterType = 'shielder';
+ self.shieldActive = false;
+ self.lastShield = 0;
+ self.shieldCooldown = 180; // 3 seconds
+ self.shieldDuration = 120; // 2 seconds
+ self.shieldTimer = 0;
+ // Create health bar
+ var healthBarBg = self.attachAsset('healthBarBg', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarBg.y = -shadowGraphics.height / 2 - 15;
+ var healthBarFill = self.attachAsset('healthBarFill', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ healthBarFill.y = -shadowGraphics.height / 2 - 15;
+ self.update = function () {
+ var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
+ self.x += Math.cos(angle) * self.speed;
+ self.y += Math.sin(angle) * self.speed;
+ // Shield activation when damaged
+ if (self.health < self.maxHealth && !self.shieldActive && LK.ticks - self.lastShield > self.shieldCooldown) {
+ self.shieldActive = true;
+ self.shieldTimer = self.shieldDuration;
+ self.lastShield = LK.ticks;
+ shadowGraphics.tint = 0x4444ff;
+ }
+ // Shield timer
+ if (self.shieldActive) {
+ self.shieldTimer--;
+ if (self.shieldTimer <= 0) {
+ self.shieldActive = false;
+ shadowGraphics.tint = 0xffffff;
+ }
+ // Pulsing blue effect when shielded
+ var pulse = 1 + Math.sin(LK.ticks * 0.6) * 0.4;
+ shadowGraphics.scaleX = pulse;
+ shadowGraphics.scaleY = pulse;
+ }
+ // Update health bar
+ var healthPercent = self.health / self.maxHealth;
+ healthBarFill.scaleX = healthPercent;
+ healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
+ };
+ return self;
+});
var SplitterShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('splitterShadow', {
anchorX: 0.5,
@@ -443,9 +675,9 @@
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
// Add score based on monster type
- var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : 10;
+ var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
// Flash effect on each enemy before destruction
tween(shadow, {
alpha: 0
@@ -566,11 +798,14 @@
if (monsterRoll < 0.7) newShadow = new Shadow();else if (monsterRoll < 0.9) newShadow = new FastShadow();else newShadow = new TankShadow();
} else if (waveLevel < 6) {
// Mid waves: introduce more variety
if (monsterRoll < 0.4) newShadow = new Shadow();else if (monsterRoll < 0.6) newShadow = new FastShadow();else if (monsterRoll < 0.75) newShadow = new TankShadow();else if (monsterRoll < 0.9) newShadow = new SplitterShadow();else newShadow = new TeleporterShadow();
- } else {
+ } else if (waveLevel < 10) {
// Late waves: all monster types including dangerous ones
- if (monsterRoll < 0.25) newShadow = new Shadow();else if (monsterRoll < 0.4) newShadow = new FastShadow();else if (monsterRoll < 0.55) newShadow = new TankShadow();else if (monsterRoll < 0.7) newShadow = new SplitterShadow();else if (monsterRoll < 0.85) newShadow = new TeleporterShadow();else newShadow = new BomberShadow();
+ if (monsterRoll < 0.2) newShadow = new Shadow();else if (monsterRoll < 0.35) newShadow = new FastShadow();else if (monsterRoll < 0.5) newShadow = new TankShadow();else if (monsterRoll < 0.65) newShadow = new SplitterShadow();else if (monsterRoll < 0.75) newShadow = new TeleporterShadow();else if (monsterRoll < 0.85) newShadow = new BomberShadow();else if (monsterRoll < 0.92) newShadow = new HealerShadow();else newShadow = new ShielderShadow();
+ } else {
+ // Very late waves: all enemy types including new ones
+ if (monsterRoll < 0.15) newShadow = new Shadow();else if (monsterRoll < 0.25) newShadow = new FastShadow();else if (monsterRoll < 0.35) newShadow = new TankShadow();else if (monsterRoll < 0.45) newShadow = new SplitterShadow();else if (monsterRoll < 0.55) newShadow = new TeleporterShadow();else if (monsterRoll < 0.65) newShadow = new BomberShadow();else if (monsterRoll < 0.75) newShadow = new HealerShadow();else if (monsterRoll < 0.85) newShadow = new ShielderShadow();else if (monsterRoll < 0.93) newShadow = new BerserkerShadow();else newShadow = new MimicShadow();
}
// Spawn from random edge
var edge = Math.floor(Math.random() * 4);
switch (edge) {
@@ -651,9 +886,16 @@
// Check collision with shadows
for (var k = shadows.length - 1; k >= 0; k--) {
if (projectile.intersects(shadows[k])) {
var shadow = shadows[k];
- shadow.health -= damageBonusActive ? 2 : 1;
+ // Check if enemy is shielded
+ var damage = damageBonusActive ? 2 : 1;
+ if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
+ damage = 0; // No damage when shielded
+ LK.effects.flashObject(shadow, 0x4444ff, 100);
+ } else {
+ shadow.health -= damage;
+ }
var shadowDestroyed = false;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter' && shadow.health <= 0) {
@@ -680,9 +922,9 @@
game.addChild(newOrb);
shadow.destroy();
shadows.splice(k, 1);
shadowDestroyed = true;
- var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : 10;
+ var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
@@ -707,9 +949,15 @@
for (var m = shadows.length - 1; m >= 0; m--) {
var distance = Math.sqrt(Math.pow(spell.x - shadows[m].x, 2) + Math.pow(spell.y - shadows[m].y, 2));
if (distance < spell.radius) {
var shadow = shadows[m];
- shadow.health -= damageBonusActive ? 4 : 2; // Fire spells do more damage
+ // Check if enemy is shielded
+ var damage = damageBonusActive ? 4 : 2; // Fire spells do more damage
+ if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
+ damage = Math.ceil(damage / 2); // Reduced damage when shielded
+ LK.effects.flashObject(shadow, 0x4444ff, 100);
+ }
+ shadow.health -= damage;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter') {
// Create two smaller fast shadows
@@ -734,9 +982,9 @@
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(m, 1);
- var scoreValue = shadow.monsterType === 'tank' ? 30 : shadow.monsterType === 'splitter' ? 35 : shadow.monsterType === 'teleporter' ? 25 : shadow.monsterType === 'bomber' ? 40 : 15;
+ var scoreValue = shadow.monsterType === 'tank' ? 30 : shadow.monsterType === 'splitter' ? 35 : shadow.monsterType === 'teleporter' ? 25 : shadow.monsterType === 'bomber' ? 40 : shadow.monsterType === 'healer' ? 45 : shadow.monsterType === 'shielder' ? 40 : shadow.monsterType === 'berserker' ? 50 : shadow.monsterType === 'mimic' ? 55 : 15;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
bola de fuego de pixeles. In-Game asset. 2d. High contrast. No shadows
monstruo de slime negro de pixeles. In-Game asset. 2d. High contrast. No shadows
suelo de sesped oscuro de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de luz de pixeles. In-Game asset. 2d. High contrast. No shadows
sombra de pixeles que de miedo. In-Game asset. 2d. High contrast. No shadows
portal de pixeles de luz. In-Game asset. 2d. High contrast. No shadows
angel en forma de ojo de pixeles. In-Game asset. 2d. High contrast. No shadows
que ahora tenga una exprecion de determinacion
fuego negro de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de luz azul de pixeles. In-Game asset. 2d. High contrast. No shadows
la muerte de pixeles. In-Game asset. 2d. High contrast. No shadows
orbe oscuro de pixeles con cara enojada. In-Game asset. 2d. High contrast. No shadows
berserquer de pixeles. In-Game asset. 2d. High contrast. No shadows
sombra mimica de pixeles. In-Game asset. 2d. High contrast. No shadows
casa de madera con barricadas de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de hielo de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de viento de pixeles. In-Game asset. 2d. High contrast. No shadows