/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function (type, pathIndex) { var self = Container.call(this); self.type = type; self.pathIndex = pathIndex || 0; self.speed = 2; self.maxHealth = 100; self.health = self.maxHealth; self.resources = 10; self.isDead = false; // Set enemy properties based on type if (type === 'goblin') { self.speed = 3; self.maxHealth = 50; self.health = 50; self.resources = 5; self.enemyGraphics = self.attachAsset('goblin', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'orc') { self.speed = 2; self.maxHealth = 100; self.health = 100; self.resources = 10; self.enemyGraphics = self.attachAsset('orc', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'troll') { self.speed = 1; self.maxHealth = 200; self.health = 200; self.resources = 20; self.enemyGraphics = self.attachAsset('troll', { anchorX: 0.5, anchorY: 0.5 }); } // Health bar self.healthBar = self.addChild(LK.getAsset('pathTile', { width: 40, height: 6, anchorX: 0.5, anchorY: 0.5, tint: 0x00FF00 })); self.healthBar.y = -40; self.takeDamage = function (damage) { self.health -= damage; var healthPercent = self.health / self.maxHealth; self.healthBar.width = 40 * healthPercent; if (healthPercent > 0.6) { self.healthBar.tint = 0x00FF00; } else if (healthPercent > 0.3) { self.healthBar.tint = 0xFFFF00; } else { self.healthBar.tint = 0xFF0000; } if (self.health <= 0) { self.isDead = true; LK.getSound('enemyDeath').play(); return true; } LK.getSound('enemyHit').play(); return false; }; self.update = function () { if (self.isDead) { return; } // Move along path if (self.pathIndex < gamePath.length - 1) { var currentTarget = gamePath[self.pathIndex + 1]; var dx = currentTarget.x - self.x; var dy = currentTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { self.pathIndex++; if (self.pathIndex >= gamePath.length - 1) { // Reached base self.reachedBase = true; } } else { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } }; return self; }); var Projectile = Container.expand(function (type, startX, startY, targetX, targetY, damage) { var self = Container.call(this); self.type = type; self.damage = damage; self.speed = 8; self.targetX = targetX; self.targetY = targetY; self.hasHit = false; self.x = startX; self.y = startY; if (type === 'arrow') { self.projectileGraphics = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'fireball') { self.projectileGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'sword') { self.projectileGraphics = self.attachAsset('sword', { anchorX: 0.5, anchorY: 0.5 }); } // Calculate direction var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); self.dirX = dx / distance; self.dirY = dy / distance; self.update = function () { if (self.hasHit) { return; } self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; // Check if reached target area var distanceToTarget = Math.sqrt(Math.pow(self.x - self.targetX, 2) + Math.pow(self.y - self.targetY, 2)); if (distanceToTarget < 20) { self.hasHit = true; } // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.hasHit = true; } }; return self; }); var Tower = Container.expand(function (type, slotX, slotY) { var self = Container.call(this); self.type = type; self.level = 1; self.range = 150; self.damage = 25; self.attackSpeed = 60; // frames between attacks self.lastAttack = 0; self.cost = 50; self.x = slotX; self.y = slotY; if (type === 'archer') { self.towerGraphics = self.attachAsset('archerTower', { anchorX: 0.5, anchorY: 0.5 }); self.projectileType = 'arrow'; self.range = 180; self.damage = 20; self.attackSpeed = 40; self.cost = 30; } else if (type === 'mage') { self.towerGraphics = self.attachAsset('mageTower', { anchorX: 0.5, anchorY: 0.5 }); self.projectileType = 'fireball'; self.range = 120; self.damage = 40; self.attackSpeed = 80; self.cost = 60; } else if (type === 'warrior') { self.towerGraphics = self.attachAsset('warriorTower', { anchorX: 0.5, anchorY: 0.5 }); self.projectileType = 'sword'; self.range = 100; self.damage = 60; self.attackSpeed = 100; self.cost = 80; self.armyCooldown = 60 * 60; // 60 seconds at 60 FPS self.lastArmyRelease = 0; } // Range indicator (invisible by default) self.rangeIndicator = self.addChild(LK.getAsset('pathTile', { width: self.range * 2, height: self.range * 2, anchorX: 0.5, anchorY: 0.5, alpha: 0, tint: 0xFFFFFF })); self.findTarget = function () { var closestEnemy = null; var closestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (enemy.isDead) { continue; } var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance <= self.range && distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } return closestEnemy; }; self.releaseArmy = function () { // Clear all enemies on the path for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (!enemy.isDead) { // Add visual effect before destroying tween(enemy, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { if (enemy && !enemy.isDead) { gameResources += enemy.resources; gameResources += 10; // Bonus 10 coins for warrior tower kills enemy.isDead = true; enemy.destroy(); enemies.splice(enemies.indexOf(enemy), 1); } } }); } } // Visual effect on tower tween(self.towerGraphics, { tint: 0xFFD700 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self.towerGraphics, { tint: 0xFFFFFF }, { duration: 800, easing: tween.easeIn }); } }); LK.getSound('shoot').play(); }; self.attack = function (target) { if (self.type === 'warrior') { // Check if army cooldown is ready if (LK.ticks - self.lastArmyRelease >= self.armyCooldown) { self.releaseArmy(); self.lastArmyRelease = LK.ticks; } return; } if (LK.ticks - self.lastAttack < self.attackSpeed) { return; } var projectile = new Projectile(self.projectileType, self.x, self.y, target.x, target.y, self.damage); projectiles.push(projectile); game.addChild(projectile); self.lastAttack = LK.ticks; LK.getSound('shoot').play(); }; self.update = function () { var target = self.findTarget(); if (target) { self.attack(target); } // Update warrior tower cooldown indicator if (self.type === 'warrior') { var cooldownRemaining = self.armyCooldown - (LK.ticks - self.lastArmyRelease); if (cooldownRemaining > 0) { var cooldownPercent = cooldownRemaining / self.armyCooldown; self.towerGraphics.tint = 0x888888 + Math.floor((1 - cooldownPercent) * 0x777777); } else { self.towerGraphics.tint = 0xFFFFFF; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F2F }); /**** * Game Code ****/ // Game state variables // Tower Assets // Enemy Assets // Projectile Assets // UI Assets // Sound Assets var gameResources = 100; var baseHealth = 100; var currentWave = 1; var enemiesInWave = 5; var enemiesSpawned = 0; var waveInProgress = false; var gameOver = false; var selectedTowerType = 'archer'; // Game arrays var enemies = []; var towers = []; var projectiles = []; var towerSlots = []; // Different paths for different waves var allPaths = [ // Path 1 - Straight horizontal then vertical [{ x: 100, y: 100 }, { x: 300, y: 100 }, { x: 300, y: 300 }, { x: 600, y: 300 }, { x: 600, y: 500 }, { x: 900, y: 500 }, { x: 900, y: 700 }, { x: 1200, y: 700 }, { x: 1200, y: 900 }, { x: 1500, y: 900 }, { x: 1500, y: 1100 }, { x: 1800, y: 1100 }], // Path 2 - Zigzag pattern [{ x: 100, y: 200 }, { x: 500, y: 200 }, { x: 500, y: 400 }, { x: 200, y: 400 }, { x: 200, y: 600 }, { x: 800, y: 600 }, { x: 800, y: 800 }, { x: 400, y: 800 }, { x: 400, y: 1000 }, { x: 1200, y: 1000 }, { x: 1200, y: 1200 }, { x: 1800, y: 1200 }], // Path 3 - Curved path [{ x: 100, y: 300 }, { x: 400, y: 300 }, { x: 400, y: 150 }, { x: 700, y: 150 }, { x: 700, y: 450 }, { x: 1000, y: 450 }, { x: 1000, y: 200 }, { x: 1300, y: 200 }, { x: 1300, y: 700 }, { x: 1600, y: 700 }, { x: 1600, y: 1000 }, { x: 1800, y: 1000 }], // Path 4 - Long winding path [{ x: 100, y: 400 }, { x: 200, y: 400 }, { x: 200, y: 200 }, { x: 600, y: 200 }, { x: 600, y: 600 }, { x: 400, y: 600 }, { x: 400, y: 800 }, { x: 1000, y: 800 }, { x: 1000, y: 400 }, { x: 1400, y: 400 }, { x: 1400, y: 1200 }, { x: 1800, y: 1200 }]]; // Current game path - changes each wave var gamePath = allPaths[0]; // Path tiles array to track them var pathTiles = []; // Create path tiles function createPathTiles() { for (var i = 0; i < gamePath.length; i++) { var pathTile = game.addChild(LK.getAsset('pathTile', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 })); pathTile.x = gamePath[i].x; pathTile.y = gamePath[i].y; pathTiles.push(pathTile); } } // Function to redraw path for new waves function redrawPath() { // Remove old path tiles for (var i = 0; i < pathTiles.length; i++) { pathTiles[i].destroy(); } pathTiles = []; // Create new path tiles createPathTiles(); // Update base position to end of new path base.x = gamePath[gamePath.length - 1].x; base.y = gamePath[gamePath.length - 1].y; } // Initialize path tiles createPathTiles(); // Create base at end of path var base = game.addChild(LK.getAsset('base', { anchorX: 0.5, anchorY: 0.5 })); base.x = gamePath[gamePath.length - 1].x; base.y = gamePath[gamePath.length - 1].y; // Create tower slots around the path var baseSlotPositions = [{ x: 200, y: 200 }, { x: 400, y: 200 }, { x: 500, y: 400 }, { x: 700, y: 400 }, { x: 800, y: 600 }, { x: 1000, y: 600 }, { x: 1100, y: 800 }, { x: 1300, y: 800 }, { x: 1400, y: 1000 }, { x: 1600, y: 1000 }, { x: 1700, y: 1200 }]; // Additional slots for wave 2 and higher var extraSlotPositions = [{ x: 150, y: 350 }, { x: 350, y: 550 }, { x: 650, y: 350 }, { x: 850, y: 450 }, { x: 1050, y: 350 }, { x: 1250, y: 550 }, { x: 1450, y: 650 }, { x: 1550, y: 850 }]; function createTowerSlots() { // Clear existing slots for (var i = 0; i < towerSlots.length; i++) { towerSlots[i].destroy(); } towerSlots = []; // Always create base slots var slotsToCreate = baseSlotPositions.slice(); // Add extra slots for wave 2 and higher if (currentWave >= 2) { slotsToCreate = slotsToCreate.concat(extraSlotPositions); } for (var i = 0; i < slotsToCreate.length; i++) { var slot = game.addChild(LK.getAsset('towerSlot', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 })); slot.x = slotsToCreate[i].x; slot.y = slotsToCreate[i].y; slot.isEmpty = true; slot.slotIndex = i; towerSlots.push(slot); } } // Initialize tower slots createTowerSlots(); // Create decorative trees and bushes var decorativeElements = []; var treePositions = [{ x: 50, y: 50 }, { x: 150, y: 80 }, { x: 250, y: 120 }, { x: 1850, y: 100 }, { x: 1750, y: 150 }, { x: 1650, y: 80 }, { x: 80, y: 800 }, { x: 180, y: 950 }, { x: 120, y: 1100 }, { x: 1880, y: 1400 }, { x: 1780, y: 1500 }, { x: 1820, y: 1600 }, { x: 950, y: 50 }, { x: 1050, y: 80 }, { x: 850, y: 120 }, { x: 50, y: 1800 }, { x: 150, y: 1900 }, { x: 250, y: 2000 }]; var bushPositions = [{ x: 350, y: 80 }, { x: 450, y: 120 }, { x: 550, y: 90 }, { x: 1550, y: 200 }, { x: 1650, y: 180 }, { x: 1750, y: 220 }, { x: 80, y: 1200 }, { x: 180, y: 1300 }, { x: 120, y: 1400 }, { x: 1880, y: 1800 }, { x: 1780, y: 1900 }, { x: 1820, y: 2000 }, { x: 750, y: 100 }, { x: 850, y: 180 }, { x: 950, y: 140 }, { x: 1100, y: 1800 }, { x: 1200, y: 1900 }, { x: 1300, y: 2000 }, { x: 300, y: 1600 }, { x: 400, y: 1700 }, { x: 500, y: 1800 }]; // Create trees for (var i = 0; i < treePositions.length; i++) { var tree = game.addChild(LK.getAsset('tree', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 })); tree.x = treePositions[i].x; tree.y = treePositions[i].y; decorativeElements.push(tree); } // Create bushes for (var i = 0; i < bushPositions.length; i++) { var bush = game.addChild(LK.getAsset('bush', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 })); bush.x = bushPositions[i].x; bush.y = bushPositions[i].y; decorativeElements.push(bush); } // UI Elements var resourcesText = new Text2('Resources: ' + gameResources, { size: 60, fill: 0xFFD700 }); resourcesText.anchor.set(0, 0); LK.gui.top.addChild(resourcesText); resourcesText.x = 200; resourcesText.y = 20; var healthText = new Text2('Base Health: ' + baseHealth, { size: 60, fill: 0xFF0000 }); healthText.anchor.set(0, 0); LK.gui.top.addChild(healthText); healthText.x = 200; healthText.y = 90; var waveText = new Text2('Wave: ' + currentWave, { size: 60, fill: 0xFFFFFF }); waveText.anchor.set(0, 0); LK.gui.top.addChild(waveText); waveText.x = 200; waveText.y = 160; // Tower selection buttons var archerButton = LK.gui.bottomLeft.addChild(LK.getAsset('archerTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); archerButton.x = 80; archerButton.y = -80; var mageButton = LK.gui.bottomLeft.addChild(LK.getAsset('mageTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); mageButton.x = 200; mageButton.y = -80; var warriorButton = LK.gui.bottomLeft.addChild(LK.getAsset('warriorTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); warriorButton.x = 320; warriorButton.y = -80; // Tower cost labels var archerCost = new Text2('30', { size: 30, fill: 0xFFFFFF }); archerCost.anchor.set(0.5, 0); LK.gui.bottomLeft.addChild(archerCost); archerCost.x = 80; archerCost.y = -40; var mageCost = new Text2('60', { size: 30, fill: 0xFFFFFF }); mageCost.anchor.set(0.5, 0); LK.gui.bottomLeft.addChild(mageCost); mageCost.x = 200; mageCost.y = -40; var warriorCost = new Text2('80', { size: 30, fill: 0xFFFFFF }); warriorCost.anchor.set(0.5, 0); LK.gui.bottomLeft.addChild(warriorCost); warriorCost.x = 320; warriorCost.y = -40; // Start wave button var startWaveButton = new Text2('START WAVE', { size: 50, fill: 0x00FF00 }); startWaveButton.anchor.set(0.5, 0); LK.gui.bottomRight.addChild(startWaveButton); startWaveButton.x = -150; startWaveButton.y = -80; // Game functions function spawnEnemy() { var enemyTypes = ['goblin', 'orc', 'troll']; var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; // Increase difficulty with wave number if (currentWave > 3) { randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; } else if (currentWave > 1) { randomType = enemyTypes[Math.floor(Math.random() * 2)]; // No trolls in early waves } else { randomType = 'goblin'; // Only goblins in first wave } var enemy = new Enemy(randomType, 0); enemy.x = gamePath[0].x; enemy.y = gamePath[0].y; enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } function updateUI() { resourcesText.setText('Resources: ' + gameResources); healthText.setText('Base Health: ' + baseHealth); waveText.setText('Wave: ' + currentWave); // Update tower selection UI updateTowerSelectionUI(); } function getTowerCost(type) { if (type === 'archer') { return 30; } if (type === 'mage') { return 60; } if (type === 'warrior') { return 80; } return 50; } function placeTower(slotIndex, towerType) { var slot = towerSlots[slotIndex]; if (!slot.isEmpty) { return false; } var cost = getTowerCost(towerType); if (gameResources < cost) { return false; } var tower = new Tower(towerType, slot.x, slot.y); towers.push(tower); game.addChild(tower); gameResources -= cost; slot.isEmpty = false; slot.alpha = 0.3; LK.getSound('towerPlace').play(); updateUI(); return true; } function startWave() { if (waveInProgress) { return; } waveInProgress = true; enemiesSpawned = 0; enemiesInWave = 3 + currentWave * 2; // Increase enemies per wave startWaveButton.setText('WAVE ' + currentWave); startWaveButton.tint = 0x888888; // Change path for each wave var pathIndex = (currentWave - 1) % allPaths.length; gamePath = allPaths[pathIndex]; redrawPath(); // Recreate tower slots for new wave createTowerSlots(); } function endWave() { waveInProgress = false; currentWave++; gameResources += 20 + currentWave * 5; // Bonus resources between waves startWaveButton.setText('START WAVE'); startWaveButton.tint = 0x00FF00; updateUI(); } // Event handlers game.down = function (x, y, obj) { if (gameOver) { return; } // Check tower slot clicks for (var i = 0; i < towerSlots.length; i++) { var slot = towerSlots[i]; var distance = Math.sqrt(Math.pow(slot.x - x, 2) + Math.pow(slot.y - y, 2)); if (distance < 50 && slot.isEmpty) { placeTower(i, selectedTowerType); return; } } }; // Button click handlers archerButton.down = function () { if (gameResources >= 30) { selectedTowerType = 'archer'; updateTowerSelectionUI(); } }; mageButton.down = function () { if (gameResources >= 60) { selectedTowerType = 'mage'; updateTowerSelectionUI(); } }; warriorButton.down = function () { if (gameResources >= 80) { selectedTowerType = 'warrior'; updateTowerSelectionUI(); } }; // Function to update tower selection UI function updateTowerSelectionUI() { // Reset all button colors archerButton.tint = gameResources >= 30 ? 0xFFFFFF : 0x888888; mageButton.tint = gameResources >= 60 ? 0xFFFFFF : 0x888888; warriorButton.tint = gameResources >= 80 ? 0xFFFFFF : 0x888888; // Highlight selected tower if (selectedTowerType === 'archer') { archerButton.tint = 0x00FF00; } else if (selectedTowerType === 'mage') { mageButton.tint = 0x00FF00; } else if (selectedTowerType === 'warrior') { warriorButton.tint = 0x00FF00; } } startWaveButton.down = function () { if (!waveInProgress) { startWave(); } }; // Main game loop game.update = function () { if (gameOver) { return; } // Spawn enemies during wave if (waveInProgress && enemiesSpawned < enemiesInWave) { if (LK.ticks % 60 === 0) { // Spawn every second spawnEnemy(); } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.isDead) { gameResources += enemy.resources; enemy.destroy(); enemies.splice(i, 1); continue; } if (enemy.reachedBase) { baseHealth -= 10; enemy.destroy(); enemies.splice(i, 1); if (baseHealth <= 0) { gameOver = true; LK.showGameOver(); return; } continue; } } // Update projectiles for (var i = projectiles.length - 1; i >= 0; i--) { var projectile = projectiles[i]; if (projectile.hasHit) { // Check for enemy hits for (var j = 0; j < enemies.length; j++) { var enemy = enemies[j]; if (!enemy.isDead && enemy.intersects(projectile)) { enemy.takeDamage(projectile.damage); break; } } projectile.destroy(); projectiles.splice(i, 1); } } // Check if wave is complete if (waveInProgress && enemiesSpawned >= enemiesInWave && enemies.length === 0) { endWave(); } // Win condition if (currentWave > 10) { LK.showYouWin(); return; } updateUI(); }; // Selected tower preview var selectedTowerPreview = null; // Initialize selected tower archerButton.tint = 0x00FF00; updateUI(); // Show preview of selected tower when hovering over valid slots game.move = function (x, y, obj) { if (gameOver) { return; } // Remove existing preview if (selectedTowerPreview) { selectedTowerPreview.destroy(); selectedTowerPreview = null; } // Check if hovering over a valid tower slot for (var i = 0; i < towerSlots.length; i++) { var slot = towerSlots[i]; var distance = Math.sqrt(Math.pow(slot.x - x, 2) + Math.pow(slot.y - y, 2)); if (slot.isEmpty && distance < 50) { var cost = getTowerCost(selectedTowerType); if (gameResources >= cost) { // Create preview of selected tower if (selectedTowerType === 'archer') { selectedTowerPreview = game.addChild(LK.getAsset('archerTower', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 })); } else if (selectedTowerType === 'mage') { selectedTowerPreview = game.addChild(LK.getAsset('mageTower', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 })); } else if (selectedTowerType === 'warrior') { selectedTowerPreview = game.addChild(LK.getAsset('warriorTower', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 })); } if (selectedTowerPreview) { selectedTowerPreview.x = slot.x; selectedTowerPreview.y = slot.y; selectedTowerPreview.tint = 0x00FF00; // Green tint for valid placement } // Highlight the slot slot.tint = 0x00FF00; slot.alpha = 1.0; } break; } else { // Reset slot appearance slot.tint = 0xFFFFFF; slot.alpha = 0.7; } } };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,1087 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var Enemy = Container.expand(function (type, pathIndex) {
+ var self = Container.call(this);
+ self.type = type;
+ self.pathIndex = pathIndex || 0;
+ self.speed = 2;
+ self.maxHealth = 100;
+ self.health = self.maxHealth;
+ self.resources = 10;
+ self.isDead = false;
+ // Set enemy properties based on type
+ if (type === 'goblin') {
+ self.speed = 3;
+ self.maxHealth = 50;
+ self.health = 50;
+ self.resources = 5;
+ self.enemyGraphics = self.attachAsset('goblin', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else if (type === 'orc') {
+ self.speed = 2;
+ self.maxHealth = 100;
+ self.health = 100;
+ self.resources = 10;
+ self.enemyGraphics = self.attachAsset('orc', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else if (type === 'troll') {
+ self.speed = 1;
+ self.maxHealth = 200;
+ self.health = 200;
+ self.resources = 20;
+ self.enemyGraphics = self.attachAsset('troll', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ // Health bar
+ self.healthBar = self.addChild(LK.getAsset('pathTile', {
+ width: 40,
+ height: 6,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x00FF00
+ }));
+ self.healthBar.y = -40;
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ var healthPercent = self.health / self.maxHealth;
+ self.healthBar.width = 40 * healthPercent;
+ if (healthPercent > 0.6) {
+ self.healthBar.tint = 0x00FF00;
+ } else if (healthPercent > 0.3) {
+ self.healthBar.tint = 0xFFFF00;
+ } else {
+ self.healthBar.tint = 0xFF0000;
+ }
+ if (self.health <= 0) {
+ self.isDead = true;
+ LK.getSound('enemyDeath').play();
+ return true;
+ }
+ LK.getSound('enemyHit').play();
+ return false;
+ };
+ self.update = function () {
+ if (self.isDead) {
+ return;
+ }
+ // Move along path
+ if (self.pathIndex < gamePath.length - 1) {
+ var currentTarget = gamePath[self.pathIndex + 1];
+ var dx = currentTarget.x - self.x;
+ var dy = currentTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 10) {
+ self.pathIndex++;
+ if (self.pathIndex >= gamePath.length - 1) {
+ // Reached base
+ self.reachedBase = true;
+ }
+ } else {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ }
+ }
+ };
+ return self;
+});
+var Projectile = Container.expand(function (type, startX, startY, targetX, targetY, damage) {
+ var self = Container.call(this);
+ self.type = type;
+ self.damage = damage;
+ self.speed = 8;
+ self.targetX = targetX;
+ self.targetY = targetY;
+ self.hasHit = false;
+ self.x = startX;
+ self.y = startY;
+ if (type === 'arrow') {
+ self.projectileGraphics = self.attachAsset('arrow', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else if (type === 'fireball') {
+ self.projectileGraphics = self.attachAsset('fireball', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else if (type === 'sword') {
+ self.projectileGraphics = self.attachAsset('sword', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ // Calculate direction
+ var dx = targetX - startX;
+ var dy = targetY - startY;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ self.dirX = dx / distance;
+ self.dirY = dy / distance;
+ self.update = function () {
+ if (self.hasHit) {
+ return;
+ }
+ self.x += self.dirX * self.speed;
+ self.y += self.dirY * self.speed;
+ // Check if reached target area
+ var distanceToTarget = Math.sqrt(Math.pow(self.x - self.targetX, 2) + Math.pow(self.y - self.targetY, 2));
+ if (distanceToTarget < 20) {
+ self.hasHit = true;
+ }
+ // Remove if off screen
+ if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
+ self.hasHit = true;
+ }
+ };
+ return self;
+});
+var Tower = Container.expand(function (type, slotX, slotY) {
+ var self = Container.call(this);
+ self.type = type;
+ self.level = 1;
+ self.range = 150;
+ self.damage = 25;
+ self.attackSpeed = 60; // frames between attacks
+ self.lastAttack = 0;
+ self.cost = 50;
+ self.x = slotX;
+ self.y = slotY;
+ if (type === 'archer') {
+ self.towerGraphics = self.attachAsset('archerTower', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.projectileType = 'arrow';
+ self.range = 180;
+ self.damage = 20;
+ self.attackSpeed = 40;
+ self.cost = 30;
+ } else if (type === 'mage') {
+ self.towerGraphics = self.attachAsset('mageTower', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.projectileType = 'fireball';
+ self.range = 120;
+ self.damage = 40;
+ self.attackSpeed = 80;
+ self.cost = 60;
+ } else if (type === 'warrior') {
+ self.towerGraphics = self.attachAsset('warriorTower', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.projectileType = 'sword';
+ self.range = 100;
+ self.damage = 60;
+ self.attackSpeed = 100;
+ self.cost = 80;
+ self.armyCooldown = 60 * 60; // 60 seconds at 60 FPS
+ self.lastArmyRelease = 0;
+ }
+ // Range indicator (invisible by default)
+ self.rangeIndicator = self.addChild(LK.getAsset('pathTile', {
+ width: self.range * 2,
+ height: self.range * 2,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0,
+ tint: 0xFFFFFF
+ }));
+ self.findTarget = function () {
+ var closestEnemy = null;
+ var closestDistance = Infinity;
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ if (enemy.isDead) {
+ continue;
+ }
+ var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
+ if (distance <= self.range && distance < closestDistance) {
+ closestDistance = distance;
+ closestEnemy = enemy;
+ }
+ }
+ return closestEnemy;
+ };
+ self.releaseArmy = function () {
+ // Clear all enemies on the path
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ var enemy = enemies[i];
+ if (!enemy.isDead) {
+ // Add visual effect before destroying
+ tween(enemy, {
+ alpha: 0,
+ scaleX: 0.1,
+ scaleY: 0.1
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ if (enemy && !enemy.isDead) {
+ gameResources += enemy.resources;
+ gameResources += 10; // Bonus 10 coins for warrior tower kills
+ enemy.isDead = true;
+ enemy.destroy();
+ enemies.splice(enemies.indexOf(enemy), 1);
+ }
+ }
+ });
+ }
+ }
+ // Visual effect on tower
+ tween(self.towerGraphics, {
+ tint: 0xFFD700
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(self.towerGraphics, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 800,
+ easing: tween.easeIn
+ });
+ }
+ });
+ LK.getSound('shoot').play();
+ };
+ self.attack = function (target) {
+ if (self.type === 'warrior') {
+ // Check if army cooldown is ready
+ if (LK.ticks - self.lastArmyRelease >= self.armyCooldown) {
+ self.releaseArmy();
+ self.lastArmyRelease = LK.ticks;
+ }
+ return;
+ }
+ if (LK.ticks - self.lastAttack < self.attackSpeed) {
+ return;
+ }
+ var projectile = new Projectile(self.projectileType, self.x, self.y, target.x, target.y, self.damage);
+ projectiles.push(projectile);
+ game.addChild(projectile);
+ self.lastAttack = LK.ticks;
+ LK.getSound('shoot').play();
+ };
+ self.update = function () {
+ var target = self.findTarget();
+ if (target) {
+ self.attack(target);
+ }
+ // Update warrior tower cooldown indicator
+ if (self.type === 'warrior') {
+ var cooldownRemaining = self.armyCooldown - (LK.ticks - self.lastArmyRelease);
+ if (cooldownRemaining > 0) {
+ var cooldownPercent = cooldownRemaining / self.armyCooldown;
+ self.towerGraphics.tint = 0x888888 + Math.floor((1 - cooldownPercent) * 0x777777);
+ } else {
+ self.towerGraphics.tint = 0xFFFFFF;
+ }
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x444444
-});
\ No newline at end of file
+ backgroundColor: 0x2F4F2F
+});
+
+/****
+* Game Code
+****/
+// Game state variables
+// Tower Assets
+// Enemy Assets
+// Projectile Assets
+// UI Assets
+// Sound Assets
+var gameResources = 100;
+var baseHealth = 100;
+var currentWave = 1;
+var enemiesInWave = 5;
+var enemiesSpawned = 0;
+var waveInProgress = false;
+var gameOver = false;
+var selectedTowerType = 'archer';
+// Game arrays
+var enemies = [];
+var towers = [];
+var projectiles = [];
+var towerSlots = [];
+// Different paths for different waves
+var allPaths = [
+// Path 1 - Straight horizontal then vertical
+[{
+ x: 100,
+ y: 100
+}, {
+ x: 300,
+ y: 100
+}, {
+ x: 300,
+ y: 300
+}, {
+ x: 600,
+ y: 300
+}, {
+ x: 600,
+ y: 500
+}, {
+ x: 900,
+ y: 500
+}, {
+ x: 900,
+ y: 700
+}, {
+ x: 1200,
+ y: 700
+}, {
+ x: 1200,
+ y: 900
+}, {
+ x: 1500,
+ y: 900
+}, {
+ x: 1500,
+ y: 1100
+}, {
+ x: 1800,
+ y: 1100
+}],
+// Path 2 - Zigzag pattern
+[{
+ x: 100,
+ y: 200
+}, {
+ x: 500,
+ y: 200
+}, {
+ x: 500,
+ y: 400
+}, {
+ x: 200,
+ y: 400
+}, {
+ x: 200,
+ y: 600
+}, {
+ x: 800,
+ y: 600
+}, {
+ x: 800,
+ y: 800
+}, {
+ x: 400,
+ y: 800
+}, {
+ x: 400,
+ y: 1000
+}, {
+ x: 1200,
+ y: 1000
+}, {
+ x: 1200,
+ y: 1200
+}, {
+ x: 1800,
+ y: 1200
+}],
+// Path 3 - Curved path
+[{
+ x: 100,
+ y: 300
+}, {
+ x: 400,
+ y: 300
+}, {
+ x: 400,
+ y: 150
+}, {
+ x: 700,
+ y: 150
+}, {
+ x: 700,
+ y: 450
+}, {
+ x: 1000,
+ y: 450
+}, {
+ x: 1000,
+ y: 200
+}, {
+ x: 1300,
+ y: 200
+}, {
+ x: 1300,
+ y: 700
+}, {
+ x: 1600,
+ y: 700
+}, {
+ x: 1600,
+ y: 1000
+}, {
+ x: 1800,
+ y: 1000
+}],
+// Path 4 - Long winding path
+[{
+ x: 100,
+ y: 400
+}, {
+ x: 200,
+ y: 400
+}, {
+ x: 200,
+ y: 200
+}, {
+ x: 600,
+ y: 200
+}, {
+ x: 600,
+ y: 600
+}, {
+ x: 400,
+ y: 600
+}, {
+ x: 400,
+ y: 800
+}, {
+ x: 1000,
+ y: 800
+}, {
+ x: 1000,
+ y: 400
+}, {
+ x: 1400,
+ y: 400
+}, {
+ x: 1400,
+ y: 1200
+}, {
+ x: 1800,
+ y: 1200
+}]];
+// Current game path - changes each wave
+var gamePath = allPaths[0];
+// Path tiles array to track them
+var pathTiles = [];
+// Create path tiles
+function createPathTiles() {
+ for (var i = 0; i < gamePath.length; i++) {
+ var pathTile = game.addChild(LK.getAsset('pathTile', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.3
+ }));
+ pathTile.x = gamePath[i].x;
+ pathTile.y = gamePath[i].y;
+ pathTiles.push(pathTile);
+ }
+}
+// Function to redraw path for new waves
+function redrawPath() {
+ // Remove old path tiles
+ for (var i = 0; i < pathTiles.length; i++) {
+ pathTiles[i].destroy();
+ }
+ pathTiles = [];
+ // Create new path tiles
+ createPathTiles();
+ // Update base position to end of new path
+ base.x = gamePath[gamePath.length - 1].x;
+ base.y = gamePath[gamePath.length - 1].y;
+}
+// Initialize path tiles
+createPathTiles();
+// Create base at end of path
+var base = game.addChild(LK.getAsset('base', {
+ anchorX: 0.5,
+ anchorY: 0.5
+}));
+base.x = gamePath[gamePath.length - 1].x;
+base.y = gamePath[gamePath.length - 1].y;
+// Create tower slots around the path
+var baseSlotPositions = [{
+ x: 200,
+ y: 200
+}, {
+ x: 400,
+ y: 200
+}, {
+ x: 500,
+ y: 400
+}, {
+ x: 700,
+ y: 400
+}, {
+ x: 800,
+ y: 600
+}, {
+ x: 1000,
+ y: 600
+}, {
+ x: 1100,
+ y: 800
+}, {
+ x: 1300,
+ y: 800
+}, {
+ x: 1400,
+ y: 1000
+}, {
+ x: 1600,
+ y: 1000
+}, {
+ x: 1700,
+ y: 1200
+}];
+// Additional slots for wave 2 and higher
+var extraSlotPositions = [{
+ x: 150,
+ y: 350
+}, {
+ x: 350,
+ y: 550
+}, {
+ x: 650,
+ y: 350
+}, {
+ x: 850,
+ y: 450
+}, {
+ x: 1050,
+ y: 350
+}, {
+ x: 1250,
+ y: 550
+}, {
+ x: 1450,
+ y: 650
+}, {
+ x: 1550,
+ y: 850
+}];
+function createTowerSlots() {
+ // Clear existing slots
+ for (var i = 0; i < towerSlots.length; i++) {
+ towerSlots[i].destroy();
+ }
+ towerSlots = [];
+ // Always create base slots
+ var slotsToCreate = baseSlotPositions.slice();
+ // Add extra slots for wave 2 and higher
+ if (currentWave >= 2) {
+ slotsToCreate = slotsToCreate.concat(extraSlotPositions);
+ }
+ for (var i = 0; i < slotsToCreate.length; i++) {
+ var slot = game.addChild(LK.getAsset('towerSlot', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ }));
+ slot.x = slotsToCreate[i].x;
+ slot.y = slotsToCreate[i].y;
+ slot.isEmpty = true;
+ slot.slotIndex = i;
+ towerSlots.push(slot);
+ }
+}
+// Initialize tower slots
+createTowerSlots();
+// Create decorative trees and bushes
+var decorativeElements = [];
+var treePositions = [{
+ x: 50,
+ y: 50
+}, {
+ x: 150,
+ y: 80
+}, {
+ x: 250,
+ y: 120
+}, {
+ x: 1850,
+ y: 100
+}, {
+ x: 1750,
+ y: 150
+}, {
+ x: 1650,
+ y: 80
+}, {
+ x: 80,
+ y: 800
+}, {
+ x: 180,
+ y: 950
+}, {
+ x: 120,
+ y: 1100
+}, {
+ x: 1880,
+ y: 1400
+}, {
+ x: 1780,
+ y: 1500
+}, {
+ x: 1820,
+ y: 1600
+}, {
+ x: 950,
+ y: 50
+}, {
+ x: 1050,
+ y: 80
+}, {
+ x: 850,
+ y: 120
+}, {
+ x: 50,
+ y: 1800
+}, {
+ x: 150,
+ y: 1900
+}, {
+ x: 250,
+ y: 2000
+}];
+var bushPositions = [{
+ x: 350,
+ y: 80
+}, {
+ x: 450,
+ y: 120
+}, {
+ x: 550,
+ y: 90
+}, {
+ x: 1550,
+ y: 200
+}, {
+ x: 1650,
+ y: 180
+}, {
+ x: 1750,
+ y: 220
+}, {
+ x: 80,
+ y: 1200
+}, {
+ x: 180,
+ y: 1300
+}, {
+ x: 120,
+ y: 1400
+}, {
+ x: 1880,
+ y: 1800
+}, {
+ x: 1780,
+ y: 1900
+}, {
+ x: 1820,
+ y: 2000
+}, {
+ x: 750,
+ y: 100
+}, {
+ x: 850,
+ y: 180
+}, {
+ x: 950,
+ y: 140
+}, {
+ x: 1100,
+ y: 1800
+}, {
+ x: 1200,
+ y: 1900
+}, {
+ x: 1300,
+ y: 2000
+}, {
+ x: 300,
+ y: 1600
+}, {
+ x: 400,
+ y: 1700
+}, {
+ x: 500,
+ y: 1800
+}];
+// Create trees
+for (var i = 0; i < treePositions.length; i++) {
+ var tree = game.addChild(LK.getAsset('tree', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ }));
+ tree.x = treePositions[i].x;
+ tree.y = treePositions[i].y;
+ decorativeElements.push(tree);
+}
+// Create bushes
+for (var i = 0; i < bushPositions.length; i++) {
+ var bush = game.addChild(LK.getAsset('bush', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ }));
+ bush.x = bushPositions[i].x;
+ bush.y = bushPositions[i].y;
+ decorativeElements.push(bush);
+}
+// UI Elements
+var resourcesText = new Text2('Resources: ' + gameResources, {
+ size: 60,
+ fill: 0xFFD700
+});
+resourcesText.anchor.set(0, 0);
+LK.gui.top.addChild(resourcesText);
+resourcesText.x = 200;
+resourcesText.y = 20;
+var healthText = new Text2('Base Health: ' + baseHealth, {
+ size: 60,
+ fill: 0xFF0000
+});
+healthText.anchor.set(0, 0);
+LK.gui.top.addChild(healthText);
+healthText.x = 200;
+healthText.y = 90;
+var waveText = new Text2('Wave: ' + currentWave, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+waveText.anchor.set(0, 0);
+LK.gui.top.addChild(waveText);
+waveText.x = 200;
+waveText.y = 160;
+// Tower selection buttons
+var archerButton = LK.gui.bottomLeft.addChild(LK.getAsset('archerTower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.8,
+ scaleY: 0.8
+}));
+archerButton.x = 80;
+archerButton.y = -80;
+var mageButton = LK.gui.bottomLeft.addChild(LK.getAsset('mageTower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.8,
+ scaleY: 0.8
+}));
+mageButton.x = 200;
+mageButton.y = -80;
+var warriorButton = LK.gui.bottomLeft.addChild(LK.getAsset('warriorTower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.8,
+ scaleY: 0.8
+}));
+warriorButton.x = 320;
+warriorButton.y = -80;
+// Tower cost labels
+var archerCost = new Text2('30', {
+ size: 30,
+ fill: 0xFFFFFF
+});
+archerCost.anchor.set(0.5, 0);
+LK.gui.bottomLeft.addChild(archerCost);
+archerCost.x = 80;
+archerCost.y = -40;
+var mageCost = new Text2('60', {
+ size: 30,
+ fill: 0xFFFFFF
+});
+mageCost.anchor.set(0.5, 0);
+LK.gui.bottomLeft.addChild(mageCost);
+mageCost.x = 200;
+mageCost.y = -40;
+var warriorCost = new Text2('80', {
+ size: 30,
+ fill: 0xFFFFFF
+});
+warriorCost.anchor.set(0.5, 0);
+LK.gui.bottomLeft.addChild(warriorCost);
+warriorCost.x = 320;
+warriorCost.y = -40;
+// Start wave button
+var startWaveButton = new Text2('START WAVE', {
+ size: 50,
+ fill: 0x00FF00
+});
+startWaveButton.anchor.set(0.5, 0);
+LK.gui.bottomRight.addChild(startWaveButton);
+startWaveButton.x = -150;
+startWaveButton.y = -80;
+// Game functions
+function spawnEnemy() {
+ var enemyTypes = ['goblin', 'orc', 'troll'];
+ var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
+ // Increase difficulty with wave number
+ if (currentWave > 3) {
+ randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
+ } else if (currentWave > 1) {
+ randomType = enemyTypes[Math.floor(Math.random() * 2)]; // No trolls in early waves
+ } else {
+ randomType = 'goblin'; // Only goblins in first wave
+ }
+ var enemy = new Enemy(randomType, 0);
+ enemy.x = gamePath[0].x;
+ enemy.y = gamePath[0].y;
+ enemies.push(enemy);
+ game.addChild(enemy);
+ enemiesSpawned++;
+}
+function updateUI() {
+ resourcesText.setText('Resources: ' + gameResources);
+ healthText.setText('Base Health: ' + baseHealth);
+ waveText.setText('Wave: ' + currentWave);
+ // Update tower selection UI
+ updateTowerSelectionUI();
+}
+function getTowerCost(type) {
+ if (type === 'archer') {
+ return 30;
+ }
+ if (type === 'mage') {
+ return 60;
+ }
+ if (type === 'warrior') {
+ return 80;
+ }
+ return 50;
+}
+function placeTower(slotIndex, towerType) {
+ var slot = towerSlots[slotIndex];
+ if (!slot.isEmpty) {
+ return false;
+ }
+ var cost = getTowerCost(towerType);
+ if (gameResources < cost) {
+ return false;
+ }
+ var tower = new Tower(towerType, slot.x, slot.y);
+ towers.push(tower);
+ game.addChild(tower);
+ gameResources -= cost;
+ slot.isEmpty = false;
+ slot.alpha = 0.3;
+ LK.getSound('towerPlace').play();
+ updateUI();
+ return true;
+}
+function startWave() {
+ if (waveInProgress) {
+ return;
+ }
+ waveInProgress = true;
+ enemiesSpawned = 0;
+ enemiesInWave = 3 + currentWave * 2; // Increase enemies per wave
+ startWaveButton.setText('WAVE ' + currentWave);
+ startWaveButton.tint = 0x888888;
+ // Change path for each wave
+ var pathIndex = (currentWave - 1) % allPaths.length;
+ gamePath = allPaths[pathIndex];
+ redrawPath();
+ // Recreate tower slots for new wave
+ createTowerSlots();
+}
+function endWave() {
+ waveInProgress = false;
+ currentWave++;
+ gameResources += 20 + currentWave * 5; // Bonus resources between waves
+ startWaveButton.setText('START WAVE');
+ startWaveButton.tint = 0x00FF00;
+ updateUI();
+}
+// Event handlers
+game.down = function (x, y, obj) {
+ if (gameOver) {
+ return;
+ }
+ // Check tower slot clicks
+ for (var i = 0; i < towerSlots.length; i++) {
+ var slot = towerSlots[i];
+ var distance = Math.sqrt(Math.pow(slot.x - x, 2) + Math.pow(slot.y - y, 2));
+ if (distance < 50 && slot.isEmpty) {
+ placeTower(i, selectedTowerType);
+ return;
+ }
+ }
+};
+// Button click handlers
+archerButton.down = function () {
+ if (gameResources >= 30) {
+ selectedTowerType = 'archer';
+ updateTowerSelectionUI();
+ }
+};
+mageButton.down = function () {
+ if (gameResources >= 60) {
+ selectedTowerType = 'mage';
+ updateTowerSelectionUI();
+ }
+};
+warriorButton.down = function () {
+ if (gameResources >= 80) {
+ selectedTowerType = 'warrior';
+ updateTowerSelectionUI();
+ }
+};
+// Function to update tower selection UI
+function updateTowerSelectionUI() {
+ // Reset all button colors
+ archerButton.tint = gameResources >= 30 ? 0xFFFFFF : 0x888888;
+ mageButton.tint = gameResources >= 60 ? 0xFFFFFF : 0x888888;
+ warriorButton.tint = gameResources >= 80 ? 0xFFFFFF : 0x888888;
+ // Highlight selected tower
+ if (selectedTowerType === 'archer') {
+ archerButton.tint = 0x00FF00;
+ } else if (selectedTowerType === 'mage') {
+ mageButton.tint = 0x00FF00;
+ } else if (selectedTowerType === 'warrior') {
+ warriorButton.tint = 0x00FF00;
+ }
+}
+startWaveButton.down = function () {
+ if (!waveInProgress) {
+ startWave();
+ }
+};
+// Main game loop
+game.update = function () {
+ if (gameOver) {
+ return;
+ }
+ // Spawn enemies during wave
+ if (waveInProgress && enemiesSpawned < enemiesInWave) {
+ if (LK.ticks % 60 === 0) {
+ // Spawn every second
+ spawnEnemy();
+ }
+ }
+ // Update enemies
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ var enemy = enemies[i];
+ if (enemy.isDead) {
+ gameResources += enemy.resources;
+ enemy.destroy();
+ enemies.splice(i, 1);
+ continue;
+ }
+ if (enemy.reachedBase) {
+ baseHealth -= 10;
+ enemy.destroy();
+ enemies.splice(i, 1);
+ if (baseHealth <= 0) {
+ gameOver = true;
+ LK.showGameOver();
+ return;
+ }
+ continue;
+ }
+ }
+ // Update projectiles
+ for (var i = projectiles.length - 1; i >= 0; i--) {
+ var projectile = projectiles[i];
+ if (projectile.hasHit) {
+ // Check for enemy hits
+ for (var j = 0; j < enemies.length; j++) {
+ var enemy = enemies[j];
+ if (!enemy.isDead && enemy.intersects(projectile)) {
+ enemy.takeDamage(projectile.damage);
+ break;
+ }
+ }
+ projectile.destroy();
+ projectiles.splice(i, 1);
+ }
+ }
+ // Check if wave is complete
+ if (waveInProgress && enemiesSpawned >= enemiesInWave && enemies.length === 0) {
+ endWave();
+ }
+ // Win condition
+ if (currentWave > 10) {
+ LK.showYouWin();
+ return;
+ }
+ updateUI();
+};
+// Selected tower preview
+var selectedTowerPreview = null;
+// Initialize selected tower
+archerButton.tint = 0x00FF00;
+updateUI();
+// Show preview of selected tower when hovering over valid slots
+game.move = function (x, y, obj) {
+ if (gameOver) {
+ return;
+ }
+ // Remove existing preview
+ if (selectedTowerPreview) {
+ selectedTowerPreview.destroy();
+ selectedTowerPreview = null;
+ }
+ // Check if hovering over a valid tower slot
+ for (var i = 0; i < towerSlots.length; i++) {
+ var slot = towerSlots[i];
+ var distance = Math.sqrt(Math.pow(slot.x - x, 2) + Math.pow(slot.y - y, 2));
+ if (slot.isEmpty && distance < 50) {
+ var cost = getTowerCost(selectedTowerType);
+ if (gameResources >= cost) {
+ // Create preview of selected tower
+ if (selectedTowerType === 'archer') {
+ selectedTowerPreview = game.addChild(LK.getAsset('archerTower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ }));
+ } else if (selectedTowerType === 'mage') {
+ selectedTowerPreview = game.addChild(LK.getAsset('mageTower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ }));
+ } else if (selectedTowerType === 'warrior') {
+ selectedTowerPreview = game.addChild(LK.getAsset('warriorTower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ }));
+ }
+ if (selectedTowerPreview) {
+ selectedTowerPreview.x = slot.x;
+ selectedTowerPreview.y = slot.y;
+ selectedTowerPreview.tint = 0x00FF00; // Green tint for valid placement
+ }
+ // Highlight the slot
+ slot.tint = 0x00FF00;
+ slot.alpha = 1.0;
+ }
+ break;
+ } else {
+ // Reset slot appearance
+ slot.tint = 0xFFFFFF;
+ slot.alpha = 0.7;
+ }
+ }
+};
\ No newline at end of file