User prompt
Change the location of rocks and make the tower building point 200 pixels away from any object, text or road
User prompt
Change the location of rocks and make the tower building point 200 pixels away from any object, text or road
User prompt
Place rocks in 10 empty spaces on the map, at least 100 pixels away from any object.
User prompt
Move the settings button in the top left 80 pixels down
User prompt
Move the settings button in the top left 80 pixels down
User prompt
Move the settings button in the top left 50 pixels down
User prompt
Move the settings button in the top left 30 pixels down
User prompt
Move the settings button in the top left 20 pixels down
User prompt
Move the settings button in the top left 20 pixels down
User prompt
Move the settings button in the upper left a little down
User prompt
Move all trees. Trees should never be even close to roads or tower installation points.
User prompt
There is a tree near the gold text, move that tree to a distant and empty location
User prompt
move all the trees, Trees should never be even close to the road or tower installation points.
User prompt
move all the trees
User prompt
Trees appear in different locations in each new game. Let's fix this and have them appear in fixed locations and not change every game
User prompt
remove village house roof object
User prompt
The mute button is visible, but currently does nothing when clicked. Please implement the following: 1. **Mute Toggle Functionality:** - When the mute button is clicked: • Mute or unmute all game audio (sound effects and music). • Toggle a global audio flag or use the engine’s built-in mute function. 2. **Visual Feedback (Mute Indicator):** - When the sound is muted: • Show a small "X" or slash symbol over the speaker icon for 1–2 seconds. • This can be a temporary overlay or animation to indicate audio is off. • After a few seconds, the "X" disappears, but the mute state remains active. 3. **Optional:** - You may also use a slightly dimmed or grayscale version of the speaker icon when muted. This will clearly communicate to the player that audio is off and ensure the mute button is fully functional. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The main menu was added correctly, but there is an issue when clicking the “Start Game” button: - After clicking “Start Game,” the screen turns green or blank, and the actual game does not begin. - It seems the button is not properly linked to the function or scene that initializes the game. - Please fix the following: 1. Ensure the “Start Game” button correctly loads or switches to the main gameplay scene. 2. The game initialization logic (map setup, tower panel, enemy spawner, etc.) should fully trigger after clicking the button. 3. If the game runs in a separate scene or container, make sure it is created and shown when the button is clicked. This issue prevents the game from starting and needs to be resolved so the player can enter the gameplay after the menu.
User prompt
Please add a simple main menu screen before the game starts, with the following buttons: 1. New Game – Starts the tower defense game. 2. How to Play – Opens a short instruction screen. 3. Credits – Opens a screen that displays: - Game Design: ilker.mez - AI Assistant: Grok + GPT - Platform: Built using upit.com Make sure the menu has a simple background and buttons are centered. Also, during gameplay, add a small settings icon in the top-right corner that opens a pause menu with: - Return to Main Menu - Mute/Unmute Audio
User prompt
Please implement the following visual and feedback improvements: --- 1. **Death Effect for Enemies:** - When any enemy dies, trigger a **small explosion or burst effect** at their position. - The effect should: • Be quick and visually satisfying (e.g., a puff, spark, or mini shockwave). • Last about 0.3–0.5 seconds. • Use a sound effect if possible (optional). - Ensure that this effect does not interfere with performance or gameplay mechanics. --- 2. **Round Start Announcement:** - At the beginning of each wave/round, display a **centered round counter message** on the screen for 2 seconds. • Example text: “Wave 2 / 100 Starting...” • The text should: - Be centered on the screen (over gameplay). - Use large, clear font with a slight animation (fade in/out or scale pop). - Automatically disappear after 2 seconds. - Ensure that this does not pause the game, only acts as an overlay notification. --- These effects will provide stronger feedback for enemy defeats and round progression, making the game feel more dynamic and polished. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please expand and rebalance the game's enemy and wave system with the following structure: --- 1. Total Waves: - Extend the game to have **100 total waves**. --- 2. Enemy Variety: - Add **20 new enemy types**, each one stronger than the previous. - These new enemies should have progressively increasing: • Health • Speed • Special abilities (optional: e.g., shield, poison resistance, faster movement) - Combine them with the 10 existing enemies to make a total of **30 unique enemy types**. - Introduce a **new enemy type every 3 rounds**: • Wave 1: 1st enemy type • Wave 4: 2nd enemy type • Wave 7: 3rd enemy type • ... • Wave 88: 30th enemy type - Enemies should appear **in mixed groups**, so older/weaker types still show up along with newer ones. --- 3. Wave Size Progression: Update the number of enemies per wave as follows: - **Waves 1–5:** 15 to 20 enemies - **Waves 6–15:** 20 to 25 enemies - **Waves 16–30:** 25 to 35 enemies - **Waves 31–60:** 35 to 45 enemies - **Waves 61–97:** 45 to 55 enemies - **Waves 98–100:** 60 to 75 enemies Use randomized amounts within the given ranges to keep each wave unpredictable. --- 4. New Enemy Names (20 Types): Please use the following names for the 20 new enemy types, ordered weakest to strongest: 1. **Mire Crawler** 2. **Fang Imp** 3. **Crimson Leaper** 4. **Rustback Beetle** 5. **Gravel Hound** 6. **Vine Stalker** 7. **Ashborne Wraith** 8. **Stonehide Orc** 9. **Toxic Maw** 10. **Frostback Boar** 11. **Ironmaw Troll** 12. **Volcanic Strider** 13. **Stormblade Knight** 14. **Twilight Serpent** 15. **Obsidian Colossus** 16. **Spectral Ravager** 17. **Boneclad Warbeast** 18. **Plague Titan** 19. **Abyss Reaper** 20. **Void Devourer** Ensure these enemies appear in increasing difficulty and stats as the game progresses. --- This full system will greatly enhance replayability, pacing, and strategic challenge.
User prompt
Lütfen aşağıdaki iyileştirmeleri düşman birimlerine uygulayın: --- 1. Ek Sağlık Güçlendirmesi: - Tüm düşmanların sağlığını (HP) mevcut tüm sağlık değiştiricilerine ek olarak ek **%10** artırın. - Bu, önceki artışlarla birleşmeli ve küresel olarak tüm düşman tiplerine ve dalgalarına uygulanmalıdır. --- 2. Bireysel Düşman Sağlık Çubukları: - **Her düşman biriminin üzerine küçük, bireysel bir sağlık çubuğu** ekleyin. - Sağlık çubuğu: • Düşman sprite'ının üstünde veya yakınında görünmelidir. • Düşman hasar aldıkça gerçek zamanlı olarak görsel olarak azalmalıdır. • Kalan sağlığı net bir şekilde göstermek için renkli bir dolgu (örneğin, yeşilden kırmızıya degrade veya sadece kırmızı) kullanın. • Mevcut HP'ye karşı maksimum HP'ye göre ölçeklenmelidir. - Düşman öldüğünde çubuk kaybolmalıdır. Bu değişiklikler, oyuncuyu bunaltmadan stratejik geri bildirimi ve zorluğu iyileştirir.
User prompt
Please implement a scalable cost system for tower upgrades based on each tower's base price: 1. First Upgrade Cost: - The cost of the first upgrade should be equal to the tower's **original purchase price**. • Example: If a Soldier Tower costs 80 gold, its first upgrade also costs 80 gold. 2. Subsequent Upgrades: - Each additional upgrade should cost **80% of the base price more** than the previous upgrade. • Example (base price = 80 gold): - Upgrade 1: 80 gold - Upgrade 2: 80 + (80 × 0.8) = 144 gold - Upgrade 3: 144 + (80 × 0.8) = 208 gold - and so on... 3. Scaling Logic: - Apply this formula consistently across all tower types. - Base the increase on the **original tower cost**, not the previous upgrade cost percentage-wise. This system ensures balanced scaling that rewards early investments but becomes more challenging over time.
User prompt
Please further increase the durability of all enemies: - Increase the health (HP) of all enemy units by an additional **10%** on top of any existing health values or buffs. - This should apply to all enemy types across all waves. - The goal is to make enemies more resilient and require stronger or upgraded towers to defeat them efficiently. Make sure this adjustment stacks properly with previous health increases (e.g., if already increased by 20%, the total increase becomes approximately 32%, not 3
User prompt
Please adjust the enemy reward and durability stats to improve overall game balance: 1. **Gold Reward Increase:** - Increase the amount of gold earned from each enemy by **10%**. - This helps players afford upgrades and new towers more consistently as the difficulty increases. 2. **Enemy Durability Increase:** - Increase the health (HP) or overall toughness of all enemies by **20%**. - This ensures that despite the increased gold gain, enemies remain a consistent threat and cannot be defeated too easily. Both changes should be applied globally across all enemy types and waves. This creates a balanced challenge while rewarding effective defense strategies.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function (type, wave, pathIndex, strengthLevel) { var self = Container.call(this); self.type = type; self.wave = wave; self.pathIndex = pathIndex || 1; self.strengthLevel = strengthLevel || 1; self.currentPath = self.pathIndex === 1 ? enemyPath1 : self.pathIndex === 2 ? enemyPath2 : enemyPath3; // Define base stats for each enemy type (reduced by 30% for balance) var baseStats = { goblin: { speed: 2.1, health: 28, coins: 7, flying: false }, crawler: { speed: 1.4, health: 42, coins: 10, flying: false }, bandit: { speed: 1.75, health: 35, coins: 12, flying: false }, golem: { speed: 0.7, health: 105, coins: 18, flying: false }, imp: { speed: 1.9, health: 49, coins: 15, flying: false }, knight: { speed: 1.05, health: 70, coins: 20, flying: false }, beast: { speed: 0.9, health: 84, coins: 22, flying: false }, mage: { speed: 1.2, health: 56, coins: 25, flying: false }, reaver: { speed: 2.3, health: 63, coins: 28, flying: true }, doom: { speed: 0.8, health: 140, coins: 35, flying: false }, // New enemy types (20 additional) mire_crawler: { speed: 1.6, health: 160, coins: 38, flying: false }, fang_imp: { speed: 2.0, health: 145, coins: 42, flying: false }, crimson_leaper: { speed: 2.4, health: 130, coins: 45, flying: true }, rustback_beetle: { speed: 1.1, health: 200, coins: 48, flying: false }, gravel_hound: { speed: 2.2, health: 155, coins: 52, flying: false }, vine_stalker: { speed: 1.3, health: 185, coins: 55, flying: false }, ashborne_wraith: { speed: 1.8, health: 170, coins: 58, flying: true }, stonehide_orc: { speed: 0.9, health: 240, coins: 62, flying: false }, toxic_maw: { speed: 1.5, health: 210, coins: 65, flying: false }, frostback_boar: { speed: 1.0, health: 260, coins: 68, flying: false }, ironmaw_troll: { speed: 0.8, health: 300, coins: 72, flying: false }, volcanic_strider: { speed: 1.7, health: 225, coins: 75, flying: false }, stormblade_knight: { speed: 1.4, health: 280, coins: 78, flying: false }, twilight_serpent: { speed: 2.1, health: 250, coins: 82, flying: true }, obsidian_colossus: { speed: 0.6, health: 400, coins: 85, flying: false }, spectral_ravager: { speed: 2.0, health: 320, coins: 88, flying: true }, boneclad_warbeast: { speed: 1.2, health: 380, coins: 92, flying: false }, plague_titan: { speed: 0.7, health: 450, coins: 95, flying: false }, abyss_reaper: { speed: 1.6, health: 420, coins: 98, flying: true }, void_devourer: { speed: 0.9, health: 500, coins: 100, flying: false } }; var stats = baseStats[type] || baseStats.goblin; // Scale stats by strength level var strengthMultiplier = 1 + (self.strengthLevel - 1) * 0.4; var speedMultiplier = 1 + (self.strengthLevel - 1) * 0.08; self.speed = stats.speed * speedMultiplier; self.maxHealth = Math.floor(stats.health * strengthMultiplier * 1.2 * 1.1 * 1.1); self.health = self.maxHealth; self.pathStep = 0; self.coinValue = Math.floor(stats.coins * strengthMultiplier * 1.1); self.flying = stats.flying; self.regeneration = type === 'beast' ? 0.5 : type === 'frostback_boar' ? 0.3 : type === 'plague_titan' ? 0.8 : 0; self.poisonResistant = type === 'doom' || type === 'toxic_maw' || type === 'plague_titan' || type === 'void_devourer'; self.slowResistant = type === 'doom' || type === 'volcanic_strider' || type === 'stormblade_knight' || type === 'abyss_reaper'; var graphics = self.attachAsset('enemy_' + type, { anchorX: 0.5, anchorY: 0.5 }); // Create health bar background self.healthBarBg = self.attachAsset('enemy_' + type, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.1, y: -25 }); self.healthBarBg.tint = 0x333333; // Create health bar fill self.healthBarFill = self.attachAsset('enemy_' + type, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.1, y: -25 }); self.healthBarFill.tint = 0x00FF00; self.x = self.currentPath[0].x; self.y = self.currentPath[0].y; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFF0000, 200); // Update health bar fill based on remaining health if (self.healthBarFill) { var healthPercent = Math.max(0, self.health / self.maxHealth); self.healthBarFill.scaleX = 0.8 * healthPercent; // Change color from green to red based on health var redComponent = Math.floor(255 * (1 - healthPercent)); var greenComponent = Math.floor(255 * healthPercent); var healthColor = redComponent << 16 | greenComponent << 8 | 0x00; self.healthBarFill.tint = healthColor; } if (self.health <= 0) { if (!audioMuted) { LK.getSound('enemy_hit').play(); } // Create death effect at enemy position tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 400, easing: tween.easeOut }); return true; } return false; }; self.update = function () { if (self.pathStep < self.currentPath.length - 1) { var target = self.currentPath[self.pathStep + 1]; var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 5) { self.pathStep++; if (self.pathStep >= self.currentPath.length - 1) { self.reachedCastle = 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.targetX = targetX; self.targetY = targetY; self.speed = type === 'arrow' ? 16 : type === 'cannonball' ? 12 : 14; var graphics = self.attachAsset('projectile_' + type, { anchorX: 0.5, anchorY: 0.5 }); self.x = startX; self.y = startY; var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); self.velocityX = dx / distance * self.speed; self.velocityY = dy / distance * self.speed; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; var distToTarget = Math.sqrt((self.x - self.targetX) * (self.x - self.targetX) + (self.y - self.targetY) * (self.y - self.targetY)); if (distToTarget < 10) { self.hasReachedTarget = true; } }; return self; }); var Tower = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.level = 1; self.lastShotTime = 0; self.maxLevel = type === 'antiair' || type === 'poison' || type === 'tesla' ? 5 : 10; // Initialize tower stats based on type if (type === 'infantry') { self.damage = 20; self.range = 100; self.attackSpeed = 600; self.cost = 80; self.projectileType = 'arrow'; } else if (type === 'frost') { self.damage = 15; self.range = 90; self.attackSpeed = 800; self.cost = 120; self.projectileType = 'magic'; self.slowEffect = true; } else if (type === 'antiair') { self.damage = 40; self.range = 130; self.attackSpeed = 1000; self.cost = 150; self.projectileType = 'magic'; self.antiAir = true; } else if (type === 'poison') { self.damage = 10; self.range = 80; self.attackSpeed = 1200; self.cost = 100; self.projectileType = 'magic'; self.poisonEffect = true; } else if (type === 'tesla') { self.damage = 35; self.range = 95; self.attackSpeed = 900; self.cost = 180; self.projectileType = 'magic'; self.chainLightning = true; } var graphics = self.attachAsset('tower_' + type, { anchorX: 0.5, anchorY: 0.5 }); self.getUpgradeNames = function () { if (self.type === 'infantry') { return ['Rifleman', 'Marksman', 'Sharpshooter', 'Machine Gunner', 'Grenadier', 'Mortar Operator', 'Tank Commander', 'Bazooka Specialist', 'Rocket Launcher', 'Missile Battery']; } else if (self.type === 'frost') { return ['Frost Spire', 'Ice Shard Tower', 'Blizzard Bastion', 'Cryo Cannon', 'Glacier Fortress', 'Snowstorm Citadel', 'Avalanche Keep', 'Frozen Maelstrom', 'Arctic Warden', 'Absolute Zero']; } else if (self.type === 'antiair') { return ['Flak Cannon', 'SAM Launcher', 'Radar Missile Battery', 'Laser Air Defense', 'Plasma Barrier']; } else if (self.type === 'poison') { return ['Venom Sprayer', 'Toxic Spitter', 'Acid Dart Tower', 'Corrosive Spire', 'Plague Altar']; } else if (self.type === 'tesla') { return ['Static Coil', 'Dual Coil', 'Arc Emitter', 'Thunderstorm Core', 'Lightning God']; } }; self.canShoot = function () { return LK.ticks - self.lastShotTime > self.attackSpeed / (1000 / 60); }; self.findTarget = function () { var closestEnemy = null; var closestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var distance = Math.sqrt((enemy.x - self.x) * (enemy.x - self.x) + (enemy.y - self.y) * (enemy.y - self.y)); if (distance <= self.range && distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } return closestEnemy; }; self.shoot = function (target) { if (!self.canShoot()) return; self.lastShotTime = LK.ticks; var projectile = new Projectile(self.projectileType, self.x, self.y, target.x, target.y, self.damage); projectile.towerType = self.type; projectile.slowEffect = self.slowEffect; projectile.poisonEffect = self.poisonEffect; projectile.chainLightning = self.chainLightning; projectiles.push(projectile); isoContainer.addChild(projectile); if (!audioMuted) { LK.getSound('shoot_arrow').play(); } }; self.getUpgradeCost = function () { // First upgrade costs the same as the tower's base price if (self.level === 1) { return self.cost; } // Each subsequent upgrade costs 80% of base price more than the previous var totalCost = self.cost; // First upgrade cost for (var i = 2; i <= self.level; i++) { totalCost += Math.floor(self.cost * 0.8); } return totalCost; }; self.upgrade = function () { if (self.level < self.maxLevel) { self.level++; self.damage = Math.floor(self.damage * 1.3); // Calculate range increase with diminishing returns var rangeMultiplier = 1.0; if (self.level === 2) { rangeMultiplier = 1.10; // +10% for level 1 upgrade } else if (self.level === 3) { rangeMultiplier = 1.10 * 1.05; // +10% then +5% } else if (self.level === 4) { rangeMultiplier = 1.10 * 1.05 * 1.035; // +10%, +5%, then +3.5% } else if (self.level >= 5) { // +10%, +5%, +3.5%, then +2% for each additional level rangeMultiplier = 1.10 * 1.05 * 1.035; var additionalLevels = self.level - 4; rangeMultiplier *= Math.pow(1.02, additionalLevels); } // Apply range multiplier to base range for this tower type var baseRange; if (self.type === 'infantry') baseRange = 100;else if (self.type === 'frost') baseRange = 90;else if (self.type === 'antiair') baseRange = 130;else if (self.type === 'poison') baseRange = 80;else if (self.type === 'tesla') baseRange = 95; self.range = Math.floor(baseRange * rangeMultiplier); self.attackSpeed = Math.max(200, Math.floor(self.attackSpeed * 0.95)); // Visual upgrade indicators var tintColors = [0xFFFFFF, 0xFFD700, 0xFF6347, 0xFF4500, 0x8A2BE2, 0x00FF00, 0x00FFFF, 0xFF69B4, 0xFFFF00, 0xFF0000]; graphics.tint = tintColors[self.level - 1] || 0xFF0000; // Show range indicator for upgraded towers if (self.level > 1 && !self.rangeIndicator) { self.rangeIndicator = LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, alpha: 0.1, scaleX: self.range / 40, scaleY: self.range / 40 }); self.rangeIndicator.x = self.x; self.rangeIndicator.y = self.y; self.rangeIndicator.tint = 0x00FF00; isoContainer.addChild(self.rangeIndicator); } else if (self.rangeIndicator) { self.rangeIndicator.scaleX = self.range / 40; self.rangeIndicator.scaleY = self.range / 40; } } }; self.down = function (x, y, obj) { selectedTower = self; // Clear any existing range indicator if (activeRangeIndicator && activeRangeIndicator.destroy) { activeRangeIndicator.destroy(); activeRangeIndicator = null; } // Create new range indicator activeRangeIndicator = LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, alpha: 0.2, scaleX: self.range / 27.5, scaleY: self.range / 27.5 }); activeRangeIndicator.x = self.x; activeRangeIndicator.y = self.y; activeRangeIndicator.tint = 0x00FFFF; // Cyan color for range indicator isoContainer.addChild(activeRangeIndicator); if (upgradeText && upgradeText.destroy) { upgradeText.destroy(); } if (self.level < self.maxLevel) { var cost = self.getUpgradeCost(); var names = self.getUpgradeNames(); var nextName = names[self.level - 1] || 'Max Level'; upgradeText = new Text2(nextName + ': ' + cost + ' gold', { size: 24, fill: coins >= cost ? 0x00FF00 : 0xFF0000 }); upgradeText.anchor.set(0.5, 1); upgradeText.x = self.x; upgradeText.y = self.y - 40; isoContainer.addChild(upgradeText); if (coins >= cost) { upgradeText.down = function () { coins -= cost; coinsText.setText('Gold: ' + coins); self.upgrade(); if (upgradeText && upgradeText.destroy) { upgradeText.destroy(); } upgradeText = null; selectedTower = null; // Clear range indicator when upgrading if (activeRangeIndicator && activeRangeIndicator.destroy) { activeRangeIndicator.destroy(); activeRangeIndicator = null; } }; } } else { upgradeText = new Text2('MAX LEVEL', { size: 30, fill: 0xFFFFFF }); upgradeText.anchor.set(0.5, 1); upgradeText.x = self.x; upgradeText.y = self.y - 40; isoContainer.addChild(upgradeText); } }; self.update = function () { var target = self.findTarget(); if (target) { self.shoot(target); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x228B22 }); /**** * Game Code ****/ // Use game container directly for top-down view var isoContainer = game; var gameState = 'mainMenu'; var mainMenuContainer = null; var howToPlayContainer = null; var creditsContainer = null; var settingsContainer = null; var settingsIcon = null; var audioMuted = false; var muteIndicator = null; var castleType = 'square'; var difficulty = 'easy'; var currentWave = 0; var maxWaves = 100; var waveEnemies = []; var enemies = []; var towers = []; var projectiles = []; var coins = 300; var castleHealth = 100; var waveInProgress = false; var nextWaveTimer = 0; var selectedTowerType = null; var selectedTower = null; var upgradeText = null; var activeRangeIndicator = null; // Enemy path 1: Detailed horizontal then vertical path var enemyPath1 = [{ x: 0, y: 200 }, { x: 25.6, y: 200 }, { x: 51.2, y: 200 }, { x: 76.8, y: 200 }, { x: 102.4, y: 200 }, { x: 128, y: 200 }, { x: 153.6, y: 200 }, { x: 179.2, y: 200 }, { x: 204.8, y: 200 }, { x: 230.4, y: 200 }, { x: 256, y: 200 }, { x: 281.6, y: 200 }, { x: 307.2, y: 200 }, { x: 332.8, y: 200 }, { x: 358.4, y: 200 }, { x: 384, y: 200 }, { x: 409.6, y: 200 }, { x: 435.2, y: 200 }, { x: 460.8, y: 200 }, { x: 486.4, y: 200 }, { x: 512, y: 200 }, { x: 537.6, y: 200 }, { x: 563.2, y: 200 }, { x: 588.8, y: 200 }, { x: 614.4, y: 200 }, { x: 640, y: 200 }, { x: 665.6, y: 200 }, { x: 691.2, y: 200 }, { x: 716.8, y: 200 }, { x: 742.4, y: 200 }, { x: 768, y: 200 }, { x: 793.6, y: 200 }, { x: 819.2, y: 200 }, { x: 844.8, y: 200 }, { x: 870.4, y: 200 }, { x: 896, y: 200 }, { x: 921.6, y: 200 }, { x: 947.2, y: 200 }, { x: 972.8, y: 200 }, { x: 998.4, y: 200 }, { x: 1024, y: 200 }, { x: 1024, y: 240 }, { x: 1024, y: 280 }, { x: 1024, y: 320 }, { x: 1024, y: 360 }, { x: 1024, y: 400 }, { x: 1024, y: 440 }, { x: 1024, y: 480 }, { x: 1024, y: 520 }, { x: 1024, y: 560 }, { x: 1024, y: 600 }, { x: 998.4, y: 600 }, { x: 972.8, y: 600 }, { x: 947.2, y: 600 }, { x: 921.6, y: 600 }, { x: 896, y: 600 }, { x: 870.4, y: 600 }, { x: 844.8, y: 600 }, { x: 819.2, y: 600 }, { x: 793.6, y: 600 }, { x: 768, y: 600 }, { x: 768, y: 640 }, { x: 768, y: 680 }, { x: 768, y: 720 }, { x: 768, y: 760 }, { x: 768, y: 800 }, { x: 768, y: 840 }, { x: 768, y: 880 }, { x: 768, y: 920 }, { x: 768, y: 960 }, { x: 768, y: 1000 }, { x: 768, y: 1040 }, { x: 768, y: 1080 }, { x: 768, y: 1120 }, { x: 768, y: 1160 }, { x: 768, y: 1200 }, { x: 768, y: 1240 }, { x: 768, y: 1280 }, { x: 768, y: 1320 }, { x: 768, y: 1360 }, { x: 768, y: 1400 }, { x: 768, y: 1440 }, { x: 768, y: 1480 }, { x: 768, y: 1520 }, { x: 768, y: 1560 }, { x: 768, y: 1600 }, { x: 768, y: 1640 }, { x: 768, y: 1680 }, { x: 768, y: 1720 }, { x: 768, y: 1760 }, { x: 768, y: 1800 }, { x: 793.6, y: 1800 }, { x: 819.2, y: 1800 }, { x: 844.8, y: 1800 }, { x: 870.4, y: 1800 }, { x: 896, y: 1800 }, { x: 921.6, y: 1800 }, { x: 947.2, y: 1800 }, { x: 972.8, y: 1800 }, { x: 998.4, y: 1800 }, { x: 1024, y: 1800 }, { x: 1024, y: 1840 }, { x: 1024, y: 1880 }, { x: 1024, y: 1920 }, { x: 1024, y: 1960 }, { x: 1024, y: 2000 }, { x: 1024, y: 2040 }, { x: 1024, y: 2080 }, { x: 1024, y: 2120 }, { x: 1024, y: 2160 }, { x: 1024, y: 2200 }]; // Enemy path 2: Detailed eastern route path var enemyPath2 = [{ x: 2048, y: 800 }, { x: 2022.4, y: 800 }, { x: 1996.8, y: 800 }, { x: 1971.2, y: 800 }, { x: 1945.6, y: 800 }, { x: 1920, y: 800 }, { x: 1894.4, y: 800 }, { x: 1868.8, y: 800 }, { x: 1843.2, y: 800 }, { x: 1817.6, y: 800 }, { x: 1792, y: 800 }, { x: 1766.4, y: 800 }, { x: 1740.8, y: 800 }, { x: 1715.2, y: 800 }, { x: 1689.6, y: 800 }, { x: 1664, y: 800 }, { x: 1638.4, y: 800 }, { x: 1612.8, y: 800 }, { x: 1587.2, y: 800 }, { x: 1561.6, y: 800 }, { x: 1536, y: 800 }, { x: 1510.4, y: 800 }, { x: 1484.8, y: 800 }, { x: 1459.2, y: 800 }, { x: 1433.6, y: 800 }, { x: 1408, y: 800 }, { x: 1382.4, y: 800 }, { x: 1356.8, y: 800 }, { x: 1331.2, y: 800 }, { x: 1305.6, y: 800 }, { x: 1280, y: 800 }, { x: 1254.4, y: 800 }, { x: 1228.8, y: 800 }, { x: 1203.2, y: 800 }, { x: 1177.6, y: 800 }, { x: 1152, y: 800 }, { x: 1126.4, y: 800 }, { x: 1100.8, y: 800 }, { x: 1075.2, y: 800 }, { x: 1049.6, y: 800 }, { x: 1024, y: 800 }, { x: 1024, y: 780 }, { x: 1024, y: 760 }, { x: 1024, y: 740 }, { x: 1024, y: 720 }, { x: 1024, y: 700 }, { x: 1024, y: 680 }, { x: 1024, y: 660 }, { x: 1024, y: 640 }, { x: 1024, y: 620 }, { x: 1024, y: 600 }, { x: 1049.6, y: 600 }, { x: 1075.2, y: 600 }, { x: 1100.8, y: 600 }, { x: 1126.4, y: 600 }, { x: 1152, y: 600 }, { x: 1177.6, y: 600 }, { x: 1203.2, y: 600 }, { x: 1228.8, y: 600 }, { x: 1254.4, y: 600 }, { x: 1280, y: 600 }, { x: 1280, y: 640 }, { x: 1280, y: 680 }, { x: 1280, y: 720 }, { x: 1280, y: 760 }, { x: 1280, y: 800 }, { x: 1280, y: 840 }, { x: 1280, y: 880 }, { x: 1280, y: 920 }, { x: 1280, y: 960 }, { x: 1280, y: 1000 }, { x: 1280, y: 1040 }, { x: 1280, y: 1080 }, { x: 1280, y: 1120 }, { x: 1280, y: 1160 }, { x: 1280, y: 1200 }, { x: 1280, y: 1240 }, { x: 1280, y: 1280 }, { x: 1280, y: 1320 }, { x: 1280, y: 1360 }, { x: 1280, y: 1400 }, { x: 1280, y: 1440 }, { x: 1280, y: 1480 }, { x: 1280, y: 1520 }, { x: 1280, y: 1560 }, { x: 1280, y: 1600 }, { x: 1280, y: 1640 }, { x: 1280, y: 1680 }, { x: 1280, y: 1720 }, { x: 1280, y: 1760 }, { x: 1280, y: 1800 }, { x: 1254.4, y: 1800 }, { x: 1228.8, y: 1800 }, { x: 1203.2, y: 1800 }, { x: 1177.6, y: 1800 }, { x: 1152, y: 1800 }, { x: 1126.4, y: 1800 }, { x: 1100.8, y: 1800 }, { x: 1075.2, y: 1800 }, { x: 1049.6, y: 1800 }, { x: 1024, y: 1800 }, { x: 1024, y: 1840 }, { x: 1024, y: 1880 }, { x: 1024, y: 1920 }, { x: 1024, y: 1960 }, { x: 1024, y: 2000 }, { x: 1024, y: 2040 }, { x: 1024, y: 2080 }, { x: 1024, y: 2120 }, { x: 1024, y: 2160 }, { x: 1024, y: 2200 }]; // Enemy path 3: Detailed western route path var enemyPath3 = [{ x: 2048, y: 50 }, { x: 2022.4, y: 50 }, { x: 1996.8, y: 50 }, { x: 1971.2, y: 50 }, { x: 1945.6, y: 50 }, { x: 1920, y: 50 }, { x: 1894.4, y: 50 }, { x: 1868.8, y: 50 }, { x: 1843.2, y: 50 }, { x: 1817.6, y: 50 }, { x: 1792, y: 50 }, { x: 1766.4, y: 50 }, { x: 1740.8, y: 50 }, { x: 1715.2, y: 50 }, { x: 1689.6, y: 50 }, { x: 1664, y: 50 }, { x: 1638.4, y: 50 }, { x: 1612.8, y: 50 }, { x: 1587.2, y: 50 }, { x: 1561.6, y: 50 }, { x: 1536, y: 50 }, { x: 1510.4, y: 50 }, { x: 1484.8, y: 50 }, { x: 1459.2, y: 50 }, { x: 1433.6, y: 50 }, { x: 1408, y: 50 }, { x: 1382.4, y: 50 }, { x: 1356.8, y: 50 }, { x: 1331.2, y: 50 }, { x: 1305.6, y: 50 }, { x: 1280, y: 50 }, { x: 1280, y: 90 }, { x: 1280, y: 130 }, { x: 1280, y: 170 }, { x: 1280, y: 210 }, { x: 1280, y: 250 }, { x: 1280, y: 290 }, { x: 1280, y: 330 }, { x: 1280, y: 370 }, { x: 1280, y: 410 }, { x: 1280, y: 450 }, { x: 1280, y: 490 }, { x: 1280, y: 530 }, { x: 1280, y: 570 }, { x: 1280, y: 610 }, { x: 1280, y: 650 }, { x: 1280, y: 690 }, { x: 1280, y: 730 }, { x: 1280, y: 770 }, { x: 1280, y: 810 }, { x: 1280, y: 850 }, { x: 1280, y: 890 }, { x: 1280, y: 930 }, { x: 1280, y: 970 }, { x: 1280, y: 1010 }, { x: 1280, y: 1050 }, { x: 1280, y: 1090 }, { x: 1280, y: 1130 }, { x: 1280, y: 1170 }, { x: 1280, y: 1210 }, { x: 1280, y: 1250 }, { x: 1280, y: 1290 }, { x: 1280, y: 1330 }, { x: 1280, y: 1370 }, { x: 1280, y: 1410 }, { x: 1280, y: 1450 }, { x: 1280, y: 1490 }, { x: 1280, y: 1530 }, { x: 1280, y: 1570 }, { x: 1280, y: 1610 }, { x: 1280, y: 1650 }, { x: 1280, y: 1690 }, { x: 1280, y: 1730 }, { x: 1280, y: 1770 }, { x: 1280, y: 1810 }, { x: 1280, y: 1850 }, { x: 1254.4, y: 1800 }, { x: 1228.8, y: 1800 }, { x: 1203.2, y: 1800 }, { x: 1177.6, y: 1800 }, { x: 1152, y: 1800 }, { x: 1126.4, y: 1800 }, { x: 1100.8, y: 1800 }, { x: 1075.2, y: 1800 }, { x: 1049.6, y: 1800 }, { x: 1024, y: 1800 }, { x: 1024, y: 1840 }, { x: 1024, y: 1880 }, { x: 1024, y: 1920 }, { x: 1024, y: 1960 }, { x: 1024, y: 2000 }, { x: 1024, y: 2040 }, { x: 1024, y: 2080 }, { x: 1024, y: 2120 }, { x: 1024, y: 2160 }, { x: 1024, y: 2200 }]; var buildZones = []; var terrainFeatures = []; function createPath() { // Create all paths visible from the start for strategic planning // Create path 1 for (var i = 0; i < enemyPath1.length; i++) { var pathTile = isoContainer.addChild(LK.getAsset('path_tile', { anchorX: 0.5, anchorY: 0.5, x: enemyPath1[i].x, y: enemyPath1[i].y, alpha: 0.7 })); } // Create path 2 - always visible for (var i = 0; i < enemyPath2.length; i++) { var pathTile = isoContainer.addChild(LK.getAsset('path_tile', { anchorX: 0.5, anchorY: 0.5, x: enemyPath2[i].x, y: enemyPath2[i].y, alpha: 0.7 })); } // Create path 3 - always visible for (var i = 0; i < enemyPath3.length; i++) { var pathTile = isoContainer.addChild(LK.getAsset('path_tile', { anchorX: 0.5, anchorY: 0.5, x: enemyPath3[i].x, y: enemyPath3[i].y, alpha: 0.7 })); } // Create build zones around paths createBuildZones(); } function createTerrain() { // Create lake var lake = isoContainer.addChild(LK.getAsset('lake', { anchorX: 0.5, anchorY: 0.5, x: 400, y: 500, alpha: 0.8 })); // Create waterfall (three parallel lines) var waterfall1 = isoContainer.addChild(LK.getAsset('waterfall_line', { anchorX: 0.5, anchorY: 0.5, x: 1550, y: 300 })); var waterfall2 = isoContainer.addChild(LK.getAsset('waterfall_line', { anchorX: 0.5, anchorY: 0.5, x: 1560, y: 300 })); var waterfall3 = isoContainer.addChild(LK.getAsset('waterfall_line', { anchorX: 0.5, anchorY: 0.5, x: 1570, y: 300 })); // Create lake in the middle of the map var centralLake = isoContainer.addChild(LK.getAsset('lake', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, alpha: 0.8, scaleX: 1.5, scaleY: 1.5 })); // Create left village (further west of castle) var leftVillagePositions = [{ x: 450, y: 2050 }, { x: 700, y: 2300 }, { x: 300, y: 2350 }, { x: 650, y: 2100 }]; for (var i = 0; i < leftVillagePositions.length; i++) { var pos = leftVillagePositions[i]; // Create house base var house = isoContainer.addChild(LK.getAsset('village_house', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, alpha: 0.9 })); // Roof removed } // Create right village (further east of castle) var rightVillagePositions = [{ x: 1600, y: 2050 }, { x: 1350, y: 2300 }, { x: 1750, y: 2250 }, { x: 1500, y: 2450 }]; for (var i = 0; i < rightVillagePositions.length; i++) { var pos = rightVillagePositions[i]; // Create house base var house = isoContainer.addChild(LK.getAsset('village_house', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, alpha: 0.9 })); // Roof removed } // Create 50 trees scattered across the map avoiding all objects var treePositions = []; // Helper function to check if a position conflicts with existing objects function isPositionSafe(x, y, buffer) { buffer = buffer || 200; // Check boundaries if (x < 50 || x > 1998 || y < 50 || y > 2682) return false; // Check castle area if (Math.sqrt((x - 1024) * (x - 1024) + (y - 2200) * (y - 2200)) < 300 + buffer) return false; // Check waterfall area if (x >= 1500 - buffer && x <= 1600 + buffer) return false; // Check central lake area if (Math.sqrt((x - 1024) * (x - 1024) + (y - 1366) * (y - 1366)) < 200 + buffer) return false; // Check original lake area if (Math.sqrt((x - 400) * (x - 400) + (y - 500) * (y - 500)) < 150 + buffer) return false; // Check all enemy paths with buffer var allPaths = [enemyPath1, enemyPath2, enemyPath3]; for (var p = 0; p < allPaths.length; p++) { var path = allPaths[p]; for (var i = 0; i < path.length; i++) { if (Math.sqrt((x - path[i].x) * (x - path[i].x) + (y - path[i].y) * (y - path[i].y)) < buffer + 20) { return false; } } } // Check build zones - now requiring 200 pixels distance for (var i = 0; i < buildZones.length; i++) { if (Math.sqrt((x - buildZones[i].x) * (x - buildZones[i].x) + (y - buildZones[i].y) * (y - buildZones[i].y)) < 200) { return false; } } // Check village house areas var allVillagePositions = leftVillagePositions.concat(rightVillagePositions); for (var i = 0; i < allVillagePositions.length; i++) { var house = allVillagePositions[i]; if (Math.sqrt((x - house.x) * (x - house.x) + (y - house.y) * (y - house.y)) < buffer) { return false; } } // Check against other trees for (var i = 0; i < treePositions.length; i++) { var tree = treePositions[i]; if (Math.sqrt((x - tree.x) * (x - tree.x) + (y - tree.y) * (y - tree.y)) < buffer) { return false; } } // Check against rocks for (var i = 0; i < rockPositions.length; i++) { var rock = rockPositions[i]; if (Math.sqrt((x - rock.x) * (x - rock.x) + (y - rock.y) * (y - rock.y)) < buffer) { return false; } } return true; } // Define fixed tree positions far from roads and tower installation points var fixedTreePositions = [{ x: 1700, y: 200 }, { x: 1800, y: 250 }, { x: 1650, y: 350 }, { x: 1750, y: 450 }, { x: 1900, y: 300 }, { x: 1950, y: 200 }, { x: 1600, y: 150 }, { x: 1850, y: 100 }, { x: 1950, y: 150 }, { x: 150, y: 300 }, { x: 250, y: 350 }, { x: 350, y: 400 }, { x: 200, y: 450 }, { x: 100, y: 500 }, { x: 300, y: 300 }, { x: 400, y: 350 }, { x: 500, y: 400 }, { x: 450, y: 300 }, { x: 550, y: 350 }, { x: 100, y: 1000 }, { x: 200, y: 1100 }, { x: 300, y: 1200 }, { x: 150, y: 1300 }, { x: 250, y: 1400 }, { x: 100, y: 1500 }, { x: 350, y: 1000 }, { x: 400, y: 1100 }, { x: 450, y: 1200 }, { x: 500, y: 1300 }, { x: 550, y: 1400 }, { x: 600, y: 1500 }, { x: 1700, y: 1000 }, { x: 1800, y: 1100 }, { x: 1900, y: 1200 }, { x: 1950, y: 1300 }, { x: 1850, y: 1400 }, { x: 1750, y: 1500 }, { x: 1650, y: 1000 }, { x: 1600, y: 1100 }, { x: 1550, y: 1200 }, { x: 1500, y: 1300 }, { x: 1450, y: 1400 }, { x: 1400, y: 1500 }, { x: 100, y: 2100 }, { x: 200, y: 2000 }, { x: 300, y: 1950 }, { x: 400, y: 2000 }, { x: 500, y: 2100 }, { x: 1600, y: 2100 }, { x: 1700, y: 2000 }]; // Define rock positions in empty spaces at least 200 pixels away from any object var rockPositions = [{ x: 200, y: 800 }, { x: 1700, y: 350 }, { x: 250, y: 1700 }, { x: 1800, y: 1500 }, { x: 700, y: 350 }, { x: 1600, y: 100 }, { x: 1900, y: 950 }, { x: 150, y: 1200 }, { x: 1700, y: 1200 }, { x: 650, y: 1750 }]; // Use the first 50 fixed positions (or however many we have) for (var i = 0; i < Math.min(50, fixedTreePositions.length); i++) { treePositions.push(fixedTreePositions[i]); } // Create the trees for (var i = 0; i < treePositions.length; i++) { var pos = treePositions[i]; var tree = isoContainer.addChild(LK.getAsset('tree', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, scaleX: 1.0, scaleY: 1.0, alpha: 0.9 })); } // Create rocks at predefined positions for (var i = 0; i < rockPositions.length; i++) { var pos = rockPositions[i]; var rock = isoContainer.addChild(LK.getAsset('ruin', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, scaleX: 1.2, scaleY: 1.2, alpha: 0.8 })); terrainFeatures.push(rock); } } function createBuildZones() { var zones = [ // enemyPath1: y=200, both sides { x: 0, y: 150 }, { x: 0, y: 250 }, { x: 100, y: 150 }, { x: 100, y: 250 }, { x: 200, y: 150 }, { x: 200, y: 250 }, { x: 300, y: 150 }, { x: 300, y: 250 }, { x: 400, y: 150 }, { x: 400, y: 250 }, { x: 500, y: 150 }, { x: 500, y: 250 }, { x: 600, y: 150 }, { x: 600, y: 250 }, { x: 700, y: 150 }, { x: 700, y: 250 }, { x: 800, y: 150 }, { x: 800, y: 250 }, { x: 900, y: 150 }, { x: 900, y: 250 }, // enemyPath1: Corner (1024, 200, right turn) { x: 974, y: 150 }, { x: 1074, y: 150 }, { x: 974, y: 250 }, { x: 1074, y: 250 }, // enemyPath1: U-shape (x=1024, y=200-600) { x: 974, y: 300 }, { x: 1074, y: 300 }, { x: 974, y: 400 }, { x: 1074, y: 400 }, { x: 974, y: 500 }, { x: 1074, y: 500 }, // enemyPath1: Corner (1024, 600, left turn, intersection) { x: 974, y: 550 }, { x: 1074, y: 550 }, { x: 974, y: 650 }, { x: 1074, y: 650 }, // enemyPath1: U-shape (x=768, y=600-1800) { x: 718, y: 700 }, { x: 818, y: 700 }, { x: 718, y: 800 }, { x: 818, y: 800 }, { x: 718, y: 900 }, { x: 818, y: 900 }, { x: 718, y: 1000 }, { x: 818, y: 1000 }, { x: 718, y: 1100 }, { x: 818, y: 1100 }, { x: 718, y: 1200 }, { x: 818, y: 1200 }, { x: 718, y: 1300 }, { x: 818, y: 1300 }, { x: 718, y: 1400 }, { x: 818, y: 1400 }, { x: 718, y: 1500 }, { x: 818, y: 1500 }, { x: 718, y: 1600 }, { x: 818, y: 1600 }, { x: 718, y: 1700 }, { x: 818, y: 1700 }, // enemyPath1: Corner (768, 1800, right turn) { x: 718, y: 1750 }, { x: 818, y: 1750 }, { x: 718, y: 1850 }, { x: 818, y: 1850 }, // enemyPath1: Corner (896, 1800, right turn) { x: 846, y: 1750 }, { x: 946, y: 1750 }, { x: 846, y: 1850 }, { x: 946, y: 1850 }, // enemyPath1: Corner (1024, 1800, down, intersection) { x: 974, y: 1750 }, { x: 1074, y: 1750 }, { x: 974, y: 1850 }, { x: 1074, y: 1850 }, // enemyPath2: y=800, both sides { x: 2048, y: 750 }, { x: 2048, y: 850 }, { x: 1948, y: 750 }, { x: 1948, y: 850 }, { x: 1848, y: 750 }, { x: 1848, y: 850 }, { x: 1748, y: 750 }, { x: 1748, y: 850 }, { x: 1648, y: 750 }, { x: 1648, y: 850 }, { x: 1548, y: 750 }, { x: 1548, y: 850 }, { x: 1448, y: 750 }, { x: 1448, y: 850 }, { x: 1348, y: 750 }, { x: 1348, y: 850 }, { x: 1248, y: 750 }, { x: 1248, y: 850 }, { x: 1148, y: 750 }, { x: 1148, y: 850 }, // enemyPath2: Corner (1024, 800, down) { x: 974, y: 750 }, { x: 1074, y: 750 }, { x: 974, y: 850 }, { x: 1074, y: 850 }, // enemyPath2: U-shape (x=1024, y=600-800) { x: 974, y: 650 }, { x: 1074, y: 650 }, { x: 974, y: 700 }, { x: 1074, y: 700 }, // enemyPath2: Corner (1024, 600, right turn, intersection) { x: 974, y: 550 }, { x: 1074, y: 550 }, { x: 974, y: 650 }, { x: 1074, y: 650 }, // enemyPath2: U-shape (x=1280, y=600-1800) { x: 1230, y: 650 }, { x: 1330, y: 650 }, { x: 1230, y: 750 }, { x: 1330, y: 750 }, { x: 1230, y: 850 }, { x: 1330, y: 850 }, { x: 1230, y: 950 }, { x: 1330, y: 950 }, { x: 1230, y: 1050 }, { x: 1330, y: 1050 }, { x: 1230, y: 1150 }, { x: 1330, y: 1150 }, { x: 1230, y: 1250 }, { x: 1330, y: 1250 }, { x: 1230, y: 1350 }, { x: 1330, y: 1350 }, { x: 1230, y: 1450 }, { x: 1330, y: 1450 }, { x: 1230, y: 1550 }, { x: 1330, y: 1550 }, { x: 1230, y: 1650 }, { x: 1330, y: 1650 }, // enemyPath2: Corner (1280, 1800, left turn) { x: 1230, y: 1750 }, { x: 1330, y: 1750 }, { x: 1230, y: 1850 }, { x: 1330, y: 1850 }, // enemyPath2: Corner (1152, 1800, left turn) { x: 1102, y: 1750 }, { x: 1202, y: 1750 }, { x: 1102, y: 1850 }, { x: 1202, y: 1850 }, // enemyPath3: y=50, both sides { x: 2048, y: 0 }, { x: 2048, y: 100 }, { x: 1948, y: 0 }, { x: 1948, y: 100 }, { x: 1848, y: 0 }, { x: 1848, y: 100 }, { x: 1748, y: 0 }, { x: 1748, y: 100 }, { x: 1648, y: 0 }, { x: 1648, y: 100 }, { x: 1548, y: 0 }, { x: 1548, y: 100 }, { x: 1448, y: 0 }, { x: 1448, y: 100 }, // enemyPath3: Corner (1280, 50, down) { x: 1230, y: 0 }, { x: 1330, y: 0 }, { x: 1230, y: 100 }, { x: 1330, y: 100 }, // enemyPath3: U-shape (x=1280, y=50-1800) { x: 1230, y: 150 }, { x: 1330, y: 150 }, { x: 1230, y: 250 }, { x: 1330, y: 250 }, { x: 1230, y: 350 }, { x: 1330, y: 350 }, { x: 1230, y: 450 }, { x: 1330, y: 450 }, // enemyPath3: Corner (1280, 1800, left turn) { x: 1230, y: 1750 }, { x: 1330, y: 1750 }, { x: 1230, y: 1850 }, { x: 1330, y: 1850 }, // enemyPath3: Corner (1152, 1800, left turn) { x: 1102, y: 1750 }, { x: 1202, y: 1750 }, { x: 1102, y: 1850 }, { x: 1202, y: 1850 }]; for (var i = 0; i < zones.length; i++) { var zone = isoContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: zones[i].x, y: zones[i].y, alpha: 0.3 })); zone.zoneData = { x: zones[i].x, y: zones[i].y, occupied: false, originalAlpha: 0.3 }; buildZones.push(zone); } } function updateBuildZoneVisuals() { for (var i = 0; i < buildZones.length; i++) { var zone = buildZones[i]; if (zone.zoneData.occupied) { // Occupied zones are invisible zone.alpha = 0; } else if (selectedTowerType) { // Available zones are highlighted when a tower is selected zone.alpha = 0.6; zone.tint = 0x00FF00; // Green highlight for available zones } else { // Normal state when no tower is selected zone.alpha = zone.zoneData.originalAlpha; zone.tint = 0xFFFFFF; // Reset tint } } } var castleHealthBarBg = null; var castleHealthBarFill = null; function createCastle() { var castle = isoContainer.addChild(LK.getAsset('castle_' + castleType, { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2200 })); // Create health bar background positioned under the castle (moved down) castleHealthBarBg = isoContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2350, scaleX: 4, scaleY: 0.4 })); castleHealthBarBg.tint = 0x333333; // Create health bar fill positioned under the castle (moved down) castleHealthBarFill = isoContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2350, scaleX: 4, scaleY: 0.4 })); castleHealthBarFill.tint = 0x00FF00; // Store references for updating castle.healthBarBg = castleHealthBarBg; castle.healthBarFill = castleHealthBarFill; } function createMainMenu() { mainMenuContainer = new Container(); isoContainer.addChild(mainMenuContainer); // Main menu background var menuBg = mainMenuContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 40, scaleY: 50 })); menuBg.tint = 0x000000; menuBg.alpha = 0.8; // Title var titleText = mainMenuContainer.addChild(new Text2('Tower Defense', { size: 120, fill: 0xFFD700 })); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; // New Game Button var newGameBtn = mainMenuContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1200, scaleX: 8, scaleY: 2 })); newGameBtn.tint = 0x00AA00; var newGameText = mainMenuContainer.addChild(new Text2('New Game', { size: 60, fill: 0xFFFFFF })); newGameText.anchor.set(0.5, 0.5); newGameText.x = 1024; newGameText.y = 1200; // How to Play Button var howToPlayBtn = mainMenuContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1400, scaleX: 8, scaleY: 2 })); howToPlayBtn.tint = 0x0066CC; var howToPlayText = mainMenuContainer.addChild(new Text2('How to Play', { size: 60, fill: 0xFFFFFF })); howToPlayText.anchor.set(0.5, 0.5); howToPlayText.x = 1024; howToPlayText.y = 1400; // Credits Button var creditsBtn = mainMenuContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1600, scaleX: 8, scaleY: 2 })); creditsBtn.tint = 0xAA6600; var creditsText = mainMenuContainer.addChild(new Text2('Credits', { size: 60, fill: 0xFFFFFF })); creditsText.anchor.set(0.5, 0.5); creditsText.x = 1024; creditsText.y = 1600; // Button interactions newGameBtn.down = function () { startGame(); }; howToPlayBtn.down = function () { showHowToPlay(); }; creditsBtn.down = function () { showCredits(); }; } function startGame() { if (mainMenuContainer) { mainMenuContainer.destroy(); mainMenuContainer = null; } gameState = 'playing'; createSettingsIcon(); createPath(); createTerrain(); createCastle(); createShop(); createWave(); } function showHowToPlay() { if (mainMenuContainer) { mainMenuContainer.alpha = 0.3; } howToPlayContainer = new Container(); isoContainer.addChild(howToPlayContainer); // Background var bg = howToPlayContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 35, scaleY: 45 })); bg.tint = 0x000000; bg.alpha = 0.9; // Title var title = howToPlayContainer.addChild(new Text2('How to Play', { size: 80, fill: 0xFFD700 })); title.anchor.set(0.5, 0.5); title.x = 1024; title.y = 600; // Instructions var instructions = ['Build towers to defend your castle from waves of enemies', 'Click tower icons at bottom to select, then click build zones', 'Upgrade towers by clicking them when you have enough gold', 'Different towers have different abilities:', '• Infantry: Basic damage, good range', '• Freezer: Slows enemies down', '• Air: Targets flying enemies effectively', '• Poison: Damages over time', '• Tesla: Chain lightning damage', 'Survive 100 waves to win!']; for (var i = 0; i < instructions.length; i++) { var instructText = howToPlayContainer.addChild(new Text2(instructions[i], { size: 35, fill: 0xFFFFFF })); instructText.anchor.set(0.5, 0.5); instructText.x = 1024; instructText.y = 800 + i * 60; } // Back button var backBtn = howToPlayContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2000, scaleX: 6, scaleY: 2 })); backBtn.tint = 0xAA0000; var backText = howToPlayContainer.addChild(new Text2('Back', { size: 50, fill: 0xFFFFFF })); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 2000; backBtn.down = function () { howToPlayContainer.destroy(); howToPlayContainer = null; if (mainMenuContainer) { mainMenuContainer.alpha = 1.0; } }; } function showCredits() { if (mainMenuContainer) { mainMenuContainer.alpha = 0.3; } creditsContainer = new Container(); isoContainer.addChild(creditsContainer); // Background var bg = creditsContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 25, scaleY: 30 })); bg.tint = 0x000000; bg.alpha = 0.9; // Title var title = creditsContainer.addChild(new Text2('Credits', { size: 80, fill: 0xFFD700 })); title.anchor.set(0.5, 0.5); title.x = 1024; title.y = 1000; // Credits info var gameDesignText = creditsContainer.addChild(new Text2('Game Design: ilker.mez', { size: 50, fill: 0xFFFFFF })); gameDesignText.anchor.set(0.5, 0.5); gameDesignText.x = 1024; gameDesignText.y = 1200; var aiText = creditsContainer.addChild(new Text2('AI Assistant: Grok + GPT', { size: 50, fill: 0xFFFFFF })); aiText.anchor.set(0.5, 0.5); aiText.x = 1024; aiText.y = 1300; var platformText = creditsContainer.addChild(new Text2('Platform: Built using upit.com', { size: 50, fill: 0xFFFFFF })); platformText.anchor.set(0.5, 0.5); platformText.x = 1024; platformText.y = 1400; // Back button var backBtn = creditsContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1600, scaleX: 6, scaleY: 2 })); backBtn.tint = 0xAA0000; var backText = creditsContainer.addChild(new Text2('Back', { size: 50, fill: 0xFFFFFF })); backText.anchor.set(0.5, 0.5); backText.x = 1024; backText.y = 1600; backBtn.down = function () { creditsContainer.destroy(); creditsContainer = null; if (mainMenuContainer) { mainMenuContainer.alpha = 1.0; } }; } function createSettingsIcon() { settingsIcon = LK.gui.topLeft.addChild(LK.getAsset('build_zone', { anchorX: 0, anchorY: 0, x: 20, y: 400, scaleX: 2, scaleY: 2 })); settingsIcon.tint = 0x666666; var settingsText = LK.gui.topLeft.addChild(new Text2('⚙', { size: 60, fill: 0xFFFFFF })); settingsText.anchor.set(0, 0); settingsText.x = 20; settingsText.y = 400; settingsIcon.down = function () { showSettings(); }; } function showSettings() { if (settingsContainer) return; settingsContainer = new Container(); isoContainer.addChild(settingsContainer); // Background var bg = settingsContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 20, scaleY: 25 })); bg.tint = 0x000000; bg.alpha = 0.9; // Title var title = settingsContainer.addChild(new Text2('Settings', { size: 80, fill: 0xFFD700 })); title.anchor.set(0.5, 0.5); title.x = 1024; title.y = 1000; // Return to Main Menu button var mainMenuBtn = settingsContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1200, scaleX: 10, scaleY: 2 })); mainMenuBtn.tint = 0x0066CC; var mainMenuText = settingsContainer.addChild(new Text2('Return to Main Menu', { size: 50, fill: 0xFFFFFF })); mainMenuText.anchor.set(0.5, 0.5); mainMenuText.x = 1024; mainMenuText.y = 1200; // Mute/Unmute button var muteBtn = settingsContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1400, scaleX: 8, scaleY: 2 })); muteBtn.tint = 0x00AA00; var muteText = settingsContainer.addChild(new Text2('Mute Audio', { size: 50, fill: 0xFFFFFF })); muteText.anchor.set(0.5, 0.5); muteText.x = 1024; muteText.y = 1400; // Close button var closeBtn = settingsContainer.addChild(LK.getAsset('build_zone', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1600, scaleX: 6, scaleY: 2 })); closeBtn.tint = 0xAA0000; var closeText = settingsContainer.addChild(new Text2('Close', { size: 50, fill: 0xFFFFFF })); closeText.anchor.set(0.5, 0.5); closeText.x = 1024; closeText.y = 1600; // Button interactions mainMenuBtn.down = function () { // Reset game state gameState = 'mainMenu'; // Clear all game objects for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); } enemies = []; for (var i = towers.length - 1; i >= 0; i--) { towers[i].destroy(); } towers = []; for (var i = projectiles.length - 1; i >= 0; i--) { projectiles[i].destroy(); } projectiles = []; // Reset game variables currentWave = 0; coins = 300; castleHealth = 100; waveInProgress = false; // Clear UI elements if (settingsIcon) { settingsIcon.destroy(); settingsIcon = null; } if (muteIndicator) { muteIndicator.destroy(); muteIndicator = null; } // Close settings and show main menu settingsContainer.destroy(); settingsContainer = null; createMainMenu(); }; muteBtn.down = function () { // Toggle audio mute state audioMuted = !audioMuted; // Update button text and color if (audioMuted) { muteText.setText('Unmute Audio'); muteBtn.tint = 0xAA0000; // Create mute indicator overlay on settings icon if (settingsIcon && !muteIndicator) { muteIndicator = LK.gui.topLeft.addChild(new Text2('✕', { size: 40, fill: 0xFF0000 })); muteIndicator.anchor.set(0, 0); muteIndicator.x = 30; muteIndicator.y = 410; // Animate the mute indicator tween(muteIndicator, { scaleX: 1.3, scaleY: 1.3, alpha: 0.8 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Auto-hide the X indicator after 2 seconds LK.setTimeout(function () { if (muteIndicator && audioMuted) { tween(muteIndicator, { alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { if (muteIndicator && muteIndicator.destroy) { muteIndicator.destroy(); muteIndicator = null; } } }); } }, 2000); } }); } } else { muteText.setText('Mute Audio'); muteBtn.tint = 0x00AA00; // Remove mute indicator immediately when unmuting if (muteIndicator && muteIndicator.destroy) { muteIndicator.destroy(); muteIndicator = null; } } }; closeBtn.down = function () { settingsContainer.destroy(); settingsContainer = null; }; } function createShop() { var shopBg = LK.gui.bottom.addChild(LK.getAsset('shop_bg', { anchorX: 0.5, anchorY: 1, alpha: 1.0 })); shopBg.tint = 0x000000; var infantryBtn = LK.gui.bottom.addChild(LK.getAsset('tower_infantry', { anchorX: 0.5, anchorY: 1, x: -400, y: -60 })); var frostBtn = LK.gui.bottom.addChild(LK.getAsset('tower_frost', { anchorX: 0.5, anchorY: 1, x: -200, y: -60 })); var antiairBtn = LK.gui.bottom.addChild(LK.getAsset('tower_antiair', { anchorX: 0.5, anchorY: 1, x: 0, y: -60 })); var poisonBtn = LK.gui.bottom.addChild(LK.getAsset('tower_poison', { anchorX: 0.5, anchorY: 1, x: 200, y: -60 })); var teslaBtn = LK.gui.bottom.addChild(LK.getAsset('tower_tesla', { anchorX: 0.5, anchorY: 1, x: 400, y: -60 })); // Add cost labels with larger, more distinct text var infantryCost = LK.gui.bottom.addChild(new Text2('80g', { size: 32, fill: 0xFFD700 })); infantryCost.anchor.set(0.5, 1); infantryCost.x = -400; infantryCost.y = -130; var frostCost = LK.gui.bottom.addChild(new Text2('120g', { size: 32, fill: 0xFFD700 })); frostCost.anchor.set(0.5, 1); frostCost.x = -200; frostCost.y = -130; var antiairCost = LK.gui.bottom.addChild(new Text2('150g', { size: 32, fill: 0xFFD700 })); antiairCost.anchor.set(0.5, 1); antiairCost.x = 0; antiairCost.y = -130; var poisonCost = LK.gui.bottom.addChild(new Text2('100g', { size: 32, fill: 0xFFD700 })); poisonCost.anchor.set(0.5, 1); poisonCost.x = 200; poisonCost.y = -130; var teslaCost = LK.gui.bottom.addChild(new Text2('180g', { size: 32, fill: 0xFFD700 })); teslaCost.anchor.set(0.5, 1); teslaCost.x = 400; teslaCost.y = -130; // Add tower name labels below the cost text var infantryName = LK.gui.bottom.addChild(new Text2('Infantry', { size: 28, fill: 0xFFFFFF })); infantryName.anchor.set(0.5, 1); infantryName.x = -400; infantryName.y = -160; var frostName = LK.gui.bottom.addChild(new Text2('Freezer', { size: 28, fill: 0xFFFFFF })); frostName.anchor.set(0.5, 1); frostName.x = -200; frostName.y = -160; var antiairName = LK.gui.bottom.addChild(new Text2('Air', { size: 28, fill: 0xFFFFFF })); antiairName.anchor.set(0.5, 1); antiairName.x = 0; antiairName.y = -160; var poisonName = LK.gui.bottom.addChild(new Text2('Poison', { size: 28, fill: 0xFFFFFF })); poisonName.anchor.set(0.5, 1); poisonName.x = 200; poisonName.y = -160; var teslaName = LK.gui.bottom.addChild(new Text2('Tesla', { size: 28, fill: 0xFFFFFF })); teslaName.anchor.set(0.5, 1); teslaName.x = 400; teslaName.y = -160; infantryBtn.down = function () { if (coins >= 80) { selectedTowerType = 'infantry'; updateBuildZoneVisuals(); } }; frostBtn.down = function () { if (coins >= 120) { selectedTowerType = 'frost'; updateBuildZoneVisuals(); } }; antiairBtn.down = function () { if (coins >= 150) { selectedTowerType = 'antiair'; updateBuildZoneVisuals(); } }; poisonBtn.down = function () { if (coins >= 100) { selectedTowerType = 'poison'; updateBuildZoneVisuals(); } }; teslaBtn.down = function () { if (coins >= 180) { selectedTowerType = 'tesla'; updateBuildZoneVisuals(); } }; } function createWave() { if (currentWave >= maxWaves) { LK.showYouWin(); return; } currentWave++; waveEnemies = []; // Scale enemy count based on wave number with new progression var enemyCount; if (currentWave <= 5) { // Waves 1-5: 15 to 20 enemies enemyCount = 15 + Math.floor(Math.random() * 6); } else if (currentWave <= 15) { // Waves 6-15: 20 to 25 enemies enemyCount = 20 + Math.floor(Math.random() * 6); } else if (currentWave <= 30) { // Waves 16-30: 25 to 35 enemies enemyCount = 25 + Math.floor(Math.random() * 11); } else if (currentWave <= 60) { // Waves 31-60: 35 to 45 enemies enemyCount = 35 + Math.floor(Math.random() * 11); } else if (currentWave <= 97) { // Waves 61-97: 45 to 55 enemies enemyCount = 45 + Math.floor(Math.random() * 11); } else { // Waves 98-100: 60 to 75 enemies enemyCount = 60 + Math.floor(Math.random() * 16); } // Calculate available enemy strength levels based on wave var maxStrengthLevel = Math.min(10, Math.floor((currentWave + 1) / 2)); var minStrengthLevel = Math.max(1, maxStrengthLevel - 2); for (var i = 0; i < enemyCount; i++) { // Define which enemies can appear based on wave number - introduce new enemy every 3 waves var availableEnemies = []; // Original 10 enemies if (currentWave >= 1) availableEnemies.push('goblin'); if (currentWave >= 4) availableEnemies.push('crawler'); if (currentWave >= 7) availableEnemies.push('bandit'); if (currentWave >= 10) availableEnemies.push('golem'); if (currentWave >= 13) availableEnemies.push('imp'); if (currentWave >= 16) availableEnemies.push('knight'); if (currentWave >= 19) availableEnemies.push('beast'); if (currentWave >= 22) availableEnemies.push('mage'); if (currentWave >= 25) availableEnemies.push('reaver'); if (currentWave >= 28) availableEnemies.push('doom'); // New 20 enemies - introduced every 3 waves starting from wave 31 if (currentWave >= 31) availableEnemies.push('mire_crawler'); if (currentWave >= 34) availableEnemies.push('fang_imp'); if (currentWave >= 37) availableEnemies.push('crimson_leaper'); if (currentWave >= 40) availableEnemies.push('rustback_beetle'); if (currentWave >= 43) availableEnemies.push('gravel_hound'); if (currentWave >= 46) availableEnemies.push('vine_stalker'); if (currentWave >= 49) availableEnemies.push('ashborne_wraith'); if (currentWave >= 52) availableEnemies.push('stonehide_orc'); if (currentWave >= 55) availableEnemies.push('toxic_maw'); if (currentWave >= 58) availableEnemies.push('frostback_boar'); if (currentWave >= 61) availableEnemies.push('ironmaw_troll'); if (currentWave >= 64) availableEnemies.push('volcanic_strider'); if (currentWave >= 67) availableEnemies.push('stormblade_knight'); if (currentWave >= 70) availableEnemies.push('twilight_serpent'); if (currentWave >= 73) availableEnemies.push('obsidian_colossus'); if (currentWave >= 76) availableEnemies.push('spectral_ravager'); if (currentWave >= 79) availableEnemies.push('boneclad_warbeast'); if (currentWave >= 82) availableEnemies.push('plague_titan'); if (currentWave >= 85) availableEnemies.push('abyss_reaper'); if (currentWave >= 88) availableEnemies.push('void_devourer'); // Select random enemy from available types var enemyType = availableEnemies[Math.floor(Math.random() * availableEnemies.length)]; // Assign strength level within available range var strengthLevel = minStrengthLevel + Math.floor(Math.random() * (maxStrengthLevel - minStrengthLevel + 1)); var pathChoice = 1; if (currentWave >= 6) { pathChoice = Math.floor(Math.random() * 3) + 1; } else if (currentWave >= 3) { pathChoice = Math.floor(Math.random() * 2) + 1; } waveEnemies.push({ type: enemyType, pathIndex: pathChoice, strengthLevel: strengthLevel, spawnTime: LK.ticks + i * 90 }); } waveInProgress = true; if (!audioMuted) { LK.getSound('wave_start').play(); } // Show round start announcement if (roundStartText && roundStartText.destroy) { roundStartText.destroy(); } roundStartText = new Text2('Wave ' + currentWave + ' / 100 Starting...', { size: 80, fill: 0xFFFFFF }); roundStartText.anchor.set(0.5, 0.5); roundStartText.x = 1024; roundStartText.y = 1000; isoContainer.addChild(roundStartText); // Animate the announcement text tween(roundStartText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(roundStartText, { alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { if (roundStartText && roundStartText.destroy) { roundStartText.destroy(); roundStartText = null; } } }); } }); } // Create background panel for castle lives text var castleLivesTextBg = isoContainer.addChild(LK.getAsset('build_zone', { anchorX: 0, anchorY: 0.5, x: 30, y: 1900, scaleX: 8, scaleY: 1.8 })); castleLivesTextBg.tint = 0x000000; castleLivesTextBg.alpha = 0.8; var castleLivesText = new Text2('Castle Health: 100', { size: 70, fill: 0xFF4444, font: "'Arial Black', Impact, 'Arial Bold'" }); castleLivesText.anchor.set(0, 0.5); castleLivesText.x = 50; castleLivesText.y = 1900; isoContainer.addChild(castleLivesText); // Create background panel for gold text var coinsTextBg = isoContainer.addChild(LK.getAsset('build_zone', { anchorX: 0, anchorY: 0.5, x: 30, y: 2180, scaleX: 6, scaleY: 1.8 })); coinsTextBg.tint = 0x000000; coinsTextBg.alpha = 0.8; var coinsText = new Text2('Gold: 300', { size: 70, fill: 0xFFD700, font: "'Arial Black', Impact, 'Arial Bold'" }); coinsText.anchor.set(0, 0.5); coinsText.x = 50; coinsText.y = 2180; isoContainer.addChild(coinsText); var waveText = new Text2('Wave: 0/100', { size: 40, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); LK.gui.top.addChild(waveText); var roundStartText = null; if (gameState === 'mainMenu') { createMainMenu(); } else { createPath(); createTerrain(); createCastle(); createShop(); } game.down = function (x, y, obj) { // Clear any existing upgrade text and range indicator when clicking elsewhere if (upgradeText && upgradeText.destroy && selectedTower && obj && !selectedTower.intersects(obj)) { upgradeText.destroy(); upgradeText = null; selectedTower = null; // Clear range indicator if (activeRangeIndicator && activeRangeIndicator.destroy) { activeRangeIndicator.destroy(); activeRangeIndicator = null; } } // Use screen coordinates directly for top-down view var isoPos = { x: x, y: y }; if (selectedTowerType && gameState === 'playing') { // Check if clicking on a valid, unoccupied build zone var validBuildZone = null; for (var i = 0; i < buildZones.length; i++) { if (!buildZones[i].zoneData.occupied) { var distance = Math.sqrt((buildZones[i].x - isoPos.x) * (buildZones[i].x - isoPos.x) + (buildZones[i].y - isoPos.y) * (buildZones[i].y - isoPos.y)); if (distance < 40) { validBuildZone = buildZones[i]; break; } } } // Only place tower if clicking on a valid build zone and player has enough coins if (validBuildZone) { var tower = new Tower(selectedTowerType); if (coins >= tower.cost) { // Place tower exactly at build zone center tower.x = validBuildZone.x; tower.y = validBuildZone.y; towers.push(tower); isoContainer.addChild(tower); coins -= tower.cost; coinsText.setText('Gold: ' + coins); selectedTowerType = null; // Mark build zone as occupied validBuildZone.zoneData.occupied = true; updateBuildZoneVisuals(); } } else { // Clear selection if clicking outside build zones selectedTowerType = null; updateBuildZoneVisuals(); } } }; game.update = function () { if (gameState === 'mainMenu' || gameState === 'setup') return; if (gameState !== 'playing') return; if (waveInProgress) { for (var i = waveEnemies.length - 1; i >= 0; i--) { var enemyData = waveEnemies[i]; if (LK.ticks >= enemyData.spawnTime) { var enemy = new Enemy(enemyData.type, currentWave, enemyData.pathIndex, enemyData.strengthLevel); enemies.push(enemy); isoContainer.addChild(enemy); waveEnemies.splice(i, 1); } } if (waveEnemies.length === 0 && enemies.length === 0) { waveInProgress = false; nextWaveTimer = LK.ticks + 180; } } if (!waveInProgress && LK.ticks >= nextWaveTimer && enemies.length === 0) { createWave(); } for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.reachedCastle) { castleHealth -= 15; // Update castle lives text castleLivesText.setText('Castle Health: ' + castleHealth); // Update health bar with smooth animation var healthPercent = castleHealth / 100; if (castleHealthBarFill) { // Animate health bar scale change smoothly tween(castleHealthBarFill, { scaleX: 4 * healthPercent }, { duration: 300 }); // Update color based on health percentage - green to red gradient var redComponent = Math.floor(255 * (1 - healthPercent)); var greenComponent = Math.floor(255 * healthPercent); var healthColor = redComponent << 16 | greenComponent << 8 | 0x00; castleHealthBarFill.tint = healthColor; // Flash effect when taking damage LK.effects.flashObject(castleHealthBarFill, 0xFF0000, 200); } enemy.destroy(); enemies.splice(i, 1); if (castleHealth <= 0) { LK.showGameOver(); return; } } } for (var i = projectiles.length - 1; i >= 0; i--) { var projectile = projectiles[i]; if (projectile.hasReachedTarget) { if (projectile.type === 'cannonball') { for (var j = 0; j < enemies.length; j++) { var enemy = enemies[j]; var distance = Math.sqrt((enemy.x - projectile.x) * (enemy.x - projectile.x) + (enemy.y - projectile.y) * (enemy.y - projectile.y)); if (distance <= 50) { if (enemy.takeDamage(projectile.damage)) { coins += enemy.coinValue; coinsText.setText('Gold: ' + coins); // Create death effect at enemy position tween(enemy, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 400, easing: tween.easeOut }); enemy.destroy(); enemies.splice(j, 1); j--; } } } } else { for (var j = 0; j < enemies.length; j++) { var enemy = enemies[j]; var distance = Math.sqrt((enemy.x - projectile.x) * (enemy.x - projectile.x) + (enemy.y - projectile.y) * (enemy.y - projectile.y)); if (distance <= 25) { if (enemy.takeDamage(projectile.damage)) { coins += enemy.coinValue; coinsText.setText('Gold: ' + coins); // Create death effect at enemy position tween(enemy, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 400, easing: tween.easeOut }); enemy.destroy(); enemies.splice(j, 1); } break; } } } projectile.destroy(); projectiles.splice(i, 1); } else if (projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) { projectile.destroy(); projectiles.splice(i, 1); } } waveText.setText('Wave: ' + currentWave + '/' + maxWaves); };
===================================================================
--- original.js
+++ change.js
@@ -1658,15 +1658,15 @@
buffer = buffer || 200;
// Check boundaries
if (x < 50 || x > 1998 || y < 50 || y > 2682) return false;
// Check castle area
- if (Math.sqrt((x - 1024) * (x - 1024) + (y - 2200) * (y - 2200)) < 300) return false;
+ if (Math.sqrt((x - 1024) * (x - 1024) + (y - 2200) * (y - 2200)) < 300 + buffer) return false;
// Check waterfall area
- if (x >= 1500 && x <= 1600) return false;
+ if (x >= 1500 - buffer && x <= 1600 + buffer) return false;
// Check central lake area
- if (Math.sqrt((x - 1024) * (x - 1024) + (y - 1366) * (y - 1366)) < 200) return false;
+ if (Math.sqrt((x - 1024) * (x - 1024) + (y - 1366) * (y - 1366)) < 200 + buffer) return false;
// Check original lake area
- if (Math.sqrt((x - 400) * (x - 400) + (y - 500) * (y - 500)) < 150) return false;
+ if (Math.sqrt((x - 400) * (x - 400) + (y - 500) * (y - 500)) < 150 + buffer) return false;
// Check all enemy paths with buffer
var allPaths = [enemyPath1, enemyPath2, enemyPath3];
for (var p = 0; p < allPaths.length; p++) {
var path = allPaths[p];
@@ -1675,11 +1675,11 @@
return false;
}
}
}
- // Check build zones
+ // Check build zones - now requiring 200 pixels distance
for (var i = 0; i < buildZones.length; i++) {
- if (Math.sqrt((x - buildZones[i].x) * (x - buildZones[i].x) + (y - buildZones[i].y) * (y - buildZones[i].y)) < buffer) {
+ if (Math.sqrt((x - buildZones[i].x) * (x - buildZones[i].x) + (y - buildZones[i].y) * (y - buildZones[i].y)) < 200) {
return false;
}
}
// Check village house areas
@@ -1859,37 +1859,37 @@
y: 2000
}];
// Define rock positions in empty spaces at least 200 pixels away from any object
var rockPositions = [{
- x: 500,
- y: 1100
+ x: 200,
+ y: 800
}, {
- x: 1500,
- y: 500
+ x: 1700,
+ y: 350
}, {
- x: 300,
- y: 1600
+ x: 250,
+ y: 1700
}, {
- x: 1700,
- y: 1600
+ x: 1800,
+ y: 1500
}, {
- x: 600,
- y: 400
+ x: 700,
+ y: 350
}, {
- x: 1400,
- y: 200
+ x: 1600,
+ y: 100
}, {
- x: 1800,
- y: 1100
+ x: 1900,
+ y: 950
}, {
- x: 350,
- y: 900
+ x: 150,
+ y: 1200
}, {
- x: 1550,
- y: 1400
+ x: 1700,
+ y: 1200
}, {
- x: 750,
- y: 1600
+ x: 650,
+ y: 1750
}];
// Use the first 50 fixed positions (or however many we have)
for (var i = 0; i < Math.min(50, fixedTreePositions.length); i++) {
treePositions.push(fixedTreePositions[i]);
A lake with a 3d view. In-Game asset. 2d. High contrast. No shadows
tree. In-Game asset. 2d. High contrast. No shadows
house. In-Game asset. 2d. High contrast. No shadows
magic ball. In-Game asset. 2d. High contrast. No shadows
arrow bullet. In-Game asset. 2d. High contrast. No shadows
realistic majestic castle. In-Game asset. 2d. High contrast. No shadows
dirt road. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
This is a button, the outer part is red, the middle circle is red, the 2nd circle is dark gray. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
village house. In-Game asset. 2d. High contrast. No shadows
poisonous tower realistic. In-Game asset. 2d. High contrast. No shadows
freezing tower realistic. In-Game asset. 2d. High contrast. No shadows
goblin. In-Game asset. 2d. High contrast. No shadows
goblin emperor. In-Game asset. 2d. High contrast. No shadows
haydut goblin. In-Game asset. 2d. High contrast. No shadows
titan goblin. In-Game asset. 2d. High contrast. No shadows
goblin tazısı. In-Game asset. 2d. High contrast. No shadows
gezgin goblin. In-Game asset. 2d. High contrast. No shadows
kıyamet canavarı goblin. In-Game asset. 2d. High contrast. No shadows
kemikli iskelet goblin. In-Game asset. 2d. High contrast. No shadows
buzul goblin. In-Game asset. 2d. High contrast. No shadows
golem goblin. In-Game asset. 2d. High contrast. No shadows
kadın goblin imparatoru. In-Game asset. 2d. High contrast. No shadows
demir goblin. In-Game asset. 2d. High contrast. No shadows
şövalye goblin. In-Game asset. 2d. High contrast. No shadows
obsidyen dev goblin. In-Game asset. 2d. High contrast. No shadows
üzerinde okçu olan, ahşap, okçu kulesi. In-Game asset. 2d. High contrast. No shadows
ahşap hava savunma kulesi, üstünde arbalet olsun. In-Game asset. 2d. High contrast. No shadows
antik elektrik atıcı kule. In-Game asset. 2d. High contrast. No shadows
goblin canavar. In-Game asset. 2d. High contrast. No shadows
volkanik gezgini goblin. In-Game asset. 2d. High contrast. No shadows
kahverengi gezgin eli bıçaklı goblin. In-Game asset. 2d. High contrast. No shadows
büyücü goblin. In-Game asset. 2d. High contrast. No shadows
paslı böcek goblin. In-Game asset. 2d. High contrast. No shadows
spektral yıkıcı goblin. In-Game asset. 2d. High contrast. No shadows
taş goblin. In-Game asset. 2d. High contrast. No shadows
kimyasalcı goblin, boydan. In-Game asset. 2d. High contrast. No shadows
yuvarlak havan topu mermisi. In-Game asset. 2d. High contrast. No shadows
karanlık büyücü goblin. In-Game asset. 2d. High contrast. No shadows
yeşil yapraklı dövüşçü goblin. In-Game asset. 2d. High contrast. No shadows
kayalık. In-Game asset. 2d. High contrast. No shadows
uçan küllü goblin. In-Game asset. 2d. High contrast. No shadows
uçan goblin yılan. In-Game asset. 2d. High contrast. No shadows
kırmızı kaslı uçan goblin. In-Game asset. 2d. High contrast. No shadows
uçan karanlık goblin. In-Game asset. 2d. High contrast. No shadows
uçan goblin yağmacı. In-Game asset. 2d. High contrast. No shadows
uçan fırtına golem. In-Game asset. 2d. High contrast. No shadows