User prompt
gold amount is always rounded up to an integer
User prompt
wizards always attacks the furthest enemy in enemy path, not the closest one to wizard.
User prompt
raise enemy hp increase by 5% between waves
User prompt
increase enemy health by 15%
User prompt
show level under wave
User prompt
move all assets north by 100 pixels
User prompt
all enemies moves 20% slower
User prompt
move all assets to east by 150 pixels
User prompt
move all assets south by 300 pixels
User prompt
revert back tank enemy health decrease and then decrease it by 30%
User prompt
decrease tank enemy health only by 20%
User prompt
decrease gold gain by 50%
User prompt
increase range by 15% and increase enemy health by 20%
User prompt
halve enemy health
/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var DamageDisplay = Container.expand(function (damage, x, y) { var self = Container.call(this); self.x = x; self.y = y; // Create damage text var damageText = new Text2(Math.floor(damage).toString(), { size: 90, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); damageText.anchor.set(0.5, 0.5); self.addChild(damageText); // Animate the damage display var startY = self.y; var targetY = startY - 100; // Tween upward movement and fade out tween(self, { y: targetY, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); return self; }); var Enemy = Container.expand(function (enemyType, level) { var self = Container.call(this); self.enemyType = enemyType || 'basic'; self.level = level || 1; self.pathIndex = 0; self.pathProgress = 0; self.speed = 2; switch (self.enemyType) { case 'basic': self.maxHP = (100 + level * 50) * 5 * 1.2; self.speed = 2; break; case 'fast': self.maxHP = (50 + level * 25) * 5 * 1.2; self.speed = 4; break; case 'tank': self.maxHP = (300 + level * 100) * 5 * 1.2; self.speed = 1; break; } self.hp = self.maxHP; self.goldValue = self.maxHP; self.originalSpeed = self.speed; self.isSlowed = false; self.slowEndTime = 0; self.isStunned = false; self.stunEndTime = 0; self.isKnockedBack = false; self.knockbackEndTime = 0; self.knockbackSpeed = 0; self.pathHistory = []; // Store path history for knockback self.isVulnerable = false; self.vulnerabilityEndTime = 0; self.vulnerabilityMultiplier = 1.2; // 20% additional damage self.isBurning = false; self.burnEndTime = 0; self.burnDamagePerTick = 0; self.burnTickInterval = 30; // 0.5 seconds at 60fps self.lastBurnTickTime = 0; var enemyGraphics = self.attachAsset('enemy_' + self.enemyType, { anchorX: 0.5, anchorY: 0.5 }); var hpBar = new Container(); var hpBackground = LK.getAsset('ui_background', { width: 60, height: 8, anchorX: 0.5, anchorY: 0.5 }); hpBackground.tint = 0x000000; hpBar.addChild(hpBackground); var hpFill = LK.getAsset('ui_background', { width: 60, height: 8, anchorX: 0, anchorY: 0.5 }); hpFill.tint = 0x00ff00; hpFill.x = -30; hpBar.addChild(hpFill); hpBar.y = -40; self.addChild(hpBar); self.update = function () { // Check if slow effect should end if (self.isSlowed && LK.ticks >= self.slowEndTime) { self.speed = self.originalSpeed; self.isSlowed = false; tween.stop(self, { tint: true }); self.tint = 0xFFFFFF; } // Check if stun effect should end if (self.isStunned && LK.ticks >= self.stunEndTime) { self.speed = self.originalSpeed; self.isStunned = false; tween.stop(self, { tint: true }); self.tint = 0xFFFFFF; } // Check if knockback effect should end if (self.isKnockedBack && LK.ticks >= self.knockbackEndTime) { self.speed = self.originalSpeed; self.isKnockedBack = false; self.knockbackSpeed = 0; tween.stop(self, { tint: true }); self.tint = 0xFFFFFF; } // Check if vulnerability effect should end if (self.isVulnerable && LK.ticks >= self.vulnerabilityEndTime) { self.isVulnerable = false; tween.stop(self, { tint: true }); self.tint = 0xFFFFFF; } // Check if burn effect should end if (self.isBurning && LK.ticks >= self.burnEndTime) { self.isBurning = false; self.burnDamagePerTick = 0; tween.stop(self, { tint: true }); self.tint = 0xFFFFFF; } // Process burn damage over time if (self.isBurning && LK.ticks - self.lastBurnTickTime >= self.burnTickInterval) { self.hp -= self.burnDamagePerTick; self.lastBurnTickTime = LK.ticks; // Create damage display for burn damage var damageDisplay = new DamageDisplay(self.burnDamagePerTick, self.x, self.y - 30); damageDisplays.push(damageDisplay); game.addChild(damageDisplay); if (self.hp <= 0) { self.die(); } } if (currentPath && currentPath.length > 0) { self.followPath(); } // Update HP bar var hpPercent = self.hp / self.maxHP; hpFill.width = 60 * hpPercent; hpFill.tint = hpPercent > 0.5 ? 0x00ff00 : hpPercent > 0.25 ? 0xffff00 : 0xff0000; }; self.followPath = function () { if (self.pathIndex >= currentPath.length) { self.reachBase(); return; } // Handle knockback movement if (self.isKnockedBack) { // Move backwards along the path history if (self.pathHistory.length > 0) { var lastPosition = self.pathHistory[self.pathHistory.length - 1]; var dx = lastPosition.x - self.x; var dy = lastPosition.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 2) { self.x += dx / distance * self.knockbackSpeed; self.y += dy / distance * self.knockbackSpeed; } else { // Remove the reached position from history self.pathHistory.pop(); } } return; } var targetPoint = currentPath[self.pathIndex]; var dx = targetPoint.x - self.x; var dy = targetPoint.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 5) { self.pathIndex++; return; } // Store current position in path history before moving self.pathHistory.push({ x: self.x, y: self.y }); // Limit history size to prevent memory issues if (self.pathHistory.length > 100) { self.pathHistory.shift(); } self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; }; self.takeDamage = function (damage) { var finalDamage = damage; if (self.isVulnerable) { finalDamage = damage * self.vulnerabilityMultiplier; } // Create damage display var damageDisplay = new DamageDisplay(finalDamage, self.x, self.y - 30); damageDisplays.push(damageDisplay); game.addChild(damageDisplay); self.hp -= finalDamage; LK.getSound('enemyHit').play(); if (self.hp <= 0) { self.die(); } }; self.die = function () { LK.getSound('enemyDeath').play(); for (var i = 0; i < enemies.length; i++) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } gold += self.goldValue / 20; updateGoldDisplay(); self.destroy(); gold += self.goldValue / 20; updateGoldDisplay(); }; self.applySlow = function () { if (!self.isSlowed) { self.speed = self.originalSpeed * 0.5; // 50% speed reduction self.isSlowed = true; self.slowEndTime = LK.ticks + 180; // 3 seconds at 60fps // Apply blue tint to indicate slow effect tween(self, { tint: 0x88CCFF }, { duration: 500 }); } else { // Refresh slow duration if already slowed self.slowEndTime = LK.ticks + 180; } }; self.applyStun = function () { if (!self.isStunned) { self.speed = 0; // Cannot move when stunned self.isStunned = true; self.stunEndTime = LK.ticks + 60; // 1 second at 60fps // Apply yellow tint to indicate stun effect tween(self, { tint: 0xFFFF00 }, { duration: 500 }); } else { // Refresh stun duration if already stunned self.stunEndTime = LK.ticks + 60; } }; self.applyKnockback = function () { if (!self.isKnockedBack) { self.knockbackSpeed = 3; // Speed for moving backwards self.isKnockedBack = true; self.knockbackEndTime = LK.ticks + 60; // 1 second at 60fps // Apply purple tint to indicate knockback effect tween(self, { tint: 0xFF00FF }, { duration: 300 }); } else { // Refresh knockback duration if already knocked back self.knockbackEndTime = LK.ticks + 60; } }; self.applyVulnerability = function () { if (!self.isVulnerable) { self.isVulnerable = true; self.vulnerabilityEndTime = LK.ticks + 300; // 5 seconds at 60fps // Apply green tint to indicate vulnerability effect tween(self, { tint: 0x00FF88 }, { duration: 500 }); } else { // Refresh vulnerability duration if already vulnerable self.vulnerabilityEndTime = LK.ticks + 300; } }; self.applyBurn = function (projectileDamage) { if (!self.isBurning) { self.isBurning = true; self.burnEndTime = LK.ticks + 300; // 5 seconds at 60fps self.burnDamagePerTick = projectileDamage * 0.5 / 10; // 50% of projectile damage over 10 ticks (5 seconds) self.lastBurnTickTime = LK.ticks; // Apply orange tint to indicate burn effect tween(self, { tint: 0xFF4400 }, { duration: 500 }); } else { // Refresh burn duration and recalculate damage if new burn is stronger var newBurnDamage = projectileDamage * 0.5 / 10; if (newBurnDamage > self.burnDamagePerTick) { self.burnDamagePerTick = newBurnDamage; } self.burnEndTime = LK.ticks + 300; } }; self.reachBase = function () { baseHP -= self.hp; updateBaseHPDisplay(); if (baseHP <= 0) { LK.showGameOver(); } for (var i = 0; i < enemies.length; i++) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); }; return self; }); var Projectile = Container.expand(function (startX, startY, target, damage, wizardType) { var self = Container.call(this); self.x = startX; self.y = startY; self.target = target; self.damage = damage; self.speed = 8; self.wizardType = wizardType || 'fire'; var projectileGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (!self.target || self.target.destroyed) { self.destroy(); return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { // Calculate actual damage taken (considering vulnerability) var actualDamage = self.damage; if (self.target.isVulnerable) { actualDamage = self.damage * self.target.vulnerabilityMultiplier; } self.target.takeDamage(self.damage); // Apply slow effect if ice wizard projectile if (self.wizardType === 'ice') { self.target.applySlow(); } // Apply stun effect if light wizard projectile if (self.wizardType === 'light') { self.target.applyStun(); } // Apply knockback effect if dark wizard projectile if (self.wizardType === 'dark') { self.target.applyKnockback(); } // Apply vulnerability effect if nature wizard projectile if (self.wizardType === 'nature') { self.target.applyVulnerability(); } // Apply burn effect if fire wizard projectile if (self.wizardType === 'fire') { self.target.applyBurn(self.damage); } self.destroy(); return; } self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; }; return self; }); var TowerSlot = Container.expand(function (x, y, towerNumber) { var self = Container.call(this); self.x = x; self.y = y; self.isEmpty = true; self.wizard = null; self.towerNumber = towerNumber; var slotGraphics = self.attachAsset('tower_slot', { anchorX: 0.5, anchorY: 0.5 }); var towerNumberText = new Text2(self.towerNumber.toString(), { size: 20, fill: 0xFFFFFF }); towerNumberText.anchor.set(0.5, 0.5); towerNumberText.y = 0; self.addChild(towerNumberText); self.down = function (x, y, obj) { if (self.isEmpty && (gameState === 'setup' || gameState === 'playing')) { selectedTowerSlot = self; gameState = 'wizard_selection'; createWizardSelectionPopup(); } else if (!self.isEmpty && self.wizard && (gameState === 'setup' || gameState === 'playing')) { // Upgrade existing wizard selectedTowerSlot = self; gameState = 'wizard_upgrade'; createWizardUpgradePopup(); } }; self.placeWizard = function (wizardType) { var cost = 500; if (gold >= cost) { gold -= cost; updateGoldDisplay(); self.wizard = new Wizard(wizardType, 1); self.wizard.x = self.x; self.wizard.y = self.y; self.isEmpty = false; game.addChild(self.wizard); wizards.push(self.wizard); draggedWizard = null; } }; return self; }); var Wizard = Container.expand(function (elementType, level) { var self = Container.call(this); self.elementType = elementType || 'fire'; self.level = level || 1; self.elementalDamage = 100 * self.level; self.magicDamage = 100 * self.level; self.range = (150 + self.level * 20) * 1.15 * 1.15; self.attackSpeed = (1000 - self.level * 50) * 0.9; // ms between attacks - 10% faster self.lastAttackTime = 0; self.cost = 500 * Math.pow(1.8, self.level - 1); var wizardGraphics = self.attachAsset('wizard_' + self.elementType, { anchorX: 0.5, anchorY: 0.5 }); var levelText = new Text2(self.level.toString(), { size: 24, fill: 0x000000, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); levelText.anchor.set(0.5, 0.5); levelText.y = -50; self.addChild(levelText); self.update = function () { if (LK.ticks - self.lastAttackTime > self.attackSpeed / 16.67) { var target = self.findTarget(); if (target) { self.attack(target); self.lastAttackTime = LK.ticks; } } }; 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(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.attack = function (target) { var projectile = new Projectile(self.x, self.y, target, self.elementalDamage + self.magicDamage, self.elementType); projectiles.push(projectile); game.addChild(projectile); LK.getSound('shoot').play(); }; return self; }); var WizardIcon = Container.expand(function (elementType) { var self = Container.call(this); self.elementType = elementType; var iconGraphics = self.attachAsset('wizard_' + elementType, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); var costText = new Text2('500', { size: 20, fill: 0xFFFFFF }); costText.anchor.set(0.5, 0); costText.y = 45; self.addChild(costText); self.down = function (x, y, obj) { // Wizard icons are now handled by tower slots }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x228B22 }); /**** * Game Code ****/ // Add cobblestone background var cobblestoneBackground = game.addChild(LK.getAsset('cobblestone_bg', { anchorX: 0, anchorY: 0 })); cobblestoneBackground.x = 0; cobblestoneBackground.y = 0; // Game state variables var currentLevel = 1; var currentWave = 1; var maxWaves = 10; var gold = 1000; var baseHP = 10000; var gameState = 'setup'; // 'setup', 'playing', 'paused', 'between_waves', 'wizard_selection' var waveSpawnTimer = 0; var enemiesSpawnedThisWave = 0; var enemiesPerWave = 10; var draggedWizard = null; var gameStarted = false; var waveStartTime = 0; var lastWaveEndTime = 0; var lastEnemySpawnTime = 0; var selectedTowerSlot = null; var wizardSelectionPopup = null; var waveInProgress = false; var allEnemiesEnteredMaze = false; var lastEnemyEnteredTime = 0; var enemySpawnDelay = 60; // 1 second at 60fps var lastSpawnTime = 0; var currentWaveEnemyType; // Game object arrays var enemies = []; var wizards = []; var projectiles = []; var towerSlots = []; var wizardIcons = []; var damageDisplays = []; // Path system var currentPath = []; var pathPoints = [{ x: 50, y: 350 }, { x: 200, y: 350 }, { x: 200, y: 500 }, { x: 350, y: 500 }, { x: 350, y: 650 }, { x: 150, y: 650 }, { x: 150, y: 800 }, { x: 450, y: 800 }, { x: 450, y: 950 }, { x: 650, y: 950 }, { x: 650, y: 750 }, { x: 800, y: 750 }, { x: 800, y: 1100 }, { x: 550, y: 1100 }, { x: 550, y: 1250 }, { x: 900, y: 1250 }, { x: 900, y: 1400 }, { x: 700, y: 1400 }, { x: 700, y: 1550 }, { x: 1050, y: 1550 }, { x: 1050, y: 1200 }, { x: 1200, y: 1200 }, { x: 1200, y: 1700 }, { x: 1000, y: 1700 }, { x: 1000, y: 1850 }, { x: 1350, y: 1850 }, { x: 1350, y: 1500 }, { x: 1500, y: 1500 }, { x: 1500, y: 2000 }, { x: 1700, y: 2000 }]; // UI elements - Create scoreboard container without background var scoreboardContainer = new Container(); var goldText = new Text2('Gold: ' + gold, { size: 60, fill: 0x000000, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); goldText.anchor.set(1, 0); goldText.x = 2048 - 40; // 40px from right edge goldText.y = 40; scoreboardContainer.addChild(goldText); var baseHPText = new Text2('Base HP: ' + baseHP, { size: 60, fill: 0x000000, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); baseHPText.anchor.set(1, 0); baseHPText.x = 2048 - 40; // 40px from right edge baseHPText.y = 110; scoreboardContainer.addChild(baseHPText); var waveText = new Text2('Wave: ' + currentWave + '/' + maxWaves, { size: 60, fill: 0x000000, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); waveText.anchor.set(1, 0); waveText.x = 2048 - 40; // 40px from right edge waveText.y = 180; scoreboardContainer.addChild(waveText); game.addChild(scoreboardContainer); // Initialize path currentPath = pathPoints; // Create continuous road path between waypoints for (var i = 0; i < currentPath.length - 1; i++) { var startPoint = currentPath[i]; var endPoint = currentPath[i + 1]; // Calculate distance and direction between points var dx = endPoint.x - startPoint.x; var dy = endPoint.y - startPoint.y; var distance = Math.sqrt(dx * dx + dy * dy); var steps = Math.ceil(distance / 50); // Place road tiles every 50 pixels // Create road tiles along the path for (var j = 0; j <= steps; j++) { var progress = j / steps; var roadX = startPoint.x + dx * progress; var roadY = startPoint.y + dy * progress; var roadTile = game.addChild(LK.getAsset('road_tile', { anchorX: 0.5, anchorY: 0.5 })); roadTile.x = roadX; roadTile.y = roadY; roadTile.tint = 0x444444; // Darker road color } } // Create home base var homeBase = game.addChild(LK.getAsset('home_base', { anchorX: 0.5, anchorY: 0.5 })); homeBase.x = currentPath[currentPath.length - 1].x; homeBase.y = currentPath[currentPath.length - 1].y; // Create tower slots - positioned outside enemy path but within level 1 wizard range (170px) of enemy path var towerPositions = [{ x: 270, y: 285 }, { x: 430, y: 440 }, { x: 70, y: 730 }, { x: 520, y: 730 }, { x: 780, y: 1475 }, { x: 390, y: 1025 }, { x: 720, y: 1005 }, { x: 1125, y: 1110 }, { x: 750, y: 1175 }, { x: 1125, y: 1380 }, { x: 1110, y: 1775 }, { x: 1425, y: 1590 }]; for (var i = 0; i < towerPositions.length; i++) { var slot = new TowerSlot(towerPositions[i].x, towerPositions[i].y, i + 1); towerSlots.push(slot); game.addChild(slot); } // Create UI bottom panel var uiPanel = game.addChild(LK.getAsset('ui_background', { anchorX: 0, anchorY: 1 })); uiPanel.x = 0; uiPanel.y = 2732; // Create start wave button var startWaveButton = LK.getAsset('ui_background', { width: 200, height: 60, anchorX: 0.5, anchorY: 0.5 }); startWaveButton.tint = 0x00AA00; startWaveButton.x = 1024; startWaveButton.y = 200; var startWaveText = new Text2('Start Game', { size: 30, fill: 0xFFFFFF }); startWaveText.anchor.set(0.5, 0.5); startWaveButton.addChild(startWaveText); startWaveButton.visible = true; game.addChild(startWaveButton); // Wizard icons removed - now handled by tower slot clicks // Add click handlers startWaveButton.down = function () { if (gameState === 'menu' || gameState === 'setup') { gameState = 'playing'; startWaveButton.visible = false; gameStarted = true; // Calculate max waves based on level var wavesPerLevel = [7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35]; maxWaves = wavesPerLevel[currentLevel - 1] || 10; enemiesPerWave = getEnemiesPerWave(); updateWaveDisplay(); // Start first wave automatically waveInProgress = true; allEnemiesEnteredMaze = false; lastSpawnTime = 0; } }; // Create wizard selection popup function createWizardSelectionPopup() { wizardSelectionPopup = new Container(); // Background - make it larger to accommodate level selection var popupBg = LK.getAsset('ui_background', { width: 2000, height: 1600, anchorX: 0.5, anchorY: 0.5 }); popupBg.tint = 0x222222; popupBg.x = 1024; popupBg.y = 1366; wizardSelectionPopup.addChild(popupBg); // Title var titleText = new Text2('Select Wizard & Level', { size: 50, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1050; wizardSelectionPopup.addChild(titleText); // Add selected wizard type and level tracking wizardSelectionPopup.selectedWizardType = 'fire'; wizardSelectionPopup.selectedLevel = 1; // Wizard type buttons var wizardTypes = ['fire', 'ice', 'nature', 'dark', 'light']; var wizardNames = ['Fire Wizard', 'Ice Wizard', 'Nature Wizard', 'Dark Wizard', 'Light Wizard']; var wizardTypeButtons = []; for (var i = 0; i < wizardTypes.length; i++) { var wizardBtn = LK.getAsset('wizard_' + wizardTypes[i], { anchorX: 0.5, anchorY: 0.5 }); wizardBtn.x = 824; // Move wizard icon to left wizardBtn.y = 1150 + i * 120; // Arrange vertically from top to bottom wizardBtn.wizardType = wizardTypes[i]; wizardBtn.alpha = wizardTypes[i] === 'fire' ? 1.0 : 0.6; // Highlight selected // Add wizard name text var nameText = new Text2(wizardNames[i], { size: 40, fill: 0xFFFFFF }); nameText.anchor.set(0, 0.5); nameText.x = 924; // Position to right of wizard icon nameText.y = 1130 + i * 120; wizardSelectionPopup.addChild(nameText); // Add cost text var wizardCostText = new Text2('Cost: 500', { size: 32, fill: 0xFFFF00 }); wizardCostText.anchor.set(0, 0.5); wizardCostText.x = 924; wizardCostText.y = 1160 + i * 120; wizardSelectionPopup.addChild(wizardCostText); // Add level text var wizardLevelText = new Text2('Level: 1', { size: 32, fill: 0x00FF00 }); wizardLevelText.anchor.set(0, 0.5); wizardLevelText.x = 924; wizardLevelText.y = 1190 + i * 120; wizardSelectionPopup.addChild(wizardLevelText); // Add elemental damage text var elementNames = { 'fire': 'Fire', 'ice': 'Ice', 'nature': 'Nature', 'dark': 'Dark', 'light': 'Light' }; var wizardDamageText = new Text2(elementNames[wizardTypes[i]] + ': 100', { size: 32, fill: 0xFF6600 }); wizardDamageText.anchor.set(0, 0.5); wizardDamageText.x = 1224; wizardDamageText.y = 1160 + i * 120; wizardSelectionPopup.addChild(wizardDamageText); // Add magic damage text var wizardMagicDamageText = new Text2('Magic: 100', { size: 32, fill: 0x9966FF }); wizardMagicDamageText.anchor.set(0, 0.5); wizardMagicDamageText.x = 1224; wizardMagicDamageText.y = 1190 + i * 120; wizardSelectionPopup.addChild(wizardMagicDamageText); // Store references to text elements for updates wizardBtn.nameText = nameText; wizardBtn.costText = wizardCostText; wizardBtn.levelText = wizardLevelText; wizardBtn.damageText = wizardDamageText; wizardBtn.magicDamageText = wizardMagicDamageText; wizardBtn.down = function () { // Update selected wizard type wizardSelectionPopup.selectedWizardType = this.wizardType; // Update button highlighting for (var j = 0; j < wizardTypeButtons.length; j++) { wizardTypeButtons[j].alpha = wizardTypeButtons[j].wizardType === this.wizardType ? 1.0 : 0.6; } // Update cost display updateCostDisplay(); // Update individual wizard info updateWizardInfo(); }; wizardSelectionPopup.addChild(wizardBtn); wizardTypeButtons.push(wizardBtn); } // Level selection section var levelTitleText = new Text2('Level:', { size: 40, fill: 0xFFFFFF }); levelTitleText.anchor.set(0.5, 0.5); levelTitleText.x = 1024; levelTitleText.y = 1770; wizardSelectionPopup.addChild(levelTitleText); // Level buttons (1-10) var levelButtons = []; for (var i = 1; i <= 10; i++) { var levelBtn = LK.getAsset('ui_background', { width: 80, height: 60, anchorX: 0.5, anchorY: 0.5 }); levelBtn.tint = i === 1 ? 0x00AA00 : 0x666666; // Highlight level 1 levelBtn.x = 400 + (i - 1) * 80; levelBtn.y = 1850; levelBtn.level = i; // Add level number text var levelNumText = new Text2(i.toString(), { size: 30, fill: 0xFFFFFF }); levelNumText.anchor.set(0.5, 0.5); levelBtn.addChild(levelNumText); levelBtn.down = function () { // Update selected level wizardSelectionPopup.selectedLevel = this.level; // Update button highlighting for (var j = 0; j < levelButtons.length; j++) { levelButtons[j].tint = levelButtons[j].level === this.level ? 0x00AA00 : 0x666666; } // Update cost display updateCostDisplay(); // Update individual wizard info updateWizardInfo(); }; wizardSelectionPopup.addChild(levelBtn); levelButtons.push(levelBtn); } // Cost display var costText = new Text2('Cost: 500', { size: 35, fill: 0xFFFF00 }); costText.anchor.set(0.5, 0.5); costText.x = 1024; costText.y = 1930; wizardSelectionPopup.addChild(costText); // Function to update cost display function updateCostDisplay() { var cost = 500 * Math.pow(1.8, wizardSelectionPopup.selectedLevel - 1); costText.setText('Cost: ' + Math.floor(cost)); costText.tint = gold >= cost ? 0xFFFF00 : 0xFF0000; // Yellow if affordable, red if not } // Function to update wizard info display function updateWizardInfo() { var cost = 500 * Math.pow(1.8, wizardSelectionPopup.selectedLevel - 1); var elementalDamage = 100 * wizardSelectionPopup.selectedLevel; var magicDamage = 100 * wizardSelectionPopup.selectedLevel; var elementNames = { 'fire': 'Fire', 'ice': 'Ice', 'nature': 'Nature', 'dark': 'Dark', 'light': 'Light' }; for (var i = 0; i < wizardTypeButtons.length; i++) { var btn = wizardTypeButtons[i]; btn.costText.setText('Cost: ' + Math.floor(cost)); btn.costText.tint = gold >= cost ? 0xFFFF00 : 0xFF0000; btn.levelText.setText('Level: ' + wizardSelectionPopup.selectedLevel); btn.damageText.setText(elementNames[btn.wizardType] + ': ' + elementalDamage); btn.magicDamageText.setText('Magic: ' + magicDamage); } } // Hire button var hireBtn = LK.getAsset('ui_background', { width: 200, height: 60, anchorX: 0.5, anchorY: 0.5 }); hireBtn.tint = 0x00AA00; hireBtn.x = 924; hireBtn.y = 2000; var hireText = new Text2('Hire', { size: 30, fill: 0xFFFFFF }); hireText.anchor.set(0.5, 0.5); hireBtn.addChild(hireText); hireBtn.down = function () { placeWizardOnSelectedSlot(wizardSelectionPopup.selectedWizardType, wizardSelectionPopup.selectedLevel); }; wizardSelectionPopup.addChild(hireBtn); // Close button var closeBtn = LK.getAsset('ui_background', { width: 100, height: 50, anchorX: 0.5, anchorY: 0.5 }); closeBtn.tint = 0xff0000; closeBtn.x = 1400; closeBtn.y = 1050; var closeText = new Text2('X', { size: 30, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeBtn.addChild(closeText); closeBtn.down = function () { closeWizardSelectionPopup(); }; wizardSelectionPopup.addChild(closeBtn); game.addChild(wizardSelectionPopup); } function closeWizardSelectionPopup() { if (wizardSelectionPopup) { wizardSelectionPopup.destroy(); wizardSelectionPopup = null; selectedTowerSlot = null; gameState = gameStarted ? 'playing' : 'setup'; } } function createWizardUpgradePopup() { var wizard = selectedTowerSlot.wizard; var upgradePopup = new Container(); // Background var popupBg = LK.getAsset('ui_background', { width: 1000, height: 800, anchorX: 0.5, anchorY: 0.5 }); popupBg.tint = 0x222222; popupBg.x = 1024; popupBg.y = 1366; upgradePopup.addChild(popupBg); // Title var titleText = new Text2('Upgrade Wizard', { size: 50, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1100; upgradePopup.addChild(titleText); // Current wizard info var currentInfoText = new Text2('Current Level: ' + wizard.level, { size: 35, fill: 0xFFFFFF }); currentInfoText.anchor.set(0.5, 0.5); currentInfoText.x = 1024; currentInfoText.y = 1200; upgradePopup.addChild(currentInfoText); var elementNames = { 'fire': 'Fire', 'ice': 'Ice', 'nature': 'Nature', 'dark': 'Dark', 'light': 'Light' }; var currentDamageText = new Text2(elementNames[wizard.elementType] + ': ' + wizard.elementalDamage + ' | Magic: ' + wizard.magicDamage, { size: 30, fill: 0x00FF00 }); currentDamageText.anchor.set(0.5, 0.5); currentDamageText.x = 1024; currentDamageText.y = 1250; upgradePopup.addChild(currentDamageText); // Upgrade info (if not max level) if (wizard.level < 10) { var upgradeCost = Math.floor(500 * Math.pow(1.8, wizard.level) * 0.6); var newElementalDamage = 100 * (wizard.level + 1); var newMagicDamage = 100 * (wizard.level + 1); var upgradeInfoText = new Text2('Upgrade to Level ' + (wizard.level + 1), { size: 35, fill: 0xFFFF00 }); upgradeInfoText.anchor.set(0.5, 0.5); upgradeInfoText.x = 1024; upgradeInfoText.y = 1350; upgradePopup.addChild(upgradeInfoText); var upgradeDamageText = new Text2(elementNames[wizard.elementType] + ': ' + newElementalDamage + ' | Magic: ' + newMagicDamage, { size: 30, fill: 0x00FF00 }); upgradeDamageText.anchor.set(0.5, 0.5); upgradeDamageText.x = 1024; upgradeDamageText.y = 1400; upgradePopup.addChild(upgradeDamageText); var costText = new Text2('Cost: ' + upgradeCost, { size: 35, fill: gold >= upgradeCost ? 0xFFFF00 : 0xFF0000 }); costText.anchor.set(0.5, 0.5); costText.x = 1024; costText.y = 1450; upgradePopup.addChild(costText); // Upgrade button var upgradeBtn = LK.getAsset('ui_background', { width: 200, height: 60, anchorX: 0.5, anchorY: 0.5 }); upgradeBtn.tint = gold >= upgradeCost ? 0x00AA00 : 0x666666; upgradeBtn.x = 924; upgradeBtn.y = 1550; var upgradeText = new Text2('Upgrade', { size: 30, fill: 0xFFFFFF }); upgradeText.anchor.set(0.5, 0.5); upgradeBtn.addChild(upgradeText); upgradeBtn.down = function () { if (gold >= upgradeCost) { upgradeWizard(wizard, upgradeCost); upgradePopup.destroy(); selectedTowerSlot = null; gameState = gameStarted ? 'playing' : 'setup'; } }; upgradePopup.addChild(upgradeBtn); } else { // Max level reached var maxLevelText = new Text2('Maximum Level Reached!', { size: 40, fill: 0xFF6600 }); maxLevelText.anchor.set(0.5, 0.5); maxLevelText.x = 1024; maxLevelText.y = 1400; upgradePopup.addChild(maxLevelText); } // Close button var closeBtn = LK.getAsset('ui_background', { width: 100, height: 50, anchorX: 0.5, anchorY: 0.5 }); closeBtn.tint = 0xff0000; closeBtn.x = 1124; closeBtn.y = 1550; var closeText = new Text2('X', { size: 30, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeBtn.addChild(closeText); closeBtn.down = function () { upgradePopup.destroy(); selectedTowerSlot = null; gameState = gameStarted ? 'playing' : 'setup'; }; upgradePopup.addChild(closeBtn); game.addChild(upgradePopup); } function upgradeWizard(wizard, cost) { gold -= cost; updateGoldDisplay(); // Upgrade wizard stats wizard.level++; wizard.elementalDamage = 100 * wizard.level; wizard.magicDamage = 100 * wizard.level; wizard.range = (150 + wizard.level * 20) * 1.15 * 1.15; wizard.attackSpeed = (1000 - wizard.level * 50) * 0.9; wizard.cost = 500 * Math.pow(1.8, wizard.level - 1); // Update level display on wizard var levelText = wizard.children.find(function (child) { return child instanceof Text2; }); if (levelText) { levelText.setText(wizard.level.toString()); } // Update range circle if it exists if (wizard.rangeCircle) { wizard.rangeCircle.scaleX = wizard.range / 45; wizard.rangeCircle.scaleY = wizard.range / 45; } } function placeWizardOnSelectedSlot(wizardType, level) { if (selectedTowerSlot && selectedTowerSlot.isEmpty) { var cost = 500 * Math.pow(1.8, level - 1); if (gold >= cost) { gold -= cost; updateGoldDisplay(); var wizard = new Wizard(wizardType, level); wizard.x = selectedTowerSlot.x; wizard.y = selectedTowerSlot.y; selectedTowerSlot.wizard = wizard; selectedTowerSlot.isEmpty = false; // Add range visualization var rangeCircle = LK.getAsset('tower_slot', { anchorX: 0.5, anchorY: 0.5, scaleX: wizard.range / 45, scaleY: wizard.range / 45 }); rangeCircle.tint = 0x00ff00; rangeCircle.alpha = 0.2; rangeCircle.x = wizard.x; rangeCircle.y = wizard.y; game.addChild(rangeCircle); wizard.rangeCircle = rangeCircle; game.addChild(wizard); wizards.push(wizard); closeWizardSelectionPopup(); } } } // Helper functions function updateGoldDisplay() { goldText.setText('Gold: ' + gold); } function updateBaseHPDisplay() { baseHPText.setText('Base HP: ' + baseHP); } function updateWaveDisplay() { waveText.setText('Wave: ' + currentWave + '/' + maxWaves); } function spawnEnemy() { // Determine enemy type for this wave - same type for all enemies in wave if (currentWaveEnemyType === undefined) { var rand = Math.random(); if (rand < 0.6) currentWaveEnemyType = 'basic';else if (rand < 0.85) currentWaveEnemyType = 'fast';else currentWaveEnemyType = 'tank'; } var enemy = new Enemy(currentWaveEnemyType, currentLevel); enemy.x = currentPath[0].x; enemy.y = currentPath[0].y; enemies.push(enemy); game.addChild(enemy); } function getEnemiesPerWave() { var min, max; if (currentLevel >= 1 && currentLevel <= 5) { min = 10; max = 20; } else if (currentLevel >= 6 && currentLevel <= 10) { min = 15; max = 25; } else if (currentLevel >= 11 && currentLevel <= 15) { min = 20; max = 35; } else if (currentLevel >= 16 && currentLevel <= 20) { min = 35; max = 50; } else { min = 50; max = 70; } return Math.floor(Math.random() * (max - min + 1)) + min; } function startNextWave() { currentWave++; enemiesSpawnedThisWave = 0; enemiesPerWave = getEnemiesPerWave(); lastWaveEndTime = LK.ticks; gameState = 'playing'; currentWaveEnemyType = undefined; // Reset enemy type for new wave updateWaveDisplay(); } // Game update loop game.update = function () { // Only update game logic if not in setup or wizard selection if (gameState === 'setup' || gameState === 'wizard_selection' || gameState === 'wizard_upgrade') { return; } // Spawn enemies with proper timing if (gameState === 'playing' && waveInProgress && enemiesSpawnedThisWave < enemiesPerWave) { // Only spawn if enough time has passed since last spawn if (LK.ticks - lastSpawnTime >= enemySpawnDelay) { spawnEnemy(); enemiesSpawnedThisWave++; lastSpawnTime = LK.ticks; // Check if all enemies have been spawned for this wave if (enemiesSpawnedThisWave >= enemiesPerWave) { allEnemiesEnteredMaze = true; lastEnemyEnteredTime = LK.ticks; } } } // Check if wave is complete - all enemies spawned and all enemies cleared if (waveInProgress && allEnemiesEnteredMaze && enemies.length === 0) { // Wait 5 seconds after last enemy entered before allowing next wave if (LK.ticks - lastEnemyEnteredTime >= 300) { // 5 seconds at 60fps waveInProgress = false; allEnemiesEnteredMaze = false; enemiesSpawnedThisWave = 0; gameState = 'between_waves'; lastWaveEndTime = LK.ticks; waveStartTime = 0; if (currentWave < maxWaves) { // Automatically start next wave after 5 seconds startNextWave(); waveInProgress = true; allEnemiesEnteredMaze = false; lastSpawnTime = 0; } else { // Level complete currentLevel++; currentWave = 0; // Will be incremented in startNextWave var wavesPerLevel = [7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35]; maxWaves = wavesPerLevel[currentLevel - 1] || 10; enemiesPerWave = getEnemiesPerWave(); if (currentLevel > 20) { LK.showYouWin(); return; } // Automatically start next level startNextWave(); waveInProgress = true; allEnemiesEnteredMaze = false; lastSpawnTime = 0; } } } // Update projectiles for (var i = projectiles.length - 1; i >= 0; i--) { var projectile = projectiles[i]; if (projectile.destroyed) { projectiles.splice(i, 1); } } // Clean up destroyed enemies for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i].destroyed) { enemies.splice(i, 1); } } // Clean up destroyed wizards for (var i = wizards.length - 1; i >= 0; i--) { if (wizards[i].destroyed) { wizards.splice(i, 1); } } // Clean up destroyed damage displays for (var i = damageDisplays.length - 1; i >= 0; i--) { if (damageDisplays[i].destroyed) { damageDisplays.splice(i, 1); } } };
===================================================================
--- original.js
+++ change.js
@@ -230,12 +230,12 @@
enemies.splice(i, 1);
break;
}
}
- gold += self.goldValue / 10;
+ gold += self.goldValue / 20;
updateGoldDisplay();
self.destroy();
- gold += self.goldValue / 10;
+ gold += self.goldValue / 20;
updateGoldDisplay();
};
self.applySlow = function () {
if (!self.isSlowed) {
Fort to defend. In-Game asset. 2d. High contrast. No shadows
bulky warrior like a tank. In-Game asset. 2d. High contrast. No shadows
fast and slim warrior to represent speed. In-Game asset. 2d. High contrast. No shadows
in game asset, colored, 2d warrior, face covered with helmet
dark wizard 2d in game asset. In-Game asset. 2d. High contrast. No shadows
mostly transparent grey circle. In-Game asset. 2d. High contrast. No shadows
top view, stone high tower.. In-Game asset. 2d. High contrast. No shadows
a fire wizard. In-Game asset. 2d. High contrast. No shadows
cornerstone 2d in game asset from top view
2d in game asset ice wizard. In-Game asset. 2d. High contrast. No shadows
2d in game asset nature (green) wizard.
2d in game asset light (yellow) wizard.
magic bolt traveling in air
2d, top view, very light grey, very very very small tiled (at least 1000 tiles), cobblestone road texture