User prompt
make the text under the difficulties bigger and more readable
User prompt
add descriptions of the gamemodes under the gaamemode button ex: Easy Made for begginers
User prompt
make more fast varients for race mode, more poison varients for infection mode, and more enemy varients in general
User prompt
make tower bullets move faster
User prompt
Make the background color change to gray in race mode and purple in infection mode
User prompt
Make the move icon its own asset
User prompt
Make the build and delete buttons their own assets
User prompt
make infection difficulty replace the hearttree asset with an old building asset (create a old building asset in asset section)
User prompt
make infection difficulty replace the buildingspot asset with a mutant tree asset (create mutant tree asset in asset section)
User prompt
make infection difficulty replace the spawn area asset with an acid barrel asset (create an acid barrel asset in asset section) (dont add acid related effects to speedy enemies, just replace the asset)
User prompt
add an infection difficulty where the dirt track becomes a acid spill asset and more poison varients spawn (make more poison varients for infection mode)
User prompt
add a race difficulty where the dirt track becomes a acid spill asset and more poison varients spawn (make more poison varients for infection mode)
User prompt
make race difficulty replace the hearttree asset with a finishline asset (create a finishline asset in asset section)
User prompt
make race difficulty replace the buildingspot asset with a tire asset (create a tire asset in asset section)
User prompt
make race difficulty replace the spawn area asset with a car asset (create a car asset in asset section) (dont add car related effects to speedy enemies, just replace the asset)
User prompt
add a delete button right next to the move and build button that if you click on a tower when it's activated it will delete the tower and give you your money back
User prompt
remove the upgrade and sell button and the tower menu
User prompt
when i click the sell button, nothing happens
User prompt
the sell button isn't working
User prompt
add a race difficulty where the dirt track becomes a racetrack asset and more fast varients spawn *make more fast variemts for fast mode) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hurry up
User prompt
make difficulty buttons (easy, normal, hard) instead of one play button
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'moveTo')' in or related to this line: 'guardian.moveTo(x, y);' Line Number: 2095
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'update')' in or related to this line: 'guardian.update();' Line Number: 2122
User prompt
Please fix the bug: 'TypeError: null is not an object (evaluating 'guardian.update')' in or related to this line: 'guardian.update();' Line Number: 2122
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, unlockedTowers: ["thorn", "shroom", "flame", "healing"] }); /**** * Classes ****/ var BuildingSpot = Container.expand(function () { var self = Container.call(this); var spotGraphics; if (gameDifficulty === 'race') { spotGraphics = self.attachAsset('tire', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); } else if (gameDifficulty === 'infection') { spotGraphics = self.attachAsset('mutanttree', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 }); } else { spotGraphics = self.attachAsset('buildingSpot', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4 }); } self.gridX = 0; self.gridY = 0; self.occupied = false; self.tower = null; self.down = function (x, y, obj) { if (!self.occupied && currentMode === 'building' && selectedTower !== null && essence >= towerCosts[selectedTower]) { self.buildTower(selectedTower); } }; self.buildTower = function (towerType) { var tower; if (towerType === 'thorn') { tower = new ThornTower(); } else if (towerType === 'shroom') { tower = new ShroomTower(); } else if (towerType === 'flame') { tower = new FlameTower(); } else if (towerType === 'healing') { tower = new FarmTower(); } if (tower) { tower.x = self.x; tower.y = self.y; tower.gridX = self.gridX; tower.gridY = self.gridY; game.addChild(tower); towers.push(tower); essence -= towerCosts[towerType]; updateEssenceText(); self.occupied = true; self.tower = tower; LK.getSound('towerPlaced').play(); } }; return self; }); var Car = Container.expand(function () { var self = Container.call(this); var carGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF3300, // Reddish tint for car scaleX: 1.3, scaleY: 0.6 // Low and wide like a car }); return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.maxHealth = 50; self.health = self.maxHealth; self.value = 10; // Essence value when defeated self.pathIndex = 0; self.alive = true; self.update = function () { if (!self.alive) { return; } // Follow path if (self.pathIndex < path.length) { var targetPoint = path[self.pathIndex]; var dx = targetPoint.x - self.x; var dy = targetPoint.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // If near target point, move to next point if (distance < 20) { self.pathIndex++; // If reached the end of path (HeartTree) if (self.pathIndex >= path.length) { heartTree.takeDamage(10); self.alive = false; return; } } else { // Move towards current target point var angle = Math.atan2(dy, dx); self.x += Math.cos(angle) * self.speed; self.y += Math.sin(angle) * self.speed; } } }; // Add a static method to Enemy to use for inheritance Enemy.prototype.update = function () { if (!this.alive) { return; } // Follow path if (this.pathIndex < path.length) { var targetPoint = path[this.pathIndex]; var dx = targetPoint.x - this.x; var dy = targetPoint.y - this.y; var distance = Math.sqrt(dx * dx + dy * dy); // If near target point, move to next point if (distance < 20) { this.pathIndex++; // If reached the end of path (HeartTree) if (this.pathIndex >= path.length) { heartTree.takeDamage(10); this.alive = false; return; } } else { // Move towards current target point var angle = Math.atan2(dy, dx); this.x += Math.cos(angle) * this.speed; this.y += Math.sin(angle) * this.speed; } } }; self.takeDamage = function (amount) { self.health -= amount; if (self.health <= 0) { self.die(); } else { // Flash enemy when hit LK.effects.flashObject(self, 0xFF0000, 200); } }; self.die = function () { self.alive = false; // Drop essence var essenceObj = new Essence(); essenceObj.value = self.value; essenceObj.x = self.x; essenceObj.y = self.y; game.addChild(essenceObj); essenceItems.push(essenceObj); // Increase score LK.setScore(LK.getScore() + self.value); scoreTxt.setText(LK.getScore()); LK.getSound('enemyDeath').play(); }; return self; }); var ToxicBlobEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var blobGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0x80FF80, // Light green tint scaleX: 1.4, scaleY: 1.4 }); self.speed = 1.3; self.maxHealth = 140; self.health = self.maxHealth; self.value = 30; // Override die method to spawn smaller toxic enemies self.die = function () { self.alive = false; // Spawn smaller toxic enemies for (var i = 0; i < 3; i++) { var smallToxic = new PoisonEnemy(); // Make it smaller smallToxic.scale.set(0.7, 0.7); // Reduce stats for smaller version smallToxic.maxHealth = 30; smallToxic.health = smallToxic.maxHealth; smallToxic.speed = 2.5; smallToxic.value = 8; smallToxic.pathIndex = self.pathIndex; // Position with slight offset smallToxic.x = self.x + (Math.random() * 60 - 30); smallToxic.y = self.y + (Math.random() * 60 - 30); game.addChild(smallToxic); enemies.push(smallToxic); enemiesRemaining++; } // Create explosion effect var explosion = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, tint: 0x00FF00, scaleX: 2, scaleY: 2 }); game.addChild(explosion); // Animate explosion tween(explosion, { alpha: 0, scaleX: 3, scaleY: 3 }, { duration: 400, onFinish: function onFinish() { explosion.destroy(); } }); // Drop essence var essenceObj = new Essence(); essenceObj.value = self.value; essenceObj.x = self.x; essenceObj.y = self.y; game.addChild(essenceObj); essenceItems.push(essenceObj); // Increase score LK.setScore(LK.getScore() + self.value); scoreTxt.setText(LK.getScore()); LK.getSound('enemyDeath').play(); }; return self; }); var TankEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var tankGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0x666666, // Grey tint for tank enemies scaleX: 1.4, scaleY: 1.4 // Larger }); self.speed = 1; // Slower self.maxHealth = 120; // Higher health self.health = self.maxHealth; self.value = 25; // Higher value return self; }); var SplitEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var splitGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF6347, // Tomato red for split enemies scaleX: 1.3, scaleY: 1.3 }); self.speed = 1.5; self.maxHealth = 70; self.health = self.maxHealth; self.value = 12; self.splitCount = 2; // Number of smaller enemies to spawn when killed self.size = 'large'; // Size tracking for spawned children // Override die method to create smaller enemies when killed self.die = function () { self.alive = false; // Only split if this is the original large enemy if (self.size === 'large') { // Spawn smaller enemies for (var i = 0; i < self.splitCount; i++) { var smallEnemy = new SplitEnemy(); // Make it smaller smallEnemy.scale.set(0.6, 0.6); // Reduce stats for smaller version smallEnemy.size = 'small'; smallEnemy.maxHealth = 25; smallEnemy.health = smallEnemy.maxHealth; smallEnemy.speed = 2.2; smallEnemy.value = 8; smallEnemy.pathIndex = self.pathIndex; // Position with slight offset smallEnemy.x = self.x + (Math.random() * 60 - 30); smallEnemy.y = self.y + (Math.random() * 60 - 30); game.addChild(smallEnemy); enemies.push(smallEnemy); enemiesRemaining++; } } // Create explosion effect var explosion = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, tint: 0xFF4500, scaleX: 2, scaleY: 2 }); game.addChild(explosion); // Animate explosion tween(explosion, { alpha: 0, scaleX: 3, scaleY: 3 }, { duration: 300, onFinish: function onFinish() { explosion.destroy(); } }); // Drop essence var essenceObj = new Essence(); essenceObj.value = self.value; essenceObj.x = self.x; essenceObj.y = self.y; game.addChild(essenceObj); essenceItems.push(essenceObj); // Increase score LK.setScore(LK.getScore() + self.value); scoreTxt.setText(LK.getScore()); LK.getSound('enemyDeath').play(); }; return self; }); var SpeedyEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var speedyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFF00, // Yellow tint for speedy enemies scaleX: 0.8, scaleY: 1.2 // Tall and thin }); self.speed = 4; // Much faster self.maxHealth = 30; // Lower health self.health = self.maxHealth; self.value = 15; // Slightly higher value return self; }); var RaceEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var raceGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF5500, // Orange-red tint for race enemies scaleX: 1.2, scaleY: 0.5 // Low and wide like a race car }); self.speed = 6; // Very fast self.maxHealth = 25; // Lower health self.health = self.maxHealth; self.value = 20; self.exhaustCounter = 0; // Override update to add exhaust particle effect self.update = function () { if (!self.alive) { return; } // Call parent update for movement Enemy.prototype.update.call(self); // Create exhaust particle effect every few ticks self.exhaustCounter++; if (self.exhaustCounter >= 5) { self.exhaustCounter = 0; var exhaust = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, x: self.x - Math.cos(Math.atan2(path[self.pathIndex].y - self.y, path[self.pathIndex].x - self.x)) * 30, y: self.y - Math.sin(Math.atan2(path[self.pathIndex].y - self.y, path[self.pathIndex].x - self.x)) * 30, tint: 0x888888, scaleX: 0.5, scaleY: 0.5, alpha: 0.7 }); game.addChild(exhaust); // Animate exhaust tween(exhaust, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { exhaust.destroy(); } }); } }; return self; }); var PoisonEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var poisonGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0x00FF00, // Green tint for poison enemies scaleX: 1.1, scaleY: 1.1 }); self.speed = 1.8; self.maxHealth = 80; self.health = self.maxHealth; self.value = 20; self.lastShotTime = 0; self.shotInterval = 3; // Seconds between shots // Override update to add shooting behavior self.update = function () { if (!self.alive) { return; } // Call parent update method for movement Enemy.prototype.update.call(self); // Add shooting behavior var currentTime = LK.ticks / 60; if (currentTime - self.lastShotTime >= self.shotInterval) { self.lastShotTime = currentTime; self.shootProjectile(); } }; self.shootProjectile = function () { // Create a poison projectile aimed at heart tree var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; projectile.damage = 5; projectile.speed = 8; projectile.target = heartTree; // Make it green projectile.getChildAt(0).tint = 0x00FF00; game.addChild(projectile); // Visual effect LK.effects.flashObject(self, 0x00FF00, 200); }; return self; }); var FlyingEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var flyingGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0x9370DB, // Purple tint for flying enemies scaleX: 0.9, scaleY: 0.6 // Flatter shape }); self.speed = 3; self.maxHealth = 40; self.health = self.maxHealth; self.value = 18; self.flyingMode = true; // Override the update method to go directly to heart tree self.update = function () { if (!self.alive) { return; } // Flying enemies ignore the path and go straight for the heart tree var dx = heartTree.x - self.x; var dy = heartTree.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // If near heart tree, attack it if (distance < 20) { heartTree.takeDamage(15); self.alive = false; return; } // Move towards heart tree var angle = Math.atan2(dy, dx); self.x += Math.cos(angle) * self.speed; self.y += Math.sin(angle) * self.speed; // Add a slight wave pattern to flight self.y += Math.sin(LK.ticks / 10) * 0.5; }; return self; }); var BossEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with boss graphics self.removeChildAt(0); // Remove default enemy graphics var bossGraphics = self.attachAsset('bossEnemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.8, // Make boss bigger scaleY: 1.8 // Make boss bigger }); self.speed = 1.2; self.maxHealth = 300 + currentWave * 30; self.health = self.maxHealth; self.value = 100 + currentWave * 15; self.lastAttackTime = 0; self.attackCooldown = 3; // seconds between special attacks // Override update method to add special attacks self.update = function () { if (!self.alive) { return; } // Call parent update for movement Enemy.prototype.update.call(self); // Special attacks var currentTime = LK.ticks / 60; if (currentTime - self.lastAttackTime >= self.attackCooldown) { self.lastAttackTime = currentTime; self.specialAttack(); } // Pulsate effect var pulse = 1 + Math.sin(LK.ticks / 15) * 0.1; self.scale.set(1.8 * pulse, 1.8 * pulse); }; // Special attack based on boss wave level self.specialAttack = function () { // Boss becomes more dangerous in later waves var attackType = Math.floor(Math.random() * 3); // Flash effect for attack LK.effects.flashObject(self, 0xFF0000, 300); if (attackType === 0) { // Projectile burst attack var projectileCount = 8; for (var i = 0; i < projectileCount; i++) { var angle = i / projectileCount * Math.PI * 2; var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; projectile.damage = 8; // Set a fixed position as target based on angle var targetDummy = { x: self.x + Math.cos(angle) * 500, y: self.y + Math.sin(angle) * 500, alive: true }; projectile.target = targetDummy; // Give projectile red color projectile.getChildAt(0).tint = 0xFF0000; game.addChild(projectile); } } else if (attackType === 1) { // Spawn minions var minionCount = 2 + Math.floor(currentWave / 5); for (var i = 0; i < minionCount; i++) { var minion = new SpeedyEnemy(); minion.x = self.x; minion.y = self.y; minion.pathIndex = self.pathIndex; minion.maxHealth = 20; minion.health = minion.maxHealth; minion.speed = 5; minion.value = 5; // Make minions smaller minion.scale.set(0.7, 0.7); game.addChild(minion); enemies.push(minion); enemiesRemaining++; } } else { // Heal self var healAmount = Math.min(self.maxHealth - self.health, self.maxHealth * 0.1); if (healAmount > 0) { self.health += healAmount; // Create healing effect var healEffect = new Text2("+" + Math.floor(healAmount), { size: 40, fill: 0x00FF00 }); healEffect.anchor.set(0.5, 0.5); healEffect.x = self.x; healEffect.y = self.y - 50; game.addChild(healEffect); // Animate healing text tween(healEffect, { alpha: 0, y: healEffect.y - 50 }, { duration: 1000, onFinish: function onFinish() { healEffect.destroy(); } }); } } }; // Override takeDamage to get enraged at low health self.takeDamage = function (amount) { self.health -= amount; // Enrage when below 30% health if (self.health <= self.maxHealth * 0.3 && self.speed < 1.8) { self.speed *= 1.5; // Move faster self.attackCooldown *= 0.6; // Attack more often // Visual effect for enrage LK.effects.flashObject(self, 0xFF0000, 1000); // Create enrage message var enrageText = new Text2("BOSS ENRAGED!", { size: 70, fill: 0xFF0000 }); enrageText.anchor.set(0.5, 0.5); enrageText.x = 2048 / 2; enrageText.y = 2732 / 2; game.addChild(enrageText); // Animate message tween(enrageText, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 1500, onFinish: function onFinish() { enrageText.destroy(); } }); } if (self.health <= 0) { self.die(); } else { // Flash when hit LK.effects.flashObject(self, 0xFF0000, 200); } }; return self; }); var InfectionBossEnemy = BossEnemy.expand(function () { var self = BossEnemy.call(this); // Replace boss graphics with infected version self.removeChildAt(0); // Remove default boss graphics var bossGraphics = self.attachAsset('bossEnemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.8, scaleY: 1.8, tint: 0x00FF00 // Green tint for infection }); // Override special attack to be infection-themed self.specialAttack = function () { // Flash effect for attack LK.effects.flashObject(self, 0x00FF00, 300); var attackType = Math.floor(Math.random() * 3); if (attackType === 0) { // Toxic cloud attack var cloudCount = 3 + Math.floor(currentWave / 7); for (var i = 0; i < cloudCount; i++) { var angle = i / cloudCount * Math.PI * 2; var distance = 200 + Math.random() * 300; var cloudX = self.x + Math.cos(angle) * distance; var cloudY = self.y + Math.sin(angle) * distance; var toxicCloud = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, x: cloudX, y: cloudY, tint: 0x00FF00, scaleX: 3, scaleY: 3, alpha: 0.7 }); game.addChild(toxicCloud); // Animate toxic cloud tween(toxicCloud, { alpha: 0, scaleX: 5, scaleY: 5 }, { duration: 4000, onFinish: function onFinish() { toxicCloud.destroy(); } }); // Damage anything near the cloud var checkCloud = LK.setInterval(function (cloudPos) { return function () { // Check for guardian in range if (guardian) { var dx = guardian.x - cloudPos.x; var dy = guardian.y - cloudPos.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Damage the heart tree heartTree.takeDamage(2); // Visual effect LK.effects.flashObject(guardian, 0x00FF00, 100); } } }; }({ "x": cloudX, "y": cloudY }), 500); // Clear interval when cloud is gone LK.setTimeout(function (interval) { return function () { LK.clearInterval(interval); }; }(checkCloud), 4000); } } else if (attackType === 1) { // Spawn infection minions var minionCount = 2 + Math.floor(currentWave / 6); for (var i = 0; i < minionCount; i++) { var minion; if (Math.random() < 0.5) { minion = new AcidEnemy(); } else { minion = new PoisonEnemy(); } minion.x = self.x; minion.y = self.y; minion.pathIndex = self.pathIndex; minion.maxHealth = 40; minion.health = minion.maxHealth; // Make minions smaller minion.scale.set(0.8, 0.8); game.addChild(minion); enemies.push(minion); enemiesRemaining++; } } else { // Viral infection - heals self and damages heart tree var healAmount = Math.min(self.maxHealth - self.health, self.maxHealth * 0.15); if (healAmount > 0) { self.health += healAmount; // Create healing effect var healEffect = new Text2("+" + Math.floor(healAmount), { size: 40, fill: 0x00FF00 }); healEffect.anchor.set(0.5, 0.5); healEffect.x = self.x; healEffect.y = self.y - 50; game.addChild(healEffect); // Animate healing text tween(healEffect, { alpha: 0, y: healEffect.y - 50 }, { duration: 1000, onFinish: function onFinish() { healEffect.destroy(); } }); } // Damage heart tree directly heartTree.takeDamage(5); // Visual effect showing infection spread to heart tree var infectionLine = new Container(); for (var i = 0; i < 10; i++) { var segment = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, tint: 0x00FF00, scaleX: 0.5, scaleY: 0.5, alpha: 0.7 }); segment.x = self.x + (heartTree.x - self.x) * (i / 10); segment.y = self.y + (heartTree.y - self.y) * (i / 10); infectionLine.addChild(segment); } game.addChild(infectionLine); // Animate and remove infection line LK.setTimeout(function () { infectionLine.destroy(); }, 1000); } }; return self; }); var AcidEnemy = Enemy.expand(function () { var self = Enemy.call(this); // Replace with custom graphics self.removeChildAt(0); // Remove default enemy graphics var acidGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0x00AA00, // Darker green tint for acid enemies scaleX: 1.2, scaleY: 1.2 }); self.speed = 1.6; self.maxHealth = 90; self.health = self.maxHealth; self.value = 22; self.lastAcidTime = 0; self.acidInterval = 2; // Seconds between acid puddles // Override update to add acid trail self.update = function () { if (!self.alive) { return; } // Call parent update method for movement Enemy.prototype.update.call(self); // Add acid trail behavior var currentTime = LK.ticks / 60; if (currentTime - self.lastAcidTime >= self.acidInterval) { self.lastAcidTime = currentTime; self.dropAcid(); } }; self.dropAcid = function () { // Create an acid puddle that damages the guardian var acid = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, tint: 0x00FF00, scaleX: 1.8, scaleY: 0.4, alpha: 0.7 }); game.addChild(acid); // Animate acid puddle tween(acid, { alpha: 0, scaleX: 2.5, scaleY: 0.2 }, { duration: 5000, onFinish: function onFinish() { acid.destroy(); } }); // Check if guardian is in acid puddle var checkAcid = LK.setInterval(function () { if (guardian) { var dx = guardian.x - acid.x; var dy = guardian.y - acid.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 60) { // Damage the heart tree if guardian is in acid heartTree.takeDamage(1); // Visual effect on guardian LK.effects.flashObject(guardian, 0x00FF00, 200); } } }, 500); // Clear interval when acid is gone LK.setTimeout(function () { LK.clearInterval(checkAcid); }, 5000); }; return self; }); var Essence = Container.expand(function () { var self = Container.call(this); var essenceGraphics = self.attachAsset('essence', { anchorX: 0.5, anchorY: 0.5 }); self.value = 10; self.lifeTime = 10; // seconds self.creationTime = LK.ticks / 60; self.collected = false; self.update = function () { if (self.collected) { return; } // Check if guardian is close enough to collect var dx = guardian.x - self.x; var dy = guardian.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 80) { self.collect(); return; } // Check if timed out var currentTime = LK.ticks / 60; if (currentTime - self.creationTime > self.lifeTime) { self.collected = true; } // Pulse animation var pulseFactor = 1 + Math.sin(LK.ticks / 20) * 0.1; self.scale.set(pulseFactor, pulseFactor); }; self.collect = function () { essence += self.value; updateEssenceText(); self.collected = true; LK.getSound('essenceCollected').play(); // Animate collection tween(self, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); var Guardian = Container.expand(function () { var self = Container.call(this); var guardianGraphics = self.attachAsset('guardian', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 7; self.targetX = null; self.targetY = null; self.moving = false; self.update = function () { if (self.moving && self.targetX !== null && self.targetY !== null) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // If near target, stop moving if (distance < 10) { self.moving = false; self.targetX = null; self.targetY = null; } else { // Move towards target var angle = Math.atan2(dy, dx); var nextX = self.x + Math.cos(angle) * self.speed; var nextY = self.y + Math.sin(angle) * self.speed; // Check if the next position is valid if (isPositionValid(nextX, nextY)) { self.x = nextX; self.y = nextY; } else { self.moving = false; } } } }; self.moveTo = function (x, y) { if (isPositionValid(x, y)) { self.targetX = x; self.targetY = y; self.moving = true; } }; return self; }); var HeartTree = Container.expand(function () { var self = Container.call(this); var treeGraphics; if (gameDifficulty === 'race') { treeGraphics = self.attachAsset('finishline', { anchorX: 0.5, anchorY: 0.5 }); } else if (gameDifficulty === 'infection') { treeGraphics = self.attachAsset('oldbuilding', { anchorX: 0.5, anchorY: 0.5 }); } else { treeGraphics = self.attachAsset('heartTree', { anchorX: 0.5, anchorY: 0.5 }); } self.maxHealth = 100; self.health = self.maxHealth; self.takeDamage = function (amount) { self.health -= amount; updateHealthBar(); LK.getSound('heartTreeDamage').play(); LK.effects.flashObject(self, 0xFF0000, 300); if (self.health <= 0) { // Game over LK.showGameOver(); // Update high score if needed if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } } }; return self; }); var PathTile = Container.expand(function () { var self = Container.call(this); var pathGraphics; if (gameDifficulty === 'race') { pathGraphics = self.attachAsset('racetrack', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9 }); } else if (gameDifficulty === 'infection') { pathGraphics = self.attachAsset('acidspill', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9 }); } else { pathGraphics = self.attachAsset('path', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); } self.gridX = 0; self.gridY = 0; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.damage = 10; self.target = null; self.alive = true; self.update = function () { if (!self.target || !self.target.alive) { self.alive = false; return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 20) { // Hit target if (typeof self.target.takeDamage === 'function') { self.target.takeDamage(self.damage); } self.alive = false; return; } // Move towards target var angle = Math.atan2(dy, dx); self.x += Math.cos(angle) * self.speed; self.y += Math.sin(angle) * self.speed; }; return self; }); var SpawnPoint = Container.expand(function () { var self = Container.call(this); var spawnGraphics; if (gameDifficulty === 'race') { spawnGraphics = self.attachAsset('car', { anchorX: 0.5, anchorY: 0.5 }); } else if (gameDifficulty === 'infection') { spawnGraphics = self.attachAsset('acidbarrel', { anchorX: 0.5, anchorY: 0.5 }); } else { spawnGraphics = self.attachAsset('spawnPoint', { anchorX: 0.5, anchorY: 0.5 }); } self.active = true; return self; }); var TitleScreen = Container.expand(function () { var self = Container.call(this); // Background overlay for title screen var overlay = self.attachAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732, tint: 0x122112, alpha: 0.8 }); // Game title self.title = new Text2('Forest Defender', { size: 180, fill: 0x83de44 }); self.title.anchor.set(0.5, 0.5); self.title.y = -500; self.addChild(self.title); // Subtitle self.subtitle = new Text2('Protect the Heart Tree!', { size: 80, fill: 0xFFFFFF }); self.subtitle.anchor.set(0.5, 0.5); self.subtitle.y = -350; self.addChild(self.subtitle); // Instructions self.instructions = new Text2('Build towers, collect essence\nand survive enemy waves', { size: 60, fill: 0xCCCCCC }); self.instructions.anchor.set(0.5, 0.5); self.instructions.y = -150; self.addChild(self.instructions); // Create difficulty buttons self.easyBtn = new Container(); var easyBtnBg = LK.getAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 100, tint: 0x00AA00 // Green for easy }); self.easyBtn.addChild(easyBtnBg); var easyBtnText = new Text2('EASY', { size: 60, fill: 0xFFFFFF }); easyBtnText.anchor.set(0.5, 0.5); self.easyBtn.addChild(easyBtnText); self.easyBtn.y = 50; self.addChild(self.easyBtn); self.normalBtn = new Container(); var normalBtnBg = LK.getAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 100, tint: 0x0088AA // Blue for normal }); self.normalBtn.addChild(normalBtnBg); var normalBtnText = new Text2('NORMAL', { size: 60, fill: 0xFFFFFF }); normalBtnText.anchor.set(0.5, 0.5); self.normalBtn.addChild(normalBtnText); self.normalBtn.y = 170; self.addChild(self.normalBtn); self.hardBtn = new Container(); var hardBtnBg = LK.getAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 100, tint: 0xAA0000 // Red for hard }); self.hardBtn.addChild(hardBtnBg); var hardBtnText = new Text2('HARD', { size: 60, fill: 0xFFFFFF }); hardBtnText.anchor.set(0.5, 0.5); self.hardBtn.addChild(hardBtnText); self.hardBtn.y = 290; self.addChild(self.hardBtn); // Race mode button self.raceBtn = new Container(); var raceBtnBg = LK.getAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 100, tint: 0xFF5500 // Orange for race }); self.raceBtn.addChild(raceBtnBg); var raceBtnText = new Text2('RACE', { size: 60, fill: 0xFFFFFF }); raceBtnText.anchor.set(0.5, 0.5); self.raceBtn.addChild(raceBtnText); self.raceBtn.y = 410; self.addChild(self.raceBtn); // Infection mode button self.infectionBtn = new Container(); var infectionBtnBg = LK.getAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 100, tint: 0x00AA00 // Green for infection }); self.infectionBtn.addChild(infectionBtnBg); var infectionBtnText = new Text2('INFECTION', { size: 50, fill: 0xFFFFFF }); infectionBtnText.anchor.set(0.5, 0.5); self.infectionBtn.addChild(infectionBtnText); self.infectionBtn.y = 530; self.addChild(self.infectionBtn); // High score display self.highScoreText = new Text2('High Score: ' + storage.highScore, { size: 50, fill: 0xFFD700 }); self.highScoreText.anchor.set(0.5, 0.5); self.highScoreText.y = 650; // Moved lower to make room for all difficulty buttons self.addChild(self.highScoreText); // Add pulsing animation to difficulty buttons self.update = function () { var pulseFactor = 1 + Math.sin(LK.ticks / 20) * 0.05; self.easyBtn.scale.set(pulseFactor, pulseFactor); self.normalBtn.scale.set(pulseFactor, pulseFactor); self.hardBtn.scale.set(pulseFactor, pulseFactor); self.raceBtn.scale.set(pulseFactor, pulseFactor); self.infectionBtn.scale.set(pulseFactor, pulseFactor); }; // Difficulty button event handlers self.easyBtn.down = function () { // Set game difficulty to easy gameDifficulty = 'easy'; // Create fade out effect tween(self, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.destroy(); initGame(); } }); }; self.normalBtn.down = function () { // Set game difficulty to normal gameDifficulty = 'normal'; // Create fade out effect tween(self, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.destroy(); initGame(); } }); }; self.hardBtn.down = function () { // Set game difficulty to hard gameDifficulty = 'hard'; // Create fade out effect tween(self, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.destroy(); initGame(); } }); }; self.raceBtn.down = function () { // Set game difficulty to race gameDifficulty = 'race'; // Create fade out effect tween(self, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.destroy(); initGame(); } }); }; self.infectionBtn.down = function () { // Set game difficulty to infection gameDifficulty = 'infection'; // Create fade out effect tween(self, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.destroy(); initGame(); } }); }; return self; }); var Tower = Container.expand(function () { var self = Container.call(this); var baseGraphics = self.attachAsset('towerBase', { anchorX: 0.5, anchorY: 0.5 }); self.gridX = 0; self.gridY = 0; self.range = 300; self.damage = 10; self.attackSpeed = 1; // attacks per second self.lastAttackTime = 0; self.level = 1; self.target = null; self.projectiles = []; self.findTarget = function () { var closestEnemy = null; var closestDistance = self.range; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } return closestEnemy; }; self.attack = function () { if (!self.target || !self.target.alive) { self.target = self.findTarget(); } if (self.target) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > self.range) { self.target = null; return; } var currentTime = LK.ticks / 60; if (currentTime - self.lastAttackTime >= 1 / self.attackSpeed) { self.lastAttackTime = currentTime; self.fireProjectile(); } } }; self.fireProjectile = function () { var projectile = new Projectile(); projectile.damage = self.damage; projectile.target = self.target; projectile.x = self.x; projectile.y = self.y; game.addChild(projectile); self.projectiles.push(projectile); LK.getSound('projectileShot').play(); }; self.down = function (x, y, obj) { // If in delete mode, sell the tower if (currentMode === 'delete') { // Find the tower's type to determine sell value var towerType = ''; if (self instanceof ThornTower) { towerType = 'thorn'; } else if (self instanceof ShroomTower) { towerType = 'shroom'; } else if (self instanceof FlameTower) { towerType = 'flame'; } else if (self instanceof FarmTower) { towerType = 'healing'; } // Add essence based on tower type essence += towerSellValues[towerType]; updateEssenceText(); // Find and mark the building spot as unoccupied for (var i = 0; i < buildingSpots.length; i++) { if (buildingSpots[i].gridX === self.gridX && buildingSpots[i].gridY === self.gridY) { buildingSpots[i].occupied = false; buildingSpots[i].tower = null; break; } } // Remove tower from towers array for (var i = 0; i < towers.length; i++) { if (towers[i] === self) { towers.splice(i, 1); break; } } // Show sell effect var sellEffect = new Text2("+" + towerSellValues[towerType], { size: 40, fill: 0xFFD700 }); sellEffect.anchor.set(0.5, 0.5); sellEffect.x = self.x; sellEffect.y = self.y; game.addChild(sellEffect); // Animate the effect tween(sellEffect, { alpha: 0, y: sellEffect.y - 50 }, { duration: 1000, onFinish: function onFinish() { sellEffect.destroy(); } }); // Destroy the tower self.destroy(); } }; self.update = function () { self.attack(); // Update projectiles for (var i = self.projectiles.length - 1; i >= 0; i--) { var projectile = self.projectiles[i]; if (!projectile.alive) { projectile.destroy(); self.projectiles.splice(i, 1); } } }; return self; }); var ThornTower = Tower.expand(function () { var self = Tower.call(this); var towerGraphics = self.attachAsset('thornTower', { anchorX: 0.5, anchorY: 0.5, y: -20 // Offset to position on base }); self.range = 350; self.damage = 15; self.attackSpeed = 1.2; return self; }); var ShroomTower = Tower.expand(function () { var self = Tower.call(this); var towerGraphics = self.attachAsset('shroomTower', { anchorX: 0.5, anchorY: 0.5, y: -20 // Offset to position on base }); self.range = 250; self.damage = 25; self.attackSpeed = 0.8; return self; }); var FlameTower = Tower.expand(function () { var self = Tower.call(this); // Remove default base and add custom base with red tint self.removeChildAt(0); var baseGraphics = self.attachAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF8800 }); var towerGraphics = self.attachAsset('flameTower', { anchorX: 0.5, anchorY: 0.5, y: -20, // Offset to position on base tint: 0xFF3300 }); self.range = 200; // Short range self.damage = 8; // Lower damage per hit self.attackSpeed = 2.5; // Fast attack speed self.areaOfEffect = true; // This tower hits multiple enemies // Override the fireProjectile method for area attack self.fireProjectile = function () { // Find all enemies in range var hitEnemies = []; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.range) { hitEnemies.push(enemy); // Visual effect - flame burst var flameBurst = LK.getAsset('projectile', { anchorX: 0.5, anchorY: 0.5, x: enemy.x, y: enemy.y, tint: 0xFF4500, scaleX: 1.5, scaleY: 1.5 }); game.addChild(flameBurst); // Animate and remove flame effect tween(flameBurst, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { flameBurst.destroy(); } }); // Damage the enemy enemy.takeDamage(self.damage); } } if (hitEnemies.length > 0) { LK.getSound('projectileShot').play(); } }; return self; }); var FarmTower = Tower.expand(function () { var self = Tower.call(this); // Remove default base and add custom base with gold tint self.removeChildAt(0); var baseGraphics = self.attachAsset('towerBase', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFD700 }); var towerGraphics = self.attachAsset('farmTower', { anchorX: 0.5, anchorY: 0.5, y: -20 // Offset to position on base }); self.range = 280; self.incomeAmount = 25; // Base income per wave self.level = 1; // Override the attack method to do nothing - this tower doesn't attack self.attack = function () { // Instead, just pulsate to show it's active if (LK.ticks % 60 == 0) { // Visual effect on self - gold coins visual var coinEffect = LK.getAsset('essence', { anchorX: 0.5, anchorY: 0.5, x: self.x + (Math.random() * 40 - 20), y: self.y + (Math.random() * 40 - 20), tint: 0xFFD700, alpha: 0.7 }); game.addChild(coinEffect); // Animate and remove coin effect tween(coinEffect, { alpha: 0, y: coinEffect.y - 50, scaleX: 0.5, scaleY: 0.5 }, { duration: 800, onFinish: function onFinish() { coinEffect.destroy(); } }); } }; // Get income amount based on level self.getIncomePerWave = function () { return Math.floor(self.incomeAmount * (1 + (self.level - 1) * 0.5)); }; // Override the fireProjectile to do nothing self.fireProjectile = function () {}; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2E5C2E // Forest green }); /**** * Game Code ****/ // Game variables var gameDifficulty = 'normal'; // Default difficulty: 'normal', 'easy', 'hard', or 'race' var deleteBtn = new Container(); // Add delete button container function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) { return; } f = !1; } else { for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) { ; } } } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) { return; } } finally { if (o) { throw n; } } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) { return r; } } var gridSize = 120; var currentMode = 'guardian'; // 'guardian', 'building', or 'delete' var selectedTower = 'thorn'; var essence = 100; var currentWave = 0; var waveInProgress = false; var waveTimer = null; var enemiesRemaining = 0; var towers = []; var enemies = []; var essenceItems = []; var buildingSpots = []; var path = []; var spawnPoints = []; var guardian; // Reference to the guardian instance var heartTree = null; // Reference to the heart tree instance // Tower costs var towerCosts = { 'thorn': 50, 'shroom': 100, 'flame': 150, 'healing': 200 }; // Tower sell values (will be calculated based on cost and level) var towerSellValues = { 'thorn': Math.floor(towerCosts['thorn'] * 0.7), 'shroom': Math.floor(towerCosts['shroom'] * 0.7), 'flame': Math.floor(towerCosts['flame'] * 0.7), 'healing': Math.floor(towerCosts['healing'] * 0.7) }; // Create UI elements var scoreTxt = new Text2('0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var essenceTxt = new Text2('💎 100', { size: 70, fill: 0x00FFFF }); essenceTxt.anchor.set(0, 0); essenceTxt.x = -250; // Move it away from the edge LK.gui.topRight.addChild(essenceTxt); var waveTxt = new Text2('Wave: 0', { size: 50, fill: 0xFFFFFF }); waveTxt.anchor.set(1, 0); LK.gui.topLeft.addChild(waveTxt); // Position away from the top left corner where menu icon is waveTxt.x = 150; var healthBarBg = new Container(); var healthBarFill = new Container(); var healthBarTxt = new Text2('100/100', { size: 40, fill: 0xFFFFFF }); healthBarTxt.anchor.set(0.5, 0.5); // Setup health bar function setupHealthBar() { // Background bar var healthBg = LK.getAsset('healthBarBg', { anchorX: 0, anchorY: 0, width: 300, height: 40 }); healthBarBg.addChild(healthBg); // Fill bar var healthFill = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0, width: 300, height: 40 }); healthBarFill.addChild(healthFill); // Add to GUI LK.gui.bottom.addChild(healthBarBg); LK.gui.bottom.addChild(healthBarFill); LK.gui.bottom.addChild(healthBarTxt); // Position health bar healthBarBg.x = -150; // Center the healthbar healthBarFill.x = -150; // Center the healthbar fill healthBarTxt.x = 0; // Center the text healthBarBg.y = -80; // Position below start wave button (which is at -150) healthBarFill.y = -80; // Match background position healthBarTxt.y = -60; // Position text in middle of healthbar } // Update health bar function updateHealthBar() { var healthPercent = heartTree.health / heartTree.maxHealth; healthBarFill.scale.x = healthPercent; healthBarTxt.setText(heartTree.health + '/' + heartTree.maxHealth); // Update color based on health percentage var fill = healthBarFill.getChildAt(0); if (healthPercent > 0.6) { fill.tint = 0x00FF00; // Green } else if (healthPercent > 0.3) { fill.tint = 0xFFFF00; // Yellow } else { fill.tint = 0xFF0000; // Red } // Flash effect when health is low if (healthPercent < 0.2 && LK.ticks % 60 < 30) { healthBarFill.alpha = 0.7; } else { healthBarFill.alpha = 1.0; } } // Create game mode buttons var guardianBtn = new Container(); var buildBtn = new Container(); function setupModeButtons() { // Guardian mode button var guardianBtnBg = LK.getAsset('moveButton', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); guardianBtn.addChild(guardianBtnBg); var guardianBtnTxt = new Text2('Move', { size: 30, fill: 0xFFFFFF }); guardianBtnTxt.anchor.set(0.5, 0.5); guardianBtnTxt.y = 50; guardianBtn.addChild(guardianBtnTxt); // Building mode button var buildBtnBg = LK.getAsset('buildButton', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); buildBtn.addChild(buildBtnBg); var buildBtnTxt = new Text2('Build', { size: 30, fill: 0xFFFFFF }); buildBtnTxt.anchor.set(0.5, 0.5); buildBtnTxt.y = 50; buildBtn.addChild(buildBtnTxt); // Delete button var deleteBtn = new Container(); var deleteBtnBg = LK.getAsset('deleteButton', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); deleteBtn.addChild(deleteBtnBg); var deleteBtnTxt = new Text2('Delete', { size: 30, fill: 0xFFFFFF }); deleteBtnTxt.anchor.set(0.5, 0.5); deleteBtnTxt.y = 50; deleteBtn.addChild(deleteBtnTxt); // Add to GUI LK.gui.bottomLeft.addChild(guardianBtn); LK.gui.bottomLeft.addChild(buildBtn); LK.gui.bottomLeft.addChild(deleteBtn); // Position buttons guardianBtn.x = 100; guardianBtn.y = -100; buildBtn.x = 220; buildBtn.y = -100; deleteBtn.x = 340; deleteBtn.y = -100; // Add event listeners guardianBtn.interactive = true; guardianBtn.down = function () { setGameMode('guardian'); }; buildBtn.interactive = true; buildBtn.down = function () { setGameMode('building'); }; deleteBtn.interactive = true; deleteBtn.down = function () { setGameMode('delete'); }; // Highlight current mode updateModeButtons(); } // Create tower selection buttons var thornBtn = new Container(); var shroomBtn = new Container(); var flameBtn = new Container(); var healingBtn = new Container(); function setupTowerButtons() { // Thorn tower button var thornBtnBg = LK.getAsset('thornTower', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); thornBtn.addChild(thornBtnBg); var thornBtnTxt = new Text2('50', { size: 30, fill: 0xFFFFFF }); thornBtnTxt.anchor.set(0.5, 0.5); thornBtnTxt.y = 50; thornBtn.addChild(thornBtnTxt); // Shroom tower button var shroomBtnBg = LK.getAsset('shroomTower', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); shroomBtn.addChild(shroomBtnBg); var shroomBtnTxt = new Text2('100', { size: 30, fill: 0xFFFFFF }); shroomBtnTxt.anchor.set(0.5, 0.5); shroomBtnTxt.y = 50; shroomBtn.addChild(shroomBtnTxt); // Flame tower button var flameBtnBg = LK.getAsset('flameTower', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80, tint: 0xFF3300 }); flameBtn.addChild(flameBtnBg); var flameBtnTxt = new Text2('150', { size: 30, fill: 0xFFFFFF }); flameBtnTxt.anchor.set(0.5, 0.5); flameBtnTxt.y = 50; flameBtn.addChild(flameBtnTxt); // Farm tower button var healingBtnBg = LK.getAsset('farmTower', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); healingBtn.addChild(healingBtnBg); var healingBtnTxt = new Text2('200', { size: 30, fill: 0xFFFFFF }); healingBtnTxt.anchor.set(0.5, 0.5); healingBtnTxt.y = 50; healingBtn.addChild(healingBtnTxt); // Add to GUI LK.gui.bottomRight.addChild(thornBtn); LK.gui.bottomRight.addChild(shroomBtn); LK.gui.bottomRight.addChild(flameBtn); LK.gui.bottomRight.addChild(healingBtn); // Position buttons thornBtn.x = -100; thornBtn.y = -100; shroomBtn.x = -220; shroomBtn.y = -100; flameBtn.x = -100; flameBtn.y = -200; healingBtn.x = -220; healingBtn.y = -200; // Add event listeners thornBtn.interactive = true; thornBtn.down = function () { if (currentMode === 'building') { selectTower('thorn'); } }; shroomBtn.interactive = true; shroomBtn.down = function () { if (currentMode === 'building' && storage.unlockedTowers.includes('shroom')) { selectTower('shroom'); } }; flameBtn.interactive = true; flameBtn.down = function () { if (currentMode === 'building' && storage.unlockedTowers.includes('flame')) { selectTower('flame'); } }; healingBtn.interactive = true; healingBtn.down = function () { if (currentMode === 'building' && storage.unlockedTowers.includes('healing')) { selectTower('healing'); } }; // If towers are not unlocked, gray them out if (!storage.unlockedTowers.includes('shroom')) { shroomBtn.alpha = 0.5; } if (!storage.unlockedTowers.includes('flame')) { flameBtn.alpha = 0.5; } if (!storage.unlockedTowers.includes('healing')) { healingBtn.alpha = 0.5; } // Highlight selected tower updateTowerButtons(); } // Start wave button var startWaveBtn = new Container(); function setupStartWaveButton() { var startWaveButtonBg = LK.getAsset('waveButton', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 80 }); startWaveBtn.addChild(startWaveButtonBg); var startWaveBtnTxt = new Text2('Start Wave', { size: 40, fill: 0xFFFFFF }); startWaveBtnTxt.anchor.set(0.5, 0.5); startWaveBtn.addChild(startWaveBtnTxt); // Add to GUI LK.gui.bottom.addChild(startWaveBtn); // Position button startWaveBtn.y = -150; // Pulsing animation for wave button when not in wave var pulseInterval = LK.setInterval(function () { if (!waveInProgress) { var pulseFactor = 1 + Math.sin(LK.ticks / 20) * 0.1; startWaveBtn.scale.set(pulseFactor, pulseFactor); } else { startWaveBtn.scale.set(1, 1); } }, 100); // Add event listener startWaveBtn.interactive = true; startWaveBtn.down = function () { if (!waveInProgress) { startWave(); } }; } function updateModeButtons() { guardianBtn.alpha = currentMode === 'guardian' ? 1.0 : 0.6; buildBtn.alpha = currentMode === 'building' ? 1.0 : 0.6; deleteBtn.alpha = currentMode === 'delete' ? 1.0 : 0.6; } function updateTowerButtons() { thornBtn.alpha = currentMode === 'building' && selectedTower === 'thorn' ? 1.0 : 0.6; shroomBtn.alpha = currentMode === 'building' && selectedTower === 'shroom' && storage.unlockedTowers.includes('shroom') ? 1.0 : 0.3; flameBtn.alpha = currentMode === 'building' && selectedTower === 'flame' && storage.unlockedTowers.includes('flame') ? 1.0 : 0.3; healingBtn.alpha = currentMode === 'building' && selectedTower === 'healing' && storage.unlockedTowers.includes('healing') ? 1.0 : 0.3; } function setGameMode(mode) { currentMode = mode; updateModeButtons(); updateTowerButtons(); } function selectTower(tower) { selectedTower = tower; updateTowerButtons(); } function updateEssenceText() { essenceTxt.setText('💎 ' + essence); // Flash effect when essence is gained/lost LK.effects.flashObject(essenceTxt, 0x00FFFF, 300); } function createLevel() { // Clear any existing level elements for (var i = 0; i < buildingSpots.length; i++) { buildingSpots[i].destroy(); } buildingSpots = []; path = []; spawnPoints = []; // Level dimensions (in grid cells) var levelWidth = 15; var levelHeight = 19; // Create a grid for the level var grid = []; for (var y = 0; y < levelHeight; y++) { grid[y] = []; for (var x = 0; x < levelWidth; x++) { grid[y][x] = 0; // 0 = empty } } // Define path through the level (1 = path) var pathCoords = [[0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 9], [6, 9], [6, 8], [6, 7], [6, 6], [6, 5], [7, 5], [8, 5], [9, 5], [9, 6], [9, 7], [9, 8], [9, 9], [9, 10], [9, 11], [8, 11], [7, 11], [6, 11], [5, 11], [4, 11], [4, 12], [4, 13], [4, 14], [4, 15], [5, 15], [6, 15], [7, 15], [8, 15], [9, 15], [10, 15], [11, 15], [11, 14], [11, 13], [11, 12], [11, 11], [11, 10], [11, 9], [11, 8], [11, 7], [12, 7], [13, 7], [14, 7]]; for (var i = 0; i < pathCoords.length; i++) { var _pathCoords$i = _slicedToArray(pathCoords[i], 2), x = _pathCoords$i[0], y = _pathCoords$i[1]; grid[y][x] = 1; } // Set spawn point (2 = spawn) grid[9][0] = 2; // Set heart tree location (3 = heart tree) grid[7][14] = 3; // Create level elements based on grid for (var y = 0; y < levelHeight; y++) { for (var x = 0; x < levelWidth; x++) { var gridValue = grid[y][x]; var worldX = x * gridSize + gridSize / 2 + 174; // Center in grid cell with some offset var worldY = y * gridSize + gridSize / 2 + 150; if (gridValue === 1) { // Path tile var pathTile = new PathTile(); pathTile.x = worldX; pathTile.y = worldY; pathTile.gridX = x; pathTile.gridY = y; game.addChild(pathTile); // Add to path array for enemy movement path.push(pathTile); } else if (gridValue === 2) { // Spawn point var spawnPoint = new SpawnPoint(); spawnPoint.x = worldX; spawnPoint.y = worldY; game.addChild(spawnPoint); spawnPoints.push(spawnPoint); // Also add as first path point path.unshift(spawnPoint); } else if (gridValue === 3) { // Heart Tree heartTree = new HeartTree(); heartTree.x = worldX; heartTree.y = worldY; game.addChild(heartTree); } else if (gridValue === 0) { // Check if adjacent to path (can build here) var adjacentToPath = false; // Check all adjacent cells var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; for (var _i = 0, _directions = directions; _i < _directions.length; _i++) { var dir = _directions[_i]; var adjX = x + dir[0]; var adjY = y + dir[1]; if (adjX >= 0 && adjX < levelWidth && adjY >= 0 && adjY < levelHeight && grid[adjY][adjX] === 1) { adjacentToPath = true; break; } } if (adjacentToPath) { // Create building spot var spot = new BuildingSpot(); spot.x = worldX; spot.y = worldY; spot.gridX = x; spot.gridY = y; game.addChild(spot); buildingSpots.push(spot); } } } } // Sort path from start to end path.sort(function (a, b) { return pathCoords.findIndex(function (coords) { return coords[0] === a.gridX && coords[1] === a.gridY; }) - pathCoords.findIndex(function (coords) { return coords[0] === b.gridX && coords[1] === b.gridY; }); }); // Create guardian guardian = new Guardian(); guardian.x = path[Math.floor(path.length / 2)].x; guardian.y = path[Math.floor(path.length / 2)].y; game.addChild(guardian); } function startWave() { if (waveInProgress) { return; } currentWave++; waveTxt.setText('Wave: ' + currentWave); waveInProgress = true; startWaveBtn.alpha = 0.5; // Display wave start message var waveStartTxt = new Text2('Wave ' + currentWave + ' Starting!', { size: 80, fill: 0xFF8C00 }); waveStartTxt.anchor.set(0.5, 0.5); waveStartTxt.x = 2048 / 2; waveStartTxt.y = 2732 / 2; game.addChild(waveStartTxt); // Animate and remove wave start message tween(waveStartTxt, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 1500, onFinish: function onFinish() { waveStartTxt.destroy(); } }); // Calculate enemies for this wave var numEnemies = 5 + Math.floor(currentWave * 1.5); var hasBoss = currentWave % 5 === 0; enemiesRemaining = numEnemies + (hasBoss ? 1 : 0); LK.getSound('waveStart').play(); // Spawn enemies periodically var enemiesSpawned = 0; waveTimer = LK.setInterval(function () { if (enemiesSpawned < numEnemies) { spawnEnemy(false); enemiesSpawned++; } else if (hasBoss && enemiesSpawned === numEnemies) { spawnEnemy(true); // Spawn boss enemiesSpawned++; } else { LK.clearInterval(waveTimer); } }, 1500); } function spawnEnemy(isBoss) { var enemy; // Apply difficulty multipliers var healthMultiplier = 1.0; var speedMultiplier = 1.0; var valueMultiplier = 1.0; // Handle race mode separately if (gameDifficulty === 'race') { if (isBoss) { enemy = new BossEnemy(); // Make boss race-themed enemy.speed *= 1.5; enemy.maxHealth *= 0.8; enemy.health = enemy.maxHealth; } else { // In race mode, spawn mostly race enemies with some speedy enemies var raceRandom = Math.random(); if (raceRandom < 0.7 || currentWave < 2) { // 70% chance of spawning race enemy enemy = new RaceEnemy(); // Scale difficulty with wave number enemy.maxHealth = 25 + currentWave * 3; enemy.health = enemy.maxHealth; enemy.speed = 6 + currentWave * 0.25; // Even faster with each wave enemy.value = 20 + currentWave * 2; } else if (raceRandom < 0.9) { // 20% chance of spawning speedy enemy in race mode enemy = new SpeedyEnemy(); enemy.maxHealth = 30 + currentWave * 4; enemy.health = enemy.maxHealth; enemy.speed = 4.5 + currentWave * 0.2; // Faster than normal mode enemy.value = 15 + currentWave; // Special visual effects for race mode speedies enemy.getChildAt(0).tint = 0xFFAA00; // More orange than yellow } else { // 10% chance of flying enemy after wave 3 if (currentWave >= 3) { enemy = new FlyingEnemy(); enemy.maxHealth = 40 + currentWave * 4; enemy.health = enemy.maxHealth; enemy.speed = 4 + currentWave * 0.15; // Faster than normal mode enemy.value = 25 + currentWave; // Change color for race mode enemy.getChildAt(0).tint = 0xFF3300; // More reddish } else { // Fallback to race enemy if flying is not available yet enemy = new RaceEnemy(); enemy.maxHealth = 25 + currentWave * 3; enemy.health = enemy.maxHealth; enemy.speed = 6 + currentWave * 0.25; enemy.value = 20 + currentWave * 2; } } } } else if (gameDifficulty === 'infection') { if (isBoss) { enemy = new InfectionBossEnemy(); // Adjust boss for infection theme enemy.maxHealth = 350 + currentWave * 30; enemy.health = enemy.maxHealth; } else { // In infection mode, spawn mostly poison-based enemies var infectionRandom = Math.random(); if (infectionRandom < 0.3 || currentWave < 2) { // Basic poison enemy enemy = new PoisonEnemy(); // Scale with wave enemy.maxHealth = 80 + currentWave * 7; enemy.health = enemy.maxHealth; enemy.speed = 1.8 + currentWave * 0.1; enemy.value = 20 + currentWave; // Faster shot interval enemy.shotInterval = Math.max(1.5, 3 - currentWave * 0.25); } else if (infectionRandom < 0.6) { // Acid enemy enemy = new AcidEnemy(); // Scale with wave enemy.maxHealth = 90 + currentWave * 8; enemy.health = enemy.maxHealth; enemy.speed = 1.6 + currentWave * 0.08; enemy.value = 22 + currentWave; // More frequent acid drops at higher waves enemy.acidInterval = Math.max(1.0, 2 - currentWave * 0.15); } else if (infectionRandom < 0.8 && currentWave >= 3) { // Toxic blob enemy spawns after wave 3 enemy = new ToxicBlobEnemy(); // Scale with wave enemy.maxHealth = 140 + currentWave * 10; enemy.health = enemy.maxHealth; enemy.speed = 1.3 + currentWave * 0.06; enemy.value = 30 + currentWave * 1.5; } else if (infectionRandom < 0.9 && currentWave >= 4) { // Flying enemy with poison theme enemy = new FlyingEnemy(); enemy.maxHealth = 40 + currentWave * 5; enemy.health = enemy.maxHealth; enemy.speed = 3 + currentWave * 0.12; enemy.value = 18 + currentWave; // Change color for infection theme enemy.getChildAt(0).tint = 0x00FF00; // Green tint } else { // Default to normal enemy with poison tint as fallback enemy = new Enemy(); enemy.maxHealth = 50 + currentWave * 6; enemy.health = enemy.maxHealth; enemy.speed = 2 + currentWave * 0.1; enemy.value = 10 + currentWave; // Add green tint enemy.getChildAt(0).tint = 0x88FF88; } } } else { // Normal, Easy, Hard difficulties if (gameDifficulty === 'easy') { healthMultiplier = 0.8; // Enemies have less health speedMultiplier = 0.9; // Enemies move slower valueMultiplier = 1.2; // Enemies give more essence } else if (gameDifficulty === 'hard') { healthMultiplier = 1.3; // Enemies have more health speedMultiplier = 1.2; // Enemies move faster valueMultiplier = 0.8; // Enemies give less essence } if (isBoss) { enemy = new BossEnemy(); } else { // Randomly choose enemy type based on wave progression var randomType = Math.random(); if (currentWave >= 6 && randomType < 0.15) { // 15% chance of spawning flying enemy after wave 6 enemy = new FlyingEnemy(); // Scale difficulty with wave number enemy.maxHealth = Math.floor((40 + currentWave * 5) * healthMultiplier); enemy.health = enemy.maxHealth; enemy.speed = (3 + currentWave * 0.12) * speedMultiplier; enemy.value = Math.floor((18 + currentWave) * valueMultiplier); } else if (currentWave >= 7 && randomType < 0.3) { // 15% chance of spawning poison enemy after wave 7 enemy = new PoisonEnemy(); // Scale difficulty with wave number enemy.maxHealth = 80 + currentWave * 8; enemy.health = enemy.maxHealth; enemy.speed = 1.8 + currentWave * 0.08; enemy.value = 20 + currentWave; enemy.shotInterval = Math.max(1.5, 3 - currentWave * 0.2); // Shoot faster at higher waves } else if (currentWave >= 5 && randomType < 0.45) { // 15% chance of spawning split enemy after wave 5 enemy = new SplitEnemy(); // Scale difficulty with wave number enemy.maxHealth = 70 + currentWave * 12; enemy.health = enemy.maxHealth; enemy.speed = 1.5 + currentWave * 0.06; enemy.value = 12 + currentWave; enemy.splitCount = 2 + Math.floor(currentWave / 10); // More splits at higher waves, max 4 } else if (currentWave >= 2 && randomType < 0.65) { // 20% chance of spawning speedy enemy after wave 2 enemy = new SpeedyEnemy(); // Scale difficulty with wave number enemy.maxHealth = 30 + currentWave * 6; enemy.health = enemy.maxHealth; enemy.speed = 4 + currentWave * 0.15; enemy.value = 15 + currentWave; } else if (currentWave >= 4 && randomType < 0.8) { // 15% chance of spawning tank enemy after wave 4 enemy = new TankEnemy(); // Scale difficulty with wave number enemy.maxHealth = 120 + currentWave * 15; enemy.health = enemy.maxHealth; enemy.speed = 1 + currentWave * 0.05; enemy.value = 25 + currentWave; } else { // Regular enemy enemy = new Enemy(); // Scale difficulty with wave number enemy.maxHealth = 50 + currentWave * 10; enemy.health = enemy.maxHealth; enemy.speed = 2 + currentWave * 0.1; enemy.value = 10 + currentWave; } } } // Set initial position at spawn point var spawnPoint = spawnPoints[0]; enemy.x = spawnPoint.x; enemy.y = spawnPoint.y; game.addChild(enemy); enemies.push(enemy); // Apply animation for spawning enemy.alpha = 0; enemy.scale.set(0.5, 0.5); tween(enemy, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 500 }); } function checkWaveComplete() { if (waveInProgress && enemies.length === 0 && enemiesRemaining === 0) { waveInProgress = false; startWaveBtn.alpha = 1.0; // Reward between waves var waveBonus = 50 + currentWave * 10; // Add farm tower income var farmIncome = 0; for (var i = 0; i < towers.length; i++) { if (towers[i] instanceof FarmTower) { var income = towers[i].getIncomePerWave(); farmIncome += income; // Show visual effect for farm income var incomeTxt = new Text2("+" + income, { size: 40, fill: 0xFFD700 }); incomeTxt.anchor.set(0.5, 0.5); incomeTxt.x = towers[i].x; incomeTxt.y = towers[i].y; game.addChild(incomeTxt); // Animate text tween(incomeTxt, { alpha: 0, y: incomeTxt.y - 50 }, { duration: 1000, onFinish: function onFinish() { incomeTxt.destroy(); } }); } } essence += waveBonus + farmIncome; updateEssenceText(); // Show wave complete message var waveBonusTxt = new Text2('Wave Complete! +' + waveBonus + ' Essence', { size: 80, fill: 0xFFFFFF }); waveBonusTxt.anchor.set(0.5, 0.5); waveBonusTxt.x = 2048 / 2; waveBonusTxt.y = 2732 / 2; game.addChild(waveBonusTxt); // Animate and remove message tween(waveBonusTxt, { alpha: 0, y: waveBonusTxt.y - 100 }, { duration: 2000, onFinish: function onFinish() { waveBonusTxt.destroy(); } }); // Unlock new tower types based on wave progress if (currentWave === 3 && !storage.unlockedTowers.includes('shroom')) { storage.unlockedTowers.push('shroom'); shroomBtn.alpha = 0.6; // Show unlock message var unlockTxt = new Text2('New Tower Unlocked: Shroom Puff!', { size: 60, fill: 0xFFFF00 }); unlockTxt.anchor.set(0.5, 0.5); unlockTxt.x = 2048 / 2; unlockTxt.y = 2732 / 2 + 100; game.addChild(unlockTxt); // Animate and remove message tween(unlockTxt, { alpha: 0, y: unlockTxt.y - 100 }, { duration: 3000, onFinish: function onFinish() { unlockTxt.destroy(); } }); } else if (currentWave === 5 && !storage.unlockedTowers.includes('flame')) { storage.unlockedTowers.push('flame'); flameBtn.alpha = 0.6; // Show unlock message var unlockTxt = new Text2('New Tower Unlocked: Flame Fern!', { size: 60, fill: 0xFF5500 }); unlockTxt.anchor.set(0.5, 0.5); unlockTxt.x = 2048 / 2; unlockTxt.y = 2732 / 2 + 100; game.addChild(unlockTxt); // Animate and remove message tween(unlockTxt, { alpha: 0, y: unlockTxt.y - 100 }, { duration: 3000, onFinish: function onFinish() { unlockTxt.destroy(); } }); } else if (currentWave === 8 && !storage.unlockedTowers.includes('healing')) { storage.unlockedTowers.push('healing'); healingBtn.alpha = 0.6; // Show unlock message var unlockTxt = new Text2('New Tower Unlocked: Farm Shroom!', { size: 60, fill: 0xFFD700 }); unlockTxt.anchor.set(0.5, 0.5); unlockTxt.x = 2048 / 2; unlockTxt.y = 2732 / 2 + 100; game.addChild(unlockTxt); // Animate and remove message tween(unlockTxt, { alpha: 0, y: unlockTxt.y - 100 }, { duration: 3000, onFinish: function onFinish() { unlockTxt.destroy(); } }); } } } function isPositionValid(x, y) { // Check if position is within game bounds if (x < 0 || x > 2048 || y < 0 || y > 2732) { return false; } return true; } // Initialize game function initGame() { // Setup UI elements setupHealthBar(); setupModeButtons(); setupTowerButtons(); setupStartWaveButton(); // Create game level createLevel(); // Set initial game state LK.setScore(0); scoreTxt.setText('0'); // Apply difficulty settings if (gameDifficulty === 'easy') { essence = 200; // More starting essence heartTree.maxHealth = 150; // More health heartTree.health = heartTree.maxHealth; } else if (gameDifficulty === 'normal') { essence = 100; // Default starting essence heartTree.maxHealth = 100; // Default health heartTree.health = heartTree.maxHealth; } else if (gameDifficulty === 'hard') { essence = 50; // Less starting essence heartTree.maxHealth = 75; // Less health heartTree.health = heartTree.maxHealth; } else if (gameDifficulty === 'race') { essence = 150; // Moderate starting essence heartTree.maxHealth = 100; // Default health heartTree.health = heartTree.maxHealth; // Set game background to a darker color for race mode game.setBackgroundColor(0x1E3A1E); // Darker forest green // Show race mode announcement var raceModeTxt = new Text2('RACE MODE ACTIVATED!', { size: 80, fill: 0xFF5500 }); raceModeTxt.anchor.set(0.5, 0.5); raceModeTxt.x = 2048 / 2; raceModeTxt.y = 2732 / 2; game.addChild(raceModeTxt); // Animate and remove announcement tween(raceModeTxt, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 2000, onFinish: function onFinish() { raceModeTxt.destroy(); } }); } else if (gameDifficulty === 'infection') { essence = 120; // Moderate starting essence heartTree.maxHealth = 90; // Lower health due to infection damage heartTree.health = heartTree.maxHealth; // Set game background to a toxic green color for infection mode game.setBackgroundColor(0x1A3A1A); // Dark toxic green // Show infection mode announcement var infectionModeTxt = new Text2('INFECTION MODE ACTIVATED!', { size: 80, fill: 0x00FF00 }); infectionModeTxt.anchor.set(0.5, 0.5); infectionModeTxt.x = 2048 / 2; infectionModeTxt.y = 2732 / 2; game.addChild(infectionModeTxt); // Animate and remove announcement tween(infectionModeTxt, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 2000, onFinish: function onFinish() { infectionModeTxt.destroy(); } }); } updateEssenceText(); updateHealthBar(); // Start background music LK.playMusic('forestAmbience', { loop: true }); } // Game event handlers game.down = function (x, y, obj) { if (currentMode === 'guardian' && guardian) { guardian.moveTo(x, y); } }; // Game update loop game.update = function () { // Update all game objects for (var i = 0; i < towers.length; i++) { towers[i].update(); } // Update enemies (backwards to safely remove) for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].update(); if (!enemies[i].alive) { enemies[i].destroy(); enemies.splice(i, 1); enemiesRemaining--; } } // Update essence items (backwards to safely remove) for (var i = essenceItems.length - 1; i >= 0; i--) { essenceItems[i].update(); if (essenceItems[i].collected) { essenceItems[i].destroy(); essenceItems.splice(i, 1); } } // Update guardian if it exists if (guardian) { guardian.update(); } // Check if wave is complete checkWaveComplete(); }; // Display title screen instead of directly initializing game var titleScreen = new TitleScreen(); titleScreen.x = 2048 / 2; titleScreen.y = 2732 / 2; game.addChild(titleScreen); // Play background music on title screen LK.playMusic('forestAmbience', { loop: true });
===================================================================
--- original.js
+++ change.js
@@ -1754,9 +1754,9 @@
var guardianBtn = new Container();
var buildBtn = new Container();
function setupModeButtons() {
// Guardian mode button
- var guardianBtnBg = LK.getAsset('guardian', {
+ var guardianBtnBg = LK.getAsset('moveButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 80
top-down angle of a tree. In-Game asset. 2d. High contrast. No shadows
thorn flower. In-Game asset. 2d. High contrast. No shadows
purple mushroom. In-Game asset. 2d. High contrast. No shadows
guardian of the forest. In-Game asset. 2d. High contrast. No shadows
mini cave invader that is covered in crystals and is made of stone. In-Game asset. 2d. High contrast. No shadows
GIANT cave boss invader that is covered in crystal diamonds and is made of stone.. In-Game asset. 2d. High contrast. No shadows
mini farm tile. In-Game asset. 2d. High contrast. No shadows
flaming flower. In-Game asset. 2d. High contrast. No shadows
cave enterance. In-Game asset. 2d. High contrast. No shadows
car parked at an angle. In-Game asset. 2d. High contrast. No shadows
top-down angle of a tire. In-Game asset. 2d. High contrast. No shadows
finish line. In-Game asset. 2d. High contrast. No shadows
spilt acid barrel fallen over. In-Game asset. 2d. High contrast. No shadows
mutant tree. In-Game asset. 2d. High contrast. No shadows
soul. In-Game asset. 2d. High contrast. No shadows
planty spike ball with no stem. In-Game asset. 2d. High contrast. No shadows
Abandoned building that’s boarded up. In-Game asset. 2d. High contrast. No shadows
Rectangle button. In-Game asset. 2d. High contrast. No shadows
https://api.upit.com/img/IwopnnYt58_k_iLtUBxBq3JSiO4=/fit-in/256x256/filters:format(png):quality(85)/https://cdn.frvr.ai/680fe4cf833660e79135a83b.png%3F3 But empty. In-Game asset. 2d. High contrast. No shadows
Empty healthbar with no heart. In-Game asset. 2d. High contrast. No shadows
Hammer icon. In-Game asset. 2d. High contrast. No shadows
Garbage can icon. In-Game asset. 2d. High contrast. No shadows
Running feet icon. In-Game asset. 2d. High contrast. No shadows