User prompt
Enemies instantly break the crystal wall, make it a little stronger and when you use the power called show and hit the enemy, he becomes immortal, fix this bug
User prompt
Please fix the bug: 'TypeError: this.destroy is not a function' in or related to this line: 'this.destroy();' Line Number: 635
User prompt
🔥✨ Spell Powers & Their Mystical Effects ✨🔥 1. 🔥 Fireball — “Inferno’s Wrath” Unleash a blazing orb of fire that erupts on impact, engulfing foes in searing flames. [🔥 DAMAGE OVER AREA] 2. ❄️ Ice Shard — “Frostbite’s Sting” Hurl razor-sharp shards of ice that pierce and freeze enemies, slowing their movements. [🐢 ENEMY SLOWED + DAMAGE] 3. ⚡ Lightning Strike — “Storm’s Judgment” Summon a sudden lightning bolt from the heavens to strike a single target with deadly force. [💥 HIGH SINGLE TARGET DAMAGE] 4. 🛡️ Magical Shield — “Aegis of the Arcane” Envelop yourself in a shimmering shield that absorbs damage, protecting you from harm. [🛡️ TEMPORARY DAMAGE ABSORPTION] 5. 💨 Teleport — “Blink of Shadows” Vanish and instantly reappear a short distance away, evading danger with ghostlike speed. [⚡ INSTANT REPOSITION] 6. ☠️ Poison Cloud — “Venomous Mist” Release a toxic fog that lingers, slowly corroding and weakening all who dare enter. [☣️ DAMAGE OVER TIME + WEAKENING EFFECT] 7. 🧠 Mind Control — “Dominion of Will” Seize control of an enemy’s mind, bending their will to fight alongside you—for a fleeting moment. [🧟 TEMPORARY ENEMY ALLY] 8. 🔮 Crystal Wall — “Barrier of Eternity” Summon a towering wall of crystal to block enemies and projectiles, halting their advance. [⛔ BLOCKS MOVEMENT & ATTACKS] 9. 💥 Explosion — “Cataclysmic Burst” Detonate a devastating blast around you, obliterating all foes in a violent radius. [💣 MASSIVE AREA DAMAGE] 10. ⏳ Time Slow — “Chrono’s Embrace” Bend the flow of time itself, slowing enemies’ movements and attacks, granting you precious seconds. [🐌 ENEMY SLOWED FOR SHORT DURATION] --- Prepare wisely, Wizard—each spell is a shard of untamed power, a tool to twist fate itself. Choose your arsenal, strike with precision, and survive the relentless onslaught of darkness! ✨🧙♂️ ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a pixel health bar
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'buttonText.style.fill = "#FFFFFF";' Line Number: 309
Code edit (1 edits merged)
Please save this source code
User prompt
Arcane Survival: Wizard's Last Stand
Initial prompt
🧙♂️ "You play as a powerful wizard who can cast 10 unique magical spells: fireball, ice shard, lightning strike, magical shield, teleport, poison cloud, mind control, crystal wall, explosion, and time slow. Waves of different enemies attack you from all directions, including goblins, demons, flying eyes, golems, skeletons, poisonous mushrooms, hellhounds, and dark sorcerers. Your goal is to survive as long as possible by strategically using your spells." 🎮 Genre: Arena Survival / Action 🎨 Style: Pixel Art / Dark Fantasy 🔥 Spells: Fireball, Ice Shard, Lightning Strike, Shield, Teleport, Poison Cloud, Mind Control, Crystal Wall, Explosion, Time Slow 👾 Enemies: Goblins, Demons, Flying Eyes, Golems, Skeletons, Poisonous Mushrooms, Hellhounds, Dark Sorcerers
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function (enemyType) { var self = Container.call(this); self.enemyType = enemyType; self.health = 1; self.speed = 2; self.damage = 1; self.points = 10; self.lastHitTime = 0; self.slowedTimer = 0; self.originalSpeed = 0; self.poisonedTimer = 0; self.poisonDamageTimer = 0; var enemyGraphics; if (enemyType === 'goblin') { enemyGraphics = self.attachAsset('goblin', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.speed = 3; self.points = 10; } else if (enemyType === 'demon') { enemyGraphics = self.attachAsset('demon', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.speed = 1.5; self.points = 30; } else if (enemyType === 'flyingEye') { enemyGraphics = self.attachAsset('flyingEye', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.speed = 4; self.points = 20; } else if (enemyType === 'golem') { enemyGraphics = self.attachAsset('golem', { anchorX: 0.5, anchorY: 0.5 }); self.health = 5; self.speed = 1; self.points = 50; } else if (enemyType === 'skeleton') { enemyGraphics = self.attachAsset('skeleton', { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; self.speed = 2; self.points = 20; } else if (enemyType === 'mushroom') { enemyGraphics = self.attachAsset('mushroom', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.speed = 1; self.points = 15; } else if (enemyType === 'hellhound') { enemyGraphics = self.attachAsset('hellhound', { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; self.speed = 5; self.points = 25; } else if (enemyType === 'darkSorcerer') { enemyGraphics = self.attachAsset('darkSorcerer', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.speed = 1.5; self.points = 40; } self.maxHealth = self.health; // Spawn from random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // Top self.x = Math.random() * 2048; self.y = -50; } else if (edge === 1) { // Right self.x = 2048 + 50; self.y = Math.random() * 2732; } else if (edge === 2) { // Bottom self.x = Math.random() * 2048; self.y = 2732 + 50; } else { // Left self.x = -50; self.y = Math.random() * 2732; } self.applySlowEffect = function () { if (self.slowedTimer <= 0) { self.originalSpeed = self.speed; } self.slowedTimer = 180; // 3 seconds self.speed = self.originalSpeed * 0.3; // 70% speed reduction tween(enemyGraphics, { tint: 0x87CEEB }, { duration: 200 }); }; self.stunTimer = 0; self.applyStunEffect = function () { self.stunTimer = 42; // 0.7 seconds at 60fps if (!self.originalSpeed) { self.originalSpeed = self.speed; } self.speed = 0; // Complete stop when stunned tween(enemyGraphics, { tint: 0xFFFF00 }, { duration: 200 }); }; self.applyPoisonEffect = function () { self.poisonedTimer = 120; // 2 seconds at 60fps self.poisonDamageTimer = 0; // Reset damage timer tween(enemyGraphics, { tint: 0x00FF00 // Green tint for poison }, { duration: 200 }); }; self.takeDamage = function (damage) { // Prevent taking damage if already dead if (self.health <= 0) { return true; } self.health -= damage; self.lastHitTime = LK.ticks; // Flash red when hit tween(enemyGraphics, { tint: 0xFF0000 }, { duration: 100, onFinish: function onFinish() { tween(enemyGraphics, { tint: 0xFFFFFF }, { duration: 100 }); } }); LK.getSound('enemyHit').play(); if (self.health <= 0) { self.health = 0; // Ensure health doesn't go negative return true; // Enemy is dead } return false; }; self.update = function () { // Handle stun effect if (self.stunTimer > 0) { self.stunTimer--; if (self.stunTimer <= 0) { self.speed = self.originalSpeed || self.speed; tween(enemyGraphics, { tint: 0xFFFFFF }, { duration: 200 }); } return; // Don't move while stunned } // Handle slow effect if (self.slowedTimer > 0) { self.slowedTimer--; if (self.slowedTimer <= 0) { self.speed = self.originalSpeed; tween(enemyGraphics, { tint: 0xFFFFFF }, { duration: 200 }); } } // Handle poison effect if (self.poisonedTimer > 0) { self.poisonedTimer--; self.poisonDamageTimer++; // Deal damage every 18 frames (0.3 seconds at 60fps) if (self.poisonDamageTimer >= 18) { self.poisonDamageTimer = 0; self.takeDamage(1); // Small poison damage } // Remove poison effect when timer expires if (self.poisonedTimer <= 0) { tween(enemyGraphics, { tint: 0xFFFFFF }, { duration: 200 }); } } // Move towards wizard var dx = wizard.x - self.x; var dy = wizard.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveX = dx / distance * self.speed; var moveY = dy / distance * self.speed; // Flying eye has erratic movement if (self.enemyType === 'flyingEye') { moveX += (Math.random() - 0.5) * 2; moveY += (Math.random() - 0.5) * 2; } self.x += moveX; self.y += moveY; } }; return self; }); var Spell = Container.expand(function (spellType, startX, startY, targetX, targetY) { var self = Container.call(this); self.spellType = spellType; self.speed = 8; self.damage = 1; self.lifeTime = 180; // 3 seconds at 60fps self.age = 0; var spellGraphics; if (spellType === 'fireball') { spellGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 2; } else if (spellType === 'iceShard') { spellGraphics = self.attachAsset('iceShard', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 1; self.slowEffect = true; } else if (spellType === 'lightning') { spellGraphics = self.attachAsset('lightning', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 3; self.speed = 15; } else if (spellType === 'poisonCloud') { spellGraphics = self.attachAsset('poisonCloud', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 1; self.speed = 0; self.lifeTime = 210; // 3.5 seconds total duration (210 frames at 60fps) self.lastDamageTick = 0; self.damageInterval = 18; // Damage every 0.3 seconds (18 frames at 60fps) spellGraphics.alpha = 0.6; } else if (spellType === 'explosion') { spellGraphics = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 4; self.speed = 0; self.lifeTime = 30; spellGraphics.alpha = 0.8; } self.x = startX; self.y = startY; // Calculate direction var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.velocityX = dx / distance * self.speed; self.velocityY = dy / distance * self.speed; } else { self.velocityX = 0; self.velocityY = 0; } self.createExplosion = function () { var explosion = new Spell('explosion', self.x, self.y, self.x, self.y); spells.push(explosion); game.addChild(explosion); }; self.update = function () { self.age++; if (self.spellType !== 'poisonCloud' && self.spellType !== 'explosion') { self.x += self.velocityX; self.y += self.velocityY; } if (self.spellType === 'explosion') { var scale = 1 + self.age / 30 * 2; spellGraphics.scaleX = scale; spellGraphics.scaleY = scale; } }; return self; }); var SpellButton = Container.expand(function (spellType, buttonX, buttonY) { var self = Container.call(this); self.spellType = spellType; self.cooldown = 0; self.maxCooldown = 60; // 1 second self.manaCost = 10; // Default mana cost var buttonBg = self.attachAsset('spellButton', { anchorX: 0.5, anchorY: 0.5 }); var spellNames = { 'fireball': 'Fire', 'iceShard': 'Ice', 'lightning': 'Bolt', 'shield': 'Shield', 'teleport': 'Port', 'poisonCloud': 'Poison', 'mindControl': 'Mind', 'explosion': 'Boom', 'timeSlow': 'Stop', 'storm': 'Storm', 'manaRestorer': 'Restore', 'heal': 'Heal' }; var buttonText = new Text2(spellNames[spellType] || spellType, { size: 32, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.spellName = spellNames[spellType] || spellType; self.x = buttonX; self.y = buttonY; // Set different cooldowns and mana costs for different spells if (spellType === 'fireball') { self.maxCooldown = 30; self.manaCost = 15; } else if (spellType === 'iceShard') { self.maxCooldown = 25; self.manaCost = 10; } else if (spellType === 'lightning') { self.maxCooldown = 45; self.manaCost = 25; } else if (spellType === 'shield') { self.maxCooldown = 180; self.manaCost = 40; } else if (spellType === 'teleport') { self.maxCooldown = 120; self.manaCost = 30; } else if (spellType === 'poisonCloud') { self.maxCooldown = 390; // 6.5 seconds at 60fps self.manaCost = 35; } else if (spellType === 'mindControl') { self.maxCooldown = 150; self.manaCost = 50; } else if (spellType === 'explosion') { self.maxCooldown = 80; self.manaCost = 45; } else if (spellType === 'timeSlow') { self.maxCooldown = 270; // 4.5 seconds self.manaCost = 60; } else if (spellType === 'storm') { self.maxCooldown = 522; // 8.7 seconds self.manaCost = 70; } else if (spellType === 'manaRestorer') { self.maxCooldown = 1000; // 10 seconds self.manaCost = 0; // No mana cost } else if (spellType === 'heal') { self.maxCooldown = 1200; // 20 seconds at 60fps self.manaCost = 130; } self.canCast = function () { if (self.spellType === 'manaRestorer') { return self.cooldown <= 0; // Mana restorer ignores mana cost and incapacity } return self.cooldown <= 0 && wizardMana >= self.manaCost && incapacityTimer <= 0; }; self.cast = function () { if (self.canCast()) { self.cooldown = self.maxCooldown; return true; } return false; }; self.update = function () { if (self.cooldown > 0) { self.cooldown--; buttonBg.tint = 0x666666; buttonText.fill = 0x999999; // Show cooldown duration var cooldownSeconds = Math.ceil(self.cooldown / 60); buttonText.setText(cooldownSeconds + 's'); } else if (self.spellType !== 'manaRestorer' && incapacityTimer > 0) { // Incapacitated - show red tint buttonBg.tint = 0xFF4444; buttonText.fill = 0xFF8888; var incapacitySeconds = Math.ceil(incapacityTimer / 60); buttonText.setText('Inc: ' + incapacitySeconds + 's'); } else if (wizardMana < self.manaCost) { // Not enough mana - show blue tint buttonBg.tint = 0x4444FF; buttonText.fill = 0x8888FF; buttonText.setText(self.spellName); } else { buttonBg.tint = 0xFFFFFF; buttonText.fill = 0xFFFFFF; buttonText.setText(self.spellName); } }; self.down = function (x, y, obj) { if (self.canCast()) { castSpell(self.spellType); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game variables // Wizard // Spells // Enemies // UI Elements // Sounds var wizard; var enemies = []; var spells = []; var spellButtons = []; var waveNumber = 1; var enemiesSpawned = 0; var enemiesPerWave = 5; var spawnTimer = 0; var spawnDelay = 120; // 2 seconds var gameTime = 0; var shieldActive = false; var shieldObject = null; var timeSlowActive = false; var timeSlowTimer = 0; var stormActive = false; var stormTimer = 0; var stormObject = null; var wizardHealth = 100; var wizardMaxHealth = 100; var wizardMana = 180; var wizardMaxMana = 180; var manaRegenRate = 0.1; // Mana regenerated per frame var incapacityTimer = 0; // Timer for power incapacity after mana restorer var poisonCloudCooldown = 0; // 6.5 second cooldown for poison cloud var stormParticles = []; // Track storm particles var healthBar = null; var healthBarFill = null; var manaBar = null; var manaBarFill = null; // Enemy types for spawning var enemyTypes = ['goblin', 'demon', 'flyingEye', 'golem', 'skeleton', 'mushroom', 'hellhound', 'darkSorcerer']; // Create wizard wizard = game.addChild(new Container()); var wizardGraphics = wizard.attachAsset('wizard', { anchorX: 0.5, anchorY: 0.5 }); wizard.x = 1024; wizard.y = 1366; // Create spell buttons var spellTypes = ['fireball', 'iceShard', 'lightning', 'shield', 'teleport', 'poisonCloud', 'mindControl', 'explosion', 'timeSlow', 'storm', 'manaRestorer', 'heal']; for (var i = 0; i < spellTypes.length; i++) { var buttonX = 150 + i % 6 * 180; // Increased horizontal spacing for larger buttons var buttonY = 2450 + Math.floor(i / 6) * 130; // Increased vertical spacing and moved up slightly var button = new SpellButton(spellTypes[i], buttonX, buttonY); spellButtons.push(button); game.addChild(button); } // Create score display var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 150; scoreTxt.y = 100; game.addChild(scoreTxt); // Create wave display var waveTxt = new Text2('Wave: 1', { size: 50, fill: 0xFFFF00 }); waveTxt.anchor.set(0, 0); waveTxt.x = 150; waveTxt.y = 180; game.addChild(waveTxt); // Create health bar healthBar = game.addChild(new Container()); var healthBarBg = healthBar.attachAsset('healthBarBg', { anchorX: 0, anchorY: 0 }); healthBarFill = healthBar.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0 }); healthBar.x = 150; healthBar.y = 250; // Health bar text var healthTxt = new Text2('Health: 100/100', { size: 40, fill: 0xFFFFFF }); healthTxt.anchor.set(0, 0); healthTxt.x = 150; healthTxt.y = 280; game.addChild(healthTxt); // Create mana bar manaBar = game.addChild(new Container()); var manaBarBg = manaBar.attachAsset('manaBarBg', { anchorX: 0, anchorY: 0 }); manaBarFill = manaBar.attachAsset('manaBarFill', { anchorX: 0, anchorY: 0 }); manaBar.x = 150; manaBar.y = 330; // Mana bar text var manaTxt = new Text2('Mana: 180/180', { size: 40, fill: 0x0080FF }); manaTxt.anchor.set(0, 0); manaTxt.x = 150; manaTxt.y = 360; game.addChild(manaTxt); function castSpell(spellType) { // Find the button and check cooldown var button = null; for (var i = 0; i < spellButtons.length; i++) { if (spellButtons[i].spellType === spellType) { button = spellButtons[i]; break; } } if (!button || !button.cast()) { return; } // Consume mana wizardMana -= button.manaCost; if (wizardMana < 0) { wizardMana = 0; } // Update mana display var manaPercent = wizardMana / wizardMaxMana; manaBarFill.scaleX = manaPercent; manaTxt.setText('Mana: ' + Math.floor(wizardMana) + '/' + wizardMaxMana); LK.getSound('spellCast').play(); if (spellType === 'shield') { activateShield(); } else if (spellType === 'teleport') { teleportWizard(); } else if (spellType === 'timeSlow') { activateTimeSlow(); } else if (spellType === 'mindControl') { mindControlEnemies(); } else if (spellType === 'explosion') { // Explosion at wizard location var spell = new Spell(spellType, wizard.x, wizard.y, wizard.x, wizard.y); spells.push(spell); game.addChild(spell); } else if (spellType === 'storm') { activateStorm(); } else if (spellType === 'manaRestorer') { activateManaRestorer(); } else if (spellType === 'heal') { activateHeal(); } else { // Targeted spells - cast towards nearest enemy var nearestEnemy = findNearestEnemy(); if (nearestEnemy) { var spell = new Spell(spellType, wizard.x, wizard.y, nearestEnemy.x, nearestEnemy.y); spell.targetX = nearestEnemy.x; spell.targetY = nearestEnemy.y; spells.push(spell); game.addChild(spell); } } } function findNearestEnemy() { var nearest = null; var minDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var dx = enemies[i].x - wizard.x; var dy = enemies[i].y - wizard.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance) { minDistance = distance; nearest = enemies[i]; } } return nearest; } function activateShield() { if (shieldObject) { shieldObject.destroy(); } shieldObject = game.addChild(new Container()); var shieldGraphics = shieldObject.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5 }); shieldGraphics.alpha = 0.5; shieldActive = true; LK.setTimeout(function () { if (shieldObject) { shieldObject.destroy(); shieldObject = null; } shieldActive = false; }, 3000); } function teleportWizard() { // Teleport to a safe random location var attempts = 0; var newX, newY; do { newX = 200 + Math.random() * (2048 - 400); newY = 200 + Math.random() * (2200 - 400); attempts++; } while (attempts < 10 && isLocationUnsafe(newX, newY)); wizard.x = newX; wizard.y = newY; // Teleport effect LK.effects.flashObject(wizard, 0x00FFFF, 500); } function isLocationUnsafe(x, y) { for (var i = 0; i < enemies.length; i++) { var dx = enemies[i].x - x; var dy = enemies[i].y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { return true; } } return false; } function activateTimeSlow() { timeSlowActive = true; timeSlowTimer = 90; // 1.5 seconds LK.effects.flashScreen(0x0066FF, 200); // Visual effect on all enemies - freeze them completely for (var i = 0; i < enemies.length; i++) { if (!enemies[i].originalSpeed) { enemies[i].originalSpeed = enemies[i].speed; } enemies[i].speed = 0; // Complete stop tween(enemies[i], { tint: 0x6666FF }, { duration: 300 }); } } function activateStorm() { stormActive = true; stormTimer = 210; // 3.5 seconds at 60fps // Create storm object that follows wizard if (stormObject) { stormObject.destroy(); } stormObject = game.addChild(new Container()); var stormGraphics = stormObject.attachAsset('stormEffect', { anchorX: 0.5, anchorY: 0.5 }); stormGraphics.alpha = 0.8; // Clear existing storm particles for (var p = 0; p < stormParticles.length; p++) { if (stormParticles[p]) { stormParticles[p].destroy(); } } stormParticles = []; // Create storm particles around wizard that follow the storm for (var i = 0; i < 8; i++) { var particle = game.addChild(new Container()); var particleGraphics = particle.attachAsset('iceShard', { anchorX: 0.5, anchorY: 0.5 }); particleGraphics.scaleX = 0.3; particleGraphics.scaleY = 0.3; particleGraphics.tint = 0x87CEEB; particle.x = wizard.x; particle.y = wizard.y; particle.angle = i / 8 * Math.PI * 2; particle.baseRadius = 100 + i * 20; particle.rotationSpeed = 0.1; stormParticles.push(particle); } // Start wizard spinning and shrinking animation tween(wizard, { rotation: Math.PI * 14, // 7 full rotations over 3.5 seconds scaleX: 0.6, // Shrink to 60% size scaleY: 0.6 }, { duration: 3500, easing: tween.linear }); // Visual storm effect LK.effects.flashScreen(0x4169E1, 300); } function activateManaRestorer() { // Instantly restore full mana wizardMana = wizardMaxMana; // Update mana display var manaPercent = wizardMana / wizardMaxMana; manaBarFill.scaleX = manaPercent; manaTxt.setText('Mana: ' + Math.floor(wizardMana) + '/' + wizardMaxMana); // Add 6 seconds of incapacity to all powers incapacityTimer = 432; // 6 seconds at 60fps // Visual effect LK.effects.flashObject(wizard, 0x00FFFF, 1000); LK.effects.flashScreen(0x00FFFF, 300); } function activateHeal() { // Restore to exactly 100 health (full health) wizardHealth = 100; wizardMaxHealth = 100; // Ensure max health is also 100 // Update health bar var healthPercent = wizardHealth / wizardMaxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Update health text healthTxt.setText('Health: ' + wizardHealth + '/' + wizardMaxHealth); // Visual healing effect LK.effects.flashObject(wizard, 0x00FF00, 1000); tween(wizard, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(wizard, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn }); } }); } function mindControlEnemies() { var controlled = 0; for (var i = 0; i < enemies.length && controlled < 3; i++) { var dx = enemies[i].x - wizard.x; var dy = enemies[i].y - wizard.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 300) { // Mind control effect - purple flash then instant kill tween(enemies[i], { tint: 0x9932CC }, { duration: 200, onFinish: function onFinish() { tween(this, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, onFinish: function onFinish() { enemies[i].takeDamage(enemies[i].health); } }); } }); controlled++; } } } function damageWizard(damage) { wizardHealth -= damage; if (wizardHealth < 0) { wizardHealth = 0; } // Update health bar var healthPercent = wizardHealth / wizardMaxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } // Update health text healthTxt.setText('Health: ' + wizardHealth + '/' + wizardMaxHealth); if (wizardHealth <= 0) { LK.effects.flashScreen(0xFF0000, 500); LK.showGameOver(); } } function spawnEnemy() { if (enemiesSpawned < enemiesPerWave) { var enemyType = enemyTypes[Math.floor(Math.random() * Math.min(enemyTypes.length, 2 + Math.floor(waveNumber / 2)))]; var enemy = new Enemy(enemyType); enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } } function checkCollisions() { // Spells vs Enemies for (var s = spells.length - 1; s >= 0; s--) { var spell = spells[s]; // Area damage spells (explosion, poison cloud) if (spell.spellType === 'explosion' || spell.spellType === 'poisonCloud') { for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; var dx = enemy.x - spell.x; var dy = enemy.y - spell.y; var distance = Math.sqrt(dx * dx + dy * dy); var damageRadius = spell.spellType === 'explosion' ? 120 : 80; if (distance < damageRadius) { // For poison cloud, only damage at intervals and apply poison effect if (spell.spellType === 'poisonCloud') { if (spell.age - spell.lastDamageTick >= spell.damageInterval) { spell.lastDamageTick = spell.age; var isDead = enemy.takeDamage(spell.damage); enemy.applyPoisonEffect(); // Apply poison effect if (isDead) { LK.setScore(LK.getScore() + enemy.points); scoreTxt.setText('Score: ' + LK.getScore()); enemy.destroy(); enemies.splice(e, 1); LK.getSound('enemyDeath').play(); } } } else { // Explosion deals instant damage var isDead = enemy.takeDamage(spell.damage); if (isDead) { LK.setScore(LK.getScore() + enemy.points); scoreTxt.setText('Score: ' + LK.getScore()); enemy.destroy(); enemies.splice(e, 1); LK.getSound('enemyDeath').play(); } } } } } else { // Single target spells for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; if (spell.intersects && spell.intersects(enemy)) { // Apply ice shard slow effect with blue tint if (spell.slowEffect) { enemy.applySlowEffect(); } var isDead = enemy.takeDamage(spell.damage); if (isDead) { LK.setScore(LK.getScore() + enemy.points); scoreTxt.setText('Score: ' + LK.getScore()); enemy.destroy(); enemies.splice(e, 1); LK.getSound('enemyDeath').play(); } // Fireball creates explosion on impact if (spell.spellType === 'fireball') { spell.createExplosion(); } if (spell.spellType !== 'poisonCloud') { spell.destroy(); spells.splice(s, 1); break; } } } } } // Enemies vs Wizard for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; if (enemy.intersects && enemy.intersects(wizard)) { if (!shieldActive) { // Only damage if enough time has passed since last hit if (LK.ticks - enemy.lastHitTime > 60) { // 1 second cooldown damageWizard(enemy.damage * 10); // Scale damage for visibility enemy.lastHitTime = LK.ticks; } } else { // Shield absorbs hit enemy.destroy(); enemies.splice(e, 1); if (shieldObject) { shieldObject.destroy(); shieldObject = null; shieldActive = false; } } } } // Storm vs Enemies if (stormActive && stormObject) { for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; var dx = enemy.x - stormObject.x; var dy = enemy.y - stormObject.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 560) { // Storm radius // Push enemy back strongly var pushDistance = 145; if (distance > 0) { enemy.x += dx / distance * pushDistance; enemy.y += dy / distance * pushDistance; } // Deal small damage every 10 frames (6 times per second) if (LK.ticks % 10 === 0) { var isDead = enemy.takeDamage(1); if (isDead) { LK.setScore(LK.getScore() + enemy.points); scoreTxt.setText('Score: ' + LK.getScore()); enemy.destroy(); enemies.splice(e, 1); LK.getSound('enemyDeath').play(); } } } } } } game.move = function (x, y, obj) { if (x > 100 && x < 1948 && y > 100 && y < 2200) { wizard.x = x; wizard.y = y; } }; game.update = function () { gameTime++; // Update incapacity timer if (incapacityTimer > 0) { incapacityTimer--; } // Update poison cloud cooldown if (poisonCloudCooldown > 0) { poisonCloudCooldown--; } // Regenerate mana if (wizardMana < wizardMaxMana) { wizardMana += manaRegenRate; if (wizardMana > wizardMaxMana) { wizardMana = wizardMaxMana; } // Update mana display var manaPercent = wizardMana / wizardMaxMana; manaBarFill.scaleX = manaPercent; manaTxt.setText('Mana: ' + Math.floor(wizardMana) + '/' + wizardMaxMana); } // Update time slow if (timeSlowActive) { timeSlowTimer--; if (timeSlowTimer <= 0) { timeSlowActive = false; } } // Update storm if (stormActive) { stormTimer--; if (stormObject) { stormObject.x = wizard.x; stormObject.y = wizard.y; } // Update storm particles to follow storm for (var p = 0; p < stormParticles.length; p++) { if (stormParticles[p]) { var particle = stormParticles[p]; particle.angle += particle.rotationSpeed; particle.x = wizard.x + Math.cos(particle.angle) * particle.baseRadius; particle.y = wizard.y + Math.sin(particle.angle) * particle.baseRadius; particle.rotation += 0.2; } } if (stormTimer <= 0) { stormActive = false; if (stormObject) { stormObject.destroy(); stormObject = null; } // Destroy all storm particles for (var p = 0; p < stormParticles.length; p++) { if (stormParticles[p]) { stormParticles[p].destroy(); } } stormParticles = []; // Stop wizard spinning and restore size tween.stop(wizard, { rotation: true, scaleX: true, scaleY: true }); // Animate wizard back to normal size tween(wizard, { scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 500, easing: tween.easeOut }); } } // Update shield position if (shieldObject) { shieldObject.x = wizard.x; shieldObject.y = wizard.y; } // Spawn enemies spawnTimer++; var actualSpawnDelay = timeSlowActive ? spawnDelay * 2 : spawnDelay; if (spawnTimer >= actualSpawnDelay) { spawnEnemy(); spawnTimer = 0; } // Update spells for (var s = spells.length - 1; s >= 0; s--) { var spell = spells[s]; spell.age++; if (spell.age >= spell.lifeTime || spell.x < -100 || spell.x > 2148 || spell.y < -100 || spell.y > 2832) { spell.destroy(); spells.splice(s, 1); } } // Update enemies with time stop effect for (var e = 0; e < enemies.length; e++) { if (timeSlowActive && !enemies[e].timeSlowApplied) { if (!enemies[e].originalSpeed) { enemies[e].originalSpeed = enemies[e].speed; } enemies[e].speed = 0; // Complete stop enemies[e].timeSlowApplied = true; } else if (!timeSlowActive && enemies[e].timeSlowApplied) { enemies[e].speed = enemies[e].originalSpeed || enemies[e].speed; enemies[e].timeSlowApplied = false; // Restore normal tint tween(enemies[e], { tint: 0xFFFFFF }, { duration: 200 }); } } // Check for wave completion if (enemiesSpawned >= enemiesPerWave && enemies.length === 0) { waveNumber++; enemiesSpawned = 0; enemiesPerWave = 5 + waveNumber * 2; spawnDelay = Math.max(30, 120 - waveNumber * 5); waveTxt.setText('Wave: ' + waveNumber); // Bonus points for completing wave LK.setScore(LK.getScore() + waveNumber * 50); scoreTxt.setText('Score: ' + LK.getScore()); } checkCollisions(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
self.enemyType = enemyType;
self.health = 1;
self.speed = 2;
self.damage = 1;
self.points = 10;
self.lastHitTime = 0;
self.slowedTimer = 0;
self.originalSpeed = 0;
self.poisonedTimer = 0;
self.poisonDamageTimer = 0;
var enemyGraphics;
if (enemyType === 'goblin') {
enemyGraphics = self.attachAsset('goblin', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 3;
self.points = 10;
} else if (enemyType === 'demon') {
enemyGraphics = self.attachAsset('demon', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.speed = 1.5;
self.points = 30;
} else if (enemyType === 'flyingEye') {
enemyGraphics = self.attachAsset('flyingEye', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 4;
self.points = 20;
} else if (enemyType === 'golem') {
enemyGraphics = self.attachAsset('golem', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 5;
self.speed = 1;
self.points = 50;
} else if (enemyType === 'skeleton') {
enemyGraphics = self.attachAsset('skeleton', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 2;
self.points = 20;
} else if (enemyType === 'mushroom') {
enemyGraphics = self.attachAsset('mushroom', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 1;
self.points = 15;
} else if (enemyType === 'hellhound') {
enemyGraphics = self.attachAsset('hellhound', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 5;
self.points = 25;
} else if (enemyType === 'darkSorcerer') {
enemyGraphics = self.attachAsset('darkSorcerer', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.speed = 1.5;
self.points = 40;
}
self.maxHealth = self.health;
// Spawn from random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// Top
self.x = Math.random() * 2048;
self.y = -50;
} else if (edge === 1) {
// Right
self.x = 2048 + 50;
self.y = Math.random() * 2732;
} else if (edge === 2) {
// Bottom
self.x = Math.random() * 2048;
self.y = 2732 + 50;
} else {
// Left
self.x = -50;
self.y = Math.random() * 2732;
}
self.applySlowEffect = function () {
if (self.slowedTimer <= 0) {
self.originalSpeed = self.speed;
}
self.slowedTimer = 180; // 3 seconds
self.speed = self.originalSpeed * 0.3; // 70% speed reduction
tween(enemyGraphics, {
tint: 0x87CEEB
}, {
duration: 200
});
};
self.stunTimer = 0;
self.applyStunEffect = function () {
self.stunTimer = 42; // 0.7 seconds at 60fps
if (!self.originalSpeed) {
self.originalSpeed = self.speed;
}
self.speed = 0; // Complete stop when stunned
tween(enemyGraphics, {
tint: 0xFFFF00
}, {
duration: 200
});
};
self.applyPoisonEffect = function () {
self.poisonedTimer = 120; // 2 seconds at 60fps
self.poisonDamageTimer = 0; // Reset damage timer
tween(enemyGraphics, {
tint: 0x00FF00 // Green tint for poison
}, {
duration: 200
});
};
self.takeDamage = function (damage) {
// Prevent taking damage if already dead
if (self.health <= 0) {
return true;
}
self.health -= damage;
self.lastHitTime = LK.ticks;
// Flash red when hit
tween(enemyGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.health = 0; // Ensure health doesn't go negative
return true; // Enemy is dead
}
return false;
};
self.update = function () {
// Handle stun effect
if (self.stunTimer > 0) {
self.stunTimer--;
if (self.stunTimer <= 0) {
self.speed = self.originalSpeed || self.speed;
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
return; // Don't move while stunned
}
// Handle slow effect
if (self.slowedTimer > 0) {
self.slowedTimer--;
if (self.slowedTimer <= 0) {
self.speed = self.originalSpeed;
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
}
// Handle poison effect
if (self.poisonedTimer > 0) {
self.poisonedTimer--;
self.poisonDamageTimer++;
// Deal damage every 18 frames (0.3 seconds at 60fps)
if (self.poisonDamageTimer >= 18) {
self.poisonDamageTimer = 0;
self.takeDamage(1); // Small poison damage
}
// Remove poison effect when timer expires
if (self.poisonedTimer <= 0) {
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
}
// Move towards wizard
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
// Flying eye has erratic movement
if (self.enemyType === 'flyingEye') {
moveX += (Math.random() - 0.5) * 2;
moveY += (Math.random() - 0.5) * 2;
}
self.x += moveX;
self.y += moveY;
}
};
return self;
});
var Spell = Container.expand(function (spellType, startX, startY, targetX, targetY) {
var self = Container.call(this);
self.spellType = spellType;
self.speed = 8;
self.damage = 1;
self.lifeTime = 180; // 3 seconds at 60fps
self.age = 0;
var spellGraphics;
if (spellType === 'fireball') {
spellGraphics = self.attachAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 2;
} else if (spellType === 'iceShard') {
spellGraphics = self.attachAsset('iceShard', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 1;
self.slowEffect = true;
} else if (spellType === 'lightning') {
spellGraphics = self.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 3;
self.speed = 15;
} else if (spellType === 'poisonCloud') {
spellGraphics = self.attachAsset('poisonCloud', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 1;
self.speed = 0;
self.lifeTime = 210; // 3.5 seconds total duration (210 frames at 60fps)
self.lastDamageTick = 0;
self.damageInterval = 18; // Damage every 0.3 seconds (18 frames at 60fps)
spellGraphics.alpha = 0.6;
} else if (spellType === 'explosion') {
spellGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 4;
self.speed = 0;
self.lifeTime = 30;
spellGraphics.alpha = 0.8;
}
self.x = startX;
self.y = startY;
// Calculate direction
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
} else {
self.velocityX = 0;
self.velocityY = 0;
}
self.createExplosion = function () {
var explosion = new Spell('explosion', self.x, self.y, self.x, self.y);
spells.push(explosion);
game.addChild(explosion);
};
self.update = function () {
self.age++;
if (self.spellType !== 'poisonCloud' && self.spellType !== 'explosion') {
self.x += self.velocityX;
self.y += self.velocityY;
}
if (self.spellType === 'explosion') {
var scale = 1 + self.age / 30 * 2;
spellGraphics.scaleX = scale;
spellGraphics.scaleY = scale;
}
};
return self;
});
var SpellButton = Container.expand(function (spellType, buttonX, buttonY) {
var self = Container.call(this);
self.spellType = spellType;
self.cooldown = 0;
self.maxCooldown = 60; // 1 second
self.manaCost = 10; // Default mana cost
var buttonBg = self.attachAsset('spellButton', {
anchorX: 0.5,
anchorY: 0.5
});
var spellNames = {
'fireball': 'Fire',
'iceShard': 'Ice',
'lightning': 'Bolt',
'shield': 'Shield',
'teleport': 'Port',
'poisonCloud': 'Poison',
'mindControl': 'Mind',
'explosion': 'Boom',
'timeSlow': 'Stop',
'storm': 'Storm',
'manaRestorer': 'Restore',
'heal': 'Heal'
};
var buttonText = new Text2(spellNames[spellType] || spellType, {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.spellName = spellNames[spellType] || spellType;
self.x = buttonX;
self.y = buttonY;
// Set different cooldowns and mana costs for different spells
if (spellType === 'fireball') {
self.maxCooldown = 30;
self.manaCost = 15;
} else if (spellType === 'iceShard') {
self.maxCooldown = 25;
self.manaCost = 10;
} else if (spellType === 'lightning') {
self.maxCooldown = 45;
self.manaCost = 25;
} else if (spellType === 'shield') {
self.maxCooldown = 180;
self.manaCost = 40;
} else if (spellType === 'teleport') {
self.maxCooldown = 120;
self.manaCost = 30;
} else if (spellType === 'poisonCloud') {
self.maxCooldown = 390; // 6.5 seconds at 60fps
self.manaCost = 35;
} else if (spellType === 'mindControl') {
self.maxCooldown = 150;
self.manaCost = 50;
} else if (spellType === 'explosion') {
self.maxCooldown = 80;
self.manaCost = 45;
} else if (spellType === 'timeSlow') {
self.maxCooldown = 270; // 4.5 seconds
self.manaCost = 60;
} else if (spellType === 'storm') {
self.maxCooldown = 522; // 8.7 seconds
self.manaCost = 70;
} else if (spellType === 'manaRestorer') {
self.maxCooldown = 1000; // 10 seconds
self.manaCost = 0; // No mana cost
} else if (spellType === 'heal') {
self.maxCooldown = 1200; // 20 seconds at 60fps
self.manaCost = 130;
}
self.canCast = function () {
if (self.spellType === 'manaRestorer') {
return self.cooldown <= 0; // Mana restorer ignores mana cost and incapacity
}
return self.cooldown <= 0 && wizardMana >= self.manaCost && incapacityTimer <= 0;
};
self.cast = function () {
if (self.canCast()) {
self.cooldown = self.maxCooldown;
return true;
}
return false;
};
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
buttonBg.tint = 0x666666;
buttonText.fill = 0x999999;
// Show cooldown duration
var cooldownSeconds = Math.ceil(self.cooldown / 60);
buttonText.setText(cooldownSeconds + 's');
} else if (self.spellType !== 'manaRestorer' && incapacityTimer > 0) {
// Incapacitated - show red tint
buttonBg.tint = 0xFF4444;
buttonText.fill = 0xFF8888;
var incapacitySeconds = Math.ceil(incapacityTimer / 60);
buttonText.setText('Inc: ' + incapacitySeconds + 's');
} else if (wizardMana < self.manaCost) {
// Not enough mana - show blue tint
buttonBg.tint = 0x4444FF;
buttonText.fill = 0x8888FF;
buttonText.setText(self.spellName);
} else {
buttonBg.tint = 0xFFFFFF;
buttonText.fill = 0xFFFFFF;
buttonText.setText(self.spellName);
}
};
self.down = function (x, y, obj) {
if (self.canCast()) {
castSpell(self.spellType);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
// Wizard
// Spells
// Enemies
// UI Elements
// Sounds
var wizard;
var enemies = [];
var spells = [];
var spellButtons = [];
var waveNumber = 1;
var enemiesSpawned = 0;
var enemiesPerWave = 5;
var spawnTimer = 0;
var spawnDelay = 120; // 2 seconds
var gameTime = 0;
var shieldActive = false;
var shieldObject = null;
var timeSlowActive = false;
var timeSlowTimer = 0;
var stormActive = false;
var stormTimer = 0;
var stormObject = null;
var wizardHealth = 100;
var wizardMaxHealth = 100;
var wizardMana = 180;
var wizardMaxMana = 180;
var manaRegenRate = 0.1; // Mana regenerated per frame
var incapacityTimer = 0; // Timer for power incapacity after mana restorer
var poisonCloudCooldown = 0; // 6.5 second cooldown for poison cloud
var stormParticles = []; // Track storm particles
var healthBar = null;
var healthBarFill = null;
var manaBar = null;
var manaBarFill = null;
// Enemy types for spawning
var enemyTypes = ['goblin', 'demon', 'flyingEye', 'golem', 'skeleton', 'mushroom', 'hellhound', 'darkSorcerer'];
// Create wizard
wizard = game.addChild(new Container());
var wizardGraphics = wizard.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5
});
wizard.x = 1024;
wizard.y = 1366;
// Create spell buttons
var spellTypes = ['fireball', 'iceShard', 'lightning', 'shield', 'teleport', 'poisonCloud', 'mindControl', 'explosion', 'timeSlow', 'storm', 'manaRestorer', 'heal'];
for (var i = 0; i < spellTypes.length; i++) {
var buttonX = 150 + i % 6 * 180; // Increased horizontal spacing for larger buttons
var buttonY = 2450 + Math.floor(i / 6) * 130; // Increased vertical spacing and moved up slightly
var button = new SpellButton(spellTypes[i], buttonX, buttonY);
spellButtons.push(button);
game.addChild(button);
}
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 150;
scoreTxt.y = 100;
game.addChild(scoreTxt);
// Create wave display
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(0, 0);
waveTxt.x = 150;
waveTxt.y = 180;
game.addChild(waveTxt);
// Create health bar
healthBar = game.addChild(new Container());
var healthBarBg = healthBar.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
healthBarFill = healthBar.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0
});
healthBar.x = 150;
healthBar.y = 250;
// Health bar text
var healthTxt = new Text2('Health: 100/100', {
size: 40,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 150;
healthTxt.y = 280;
game.addChild(healthTxt);
// Create mana bar
manaBar = game.addChild(new Container());
var manaBarBg = manaBar.attachAsset('manaBarBg', {
anchorX: 0,
anchorY: 0
});
manaBarFill = manaBar.attachAsset('manaBarFill', {
anchorX: 0,
anchorY: 0
});
manaBar.x = 150;
manaBar.y = 330;
// Mana bar text
var manaTxt = new Text2('Mana: 180/180', {
size: 40,
fill: 0x0080FF
});
manaTxt.anchor.set(0, 0);
manaTxt.x = 150;
manaTxt.y = 360;
game.addChild(manaTxt);
function castSpell(spellType) {
// Find the button and check cooldown
var button = null;
for (var i = 0; i < spellButtons.length; i++) {
if (spellButtons[i].spellType === spellType) {
button = spellButtons[i];
break;
}
}
if (!button || !button.cast()) {
return;
}
// Consume mana
wizardMana -= button.manaCost;
if (wizardMana < 0) {
wizardMana = 0;
}
// Update mana display
var manaPercent = wizardMana / wizardMaxMana;
manaBarFill.scaleX = manaPercent;
manaTxt.setText('Mana: ' + Math.floor(wizardMana) + '/' + wizardMaxMana);
LK.getSound('spellCast').play();
if (spellType === 'shield') {
activateShield();
} else if (spellType === 'teleport') {
teleportWizard();
} else if (spellType === 'timeSlow') {
activateTimeSlow();
} else if (spellType === 'mindControl') {
mindControlEnemies();
} else if (spellType === 'explosion') {
// Explosion at wizard location
var spell = new Spell(spellType, wizard.x, wizard.y, wizard.x, wizard.y);
spells.push(spell);
game.addChild(spell);
} else if (spellType === 'storm') {
activateStorm();
} else if (spellType === 'manaRestorer') {
activateManaRestorer();
} else if (spellType === 'heal') {
activateHeal();
} else {
// Targeted spells - cast towards nearest enemy
var nearestEnemy = findNearestEnemy();
if (nearestEnemy) {
var spell = new Spell(spellType, wizard.x, wizard.y, nearestEnemy.x, nearestEnemy.y);
spell.targetX = nearestEnemy.x;
spell.targetY = nearestEnemy.y;
spells.push(spell);
game.addChild(spell);
}
}
}
function findNearestEnemy() {
var nearest = null;
var minDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var dx = enemies[i].x - wizard.x;
var dy = enemies[i].y - wizard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
minDistance = distance;
nearest = enemies[i];
}
}
return nearest;
}
function activateShield() {
if (shieldObject) {
shieldObject.destroy();
}
shieldObject = game.addChild(new Container());
var shieldGraphics = shieldObject.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
shieldGraphics.alpha = 0.5;
shieldActive = true;
LK.setTimeout(function () {
if (shieldObject) {
shieldObject.destroy();
shieldObject = null;
}
shieldActive = false;
}, 3000);
}
function teleportWizard() {
// Teleport to a safe random location
var attempts = 0;
var newX, newY;
do {
newX = 200 + Math.random() * (2048 - 400);
newY = 200 + Math.random() * (2200 - 400);
attempts++;
} while (attempts < 10 && isLocationUnsafe(newX, newY));
wizard.x = newX;
wizard.y = newY;
// Teleport effect
LK.effects.flashObject(wizard, 0x00FFFF, 500);
}
function isLocationUnsafe(x, y) {
for (var i = 0; i < enemies.length; i++) {
var dx = enemies[i].x - x;
var dy = enemies[i].y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
return true;
}
}
return false;
}
function activateTimeSlow() {
timeSlowActive = true;
timeSlowTimer = 90; // 1.5 seconds
LK.effects.flashScreen(0x0066FF, 200);
// Visual effect on all enemies - freeze them completely
for (var i = 0; i < enemies.length; i++) {
if (!enemies[i].originalSpeed) {
enemies[i].originalSpeed = enemies[i].speed;
}
enemies[i].speed = 0; // Complete stop
tween(enemies[i], {
tint: 0x6666FF
}, {
duration: 300
});
}
}
function activateStorm() {
stormActive = true;
stormTimer = 210; // 3.5 seconds at 60fps
// Create storm object that follows wizard
if (stormObject) {
stormObject.destroy();
}
stormObject = game.addChild(new Container());
var stormGraphics = stormObject.attachAsset('stormEffect', {
anchorX: 0.5,
anchorY: 0.5
});
stormGraphics.alpha = 0.8;
// Clear existing storm particles
for (var p = 0; p < stormParticles.length; p++) {
if (stormParticles[p]) {
stormParticles[p].destroy();
}
}
stormParticles = [];
// Create storm particles around wizard that follow the storm
for (var i = 0; i < 8; i++) {
var particle = game.addChild(new Container());
var particleGraphics = particle.attachAsset('iceShard', {
anchorX: 0.5,
anchorY: 0.5
});
particleGraphics.scaleX = 0.3;
particleGraphics.scaleY = 0.3;
particleGraphics.tint = 0x87CEEB;
particle.x = wizard.x;
particle.y = wizard.y;
particle.angle = i / 8 * Math.PI * 2;
particle.baseRadius = 100 + i * 20;
particle.rotationSpeed = 0.1;
stormParticles.push(particle);
}
// Start wizard spinning and shrinking animation
tween(wizard, {
rotation: Math.PI * 14,
// 7 full rotations over 3.5 seconds
scaleX: 0.6,
// Shrink to 60% size
scaleY: 0.6
}, {
duration: 3500,
easing: tween.linear
});
// Visual storm effect
LK.effects.flashScreen(0x4169E1, 300);
}
function activateManaRestorer() {
// Instantly restore full mana
wizardMana = wizardMaxMana;
// Update mana display
var manaPercent = wizardMana / wizardMaxMana;
manaBarFill.scaleX = manaPercent;
manaTxt.setText('Mana: ' + Math.floor(wizardMana) + '/' + wizardMaxMana);
// Add 6 seconds of incapacity to all powers
incapacityTimer = 432; // 6 seconds at 60fps
// Visual effect
LK.effects.flashObject(wizard, 0x00FFFF, 1000);
LK.effects.flashScreen(0x00FFFF, 300);
}
function activateHeal() {
// Restore to exactly 100 health (full health)
wizardHealth = 100;
wizardMaxHealth = 100; // Ensure max health is also 100
// Update health bar
var healthPercent = wizardHealth / wizardMaxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
// Update health text
healthTxt.setText('Health: ' + wizardHealth + '/' + wizardMaxHealth);
// Visual healing effect
LK.effects.flashObject(wizard, 0x00FF00, 1000);
tween(wizard, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(wizard, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
function mindControlEnemies() {
var controlled = 0;
for (var i = 0; i < enemies.length && controlled < 3; i++) {
var dx = enemies[i].x - wizard.x;
var dy = enemies[i].y - wizard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
// Mind control effect - purple flash then instant kill
tween(enemies[i], {
tint: 0x9932CC
}, {
duration: 200,
onFinish: function onFinish() {
tween(this, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
enemies[i].takeDamage(enemies[i].health);
}
});
}
});
controlled++;
}
}
}
function damageWizard(damage) {
wizardHealth -= damage;
if (wizardHealth < 0) {
wizardHealth = 0;
}
// Update health bar
var healthPercent = wizardHealth / wizardMaxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
// Update health text
healthTxt.setText('Health: ' + wizardHealth + '/' + wizardMaxHealth);
if (wizardHealth <= 0) {
LK.effects.flashScreen(0xFF0000, 500);
LK.showGameOver();
}
}
function spawnEnemy() {
if (enemiesSpawned < enemiesPerWave) {
var enemyType = enemyTypes[Math.floor(Math.random() * Math.min(enemyTypes.length, 2 + Math.floor(waveNumber / 2)))];
var enemy = new Enemy(enemyType);
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
}
function checkCollisions() {
// Spells vs Enemies
for (var s = spells.length - 1; s >= 0; s--) {
var spell = spells[s];
// Area damage spells (explosion, poison cloud)
if (spell.spellType === 'explosion' || spell.spellType === 'poisonCloud') {
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
var dx = enemy.x - spell.x;
var dy = enemy.y - spell.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var damageRadius = spell.spellType === 'explosion' ? 120 : 80;
if (distance < damageRadius) {
// For poison cloud, only damage at intervals and apply poison effect
if (spell.spellType === 'poisonCloud') {
if (spell.age - spell.lastDamageTick >= spell.damageInterval) {
spell.lastDamageTick = spell.age;
var isDead = enemy.takeDamage(spell.damage);
enemy.applyPoisonEffect(); // Apply poison effect
if (isDead) {
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText('Score: ' + LK.getScore());
enemy.destroy();
enemies.splice(e, 1);
LK.getSound('enemyDeath').play();
}
}
} else {
// Explosion deals instant damage
var isDead = enemy.takeDamage(spell.damage);
if (isDead) {
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText('Score: ' + LK.getScore());
enemy.destroy();
enemies.splice(e, 1);
LK.getSound('enemyDeath').play();
}
}
}
}
} else {
// Single target spells
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (spell.intersects && spell.intersects(enemy)) {
// Apply ice shard slow effect with blue tint
if (spell.slowEffect) {
enemy.applySlowEffect();
}
var isDead = enemy.takeDamage(spell.damage);
if (isDead) {
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText('Score: ' + LK.getScore());
enemy.destroy();
enemies.splice(e, 1);
LK.getSound('enemyDeath').play();
}
// Fireball creates explosion on impact
if (spell.spellType === 'fireball') {
spell.createExplosion();
}
if (spell.spellType !== 'poisonCloud') {
spell.destroy();
spells.splice(s, 1);
break;
}
}
}
}
}
// Enemies vs Wizard
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (enemy.intersects && enemy.intersects(wizard)) {
if (!shieldActive) {
// Only damage if enough time has passed since last hit
if (LK.ticks - enemy.lastHitTime > 60) {
// 1 second cooldown
damageWizard(enemy.damage * 10); // Scale damage for visibility
enemy.lastHitTime = LK.ticks;
}
} else {
// Shield absorbs hit
enemy.destroy();
enemies.splice(e, 1);
if (shieldObject) {
shieldObject.destroy();
shieldObject = null;
shieldActive = false;
}
}
}
}
// Storm vs Enemies
if (stormActive && stormObject) {
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
var dx = enemy.x - stormObject.x;
var dy = enemy.y - stormObject.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 560) {
// Storm radius
// Push enemy back strongly
var pushDistance = 145;
if (distance > 0) {
enemy.x += dx / distance * pushDistance;
enemy.y += dy / distance * pushDistance;
}
// Deal small damage every 10 frames (6 times per second)
if (LK.ticks % 10 === 0) {
var isDead = enemy.takeDamage(1);
if (isDead) {
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText('Score: ' + LK.getScore());
enemy.destroy();
enemies.splice(e, 1);
LK.getSound('enemyDeath').play();
}
}
}
}
}
}
game.move = function (x, y, obj) {
if (x > 100 && x < 1948 && y > 100 && y < 2200) {
wizard.x = x;
wizard.y = y;
}
};
game.update = function () {
gameTime++;
// Update incapacity timer
if (incapacityTimer > 0) {
incapacityTimer--;
}
// Update poison cloud cooldown
if (poisonCloudCooldown > 0) {
poisonCloudCooldown--;
}
// Regenerate mana
if (wizardMana < wizardMaxMana) {
wizardMana += manaRegenRate;
if (wizardMana > wizardMaxMana) {
wizardMana = wizardMaxMana;
}
// Update mana display
var manaPercent = wizardMana / wizardMaxMana;
manaBarFill.scaleX = manaPercent;
manaTxt.setText('Mana: ' + Math.floor(wizardMana) + '/' + wizardMaxMana);
}
// Update time slow
if (timeSlowActive) {
timeSlowTimer--;
if (timeSlowTimer <= 0) {
timeSlowActive = false;
}
}
// Update storm
if (stormActive) {
stormTimer--;
if (stormObject) {
stormObject.x = wizard.x;
stormObject.y = wizard.y;
}
// Update storm particles to follow storm
for (var p = 0; p < stormParticles.length; p++) {
if (stormParticles[p]) {
var particle = stormParticles[p];
particle.angle += particle.rotationSpeed;
particle.x = wizard.x + Math.cos(particle.angle) * particle.baseRadius;
particle.y = wizard.y + Math.sin(particle.angle) * particle.baseRadius;
particle.rotation += 0.2;
}
}
if (stormTimer <= 0) {
stormActive = false;
if (stormObject) {
stormObject.destroy();
stormObject = null;
}
// Destroy all storm particles
for (var p = 0; p < stormParticles.length; p++) {
if (stormParticles[p]) {
stormParticles[p].destroy();
}
}
stormParticles = [];
// Stop wizard spinning and restore size
tween.stop(wizard, {
rotation: true,
scaleX: true,
scaleY: true
});
// Animate wizard back to normal size
tween(wizard, {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Update shield position
if (shieldObject) {
shieldObject.x = wizard.x;
shieldObject.y = wizard.y;
}
// Spawn enemies
spawnTimer++;
var actualSpawnDelay = timeSlowActive ? spawnDelay * 2 : spawnDelay;
if (spawnTimer >= actualSpawnDelay) {
spawnEnemy();
spawnTimer = 0;
}
// Update spells
for (var s = spells.length - 1; s >= 0; s--) {
var spell = spells[s];
spell.age++;
if (spell.age >= spell.lifeTime || spell.x < -100 || spell.x > 2148 || spell.y < -100 || spell.y > 2832) {
spell.destroy();
spells.splice(s, 1);
}
}
// Update enemies with time stop effect
for (var e = 0; e < enemies.length; e++) {
if (timeSlowActive && !enemies[e].timeSlowApplied) {
if (!enemies[e].originalSpeed) {
enemies[e].originalSpeed = enemies[e].speed;
}
enemies[e].speed = 0; // Complete stop
enemies[e].timeSlowApplied = true;
} else if (!timeSlowActive && enemies[e].timeSlowApplied) {
enemies[e].speed = enemies[e].originalSpeed || enemies[e].speed;
enemies[e].timeSlowApplied = false;
// Restore normal tint
tween(enemies[e], {
tint: 0xFFFFFF
}, {
duration: 200
});
}
}
// Check for wave completion
if (enemiesSpawned >= enemiesPerWave && enemies.length === 0) {
waveNumber++;
enemiesSpawned = 0;
enemiesPerWave = 5 + waveNumber * 2;
spawnDelay = Math.max(30, 120 - waveNumber * 5);
waveTxt.setText('Wave: ' + waveNumber);
// Bonus points for completing wave
LK.setScore(LK.getScore() + waveNumber * 50);
scoreTxt.setText('Score: ' + LK.getScore());
}
checkCollisions();
};
A very mysterious and cool man with a purple hat a wizard character's head is purple and dark blue themed. In-Game asset. 2d. High contrast. No shadows
a mysterious and angry goblin. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary demon character's head. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary flying eye character's head. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary golem character's head. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary wizard character's head. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary skeleton character's head. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary hellhound character's head. In-Game asset. 2d. High contrast. No shadows
2d mysterious and scary mushroom character's head. In-Game asset. 2d. High contrast. No shadows
an old-style square long button in grey in a magical way. In-Game asset. 2d. High contrast. No shadows