Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Remix started
Copy Tower Defense Template
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ /**** * Classes ****/ var Bullet = Container.expand(function (startX, startY, targetEnemy, damage, speed) { var self = Container.call(this); self.targetEnemy = targetEnemy; self.damage = damage || 10; self.speed = speed || 5; self.x = startX; self.y = startY; self.isCatalyzed = false; // Nowa właściwość var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { if (!self.targetEnemy || !self.targetEnemy.parent) { self.destroy(); return; } var dx = self.targetEnemy.x - self.x; var dy = self.targetEnemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.speed) { self.targetEnemy.health -= self.damage; // ... (logika paska życia) // --- LOGIKA EFEKTU "CATALYST" --- if (self.type === 'slow' && self.isCatalyzed) { // Wieża Spowalniająca na polu mocy spowalnia o 80% self.targetEnemy.speed *= 0.2; // Dalsza logika spowolnienia } else if (self.type === 'slow') { // Normalne spowolnienie self.targetEnemy.speed *= 0.5; } // Tutaj w przyszłości dodamy logikę dla innych wież z bonusem Catalyst // np. dla wieży trującej. self.destroy(); } else { var angle = Math.atan2(dy, dx); self.x += Math.cos(angle) * self.speed; self.y += Math.sin(angle) * self.speed; } }; return self; }); var DebugCell = Container.expand(function () { var self = Container.call(this); var cellGraphics = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); cellGraphics.tint = Math.random() * 0xffffff; var debugArrows = []; var numberLabel = new Text2('0', { size: 30, fill: 0xFFFFFF, weight: 800 }); numberLabel.anchor.set(.5, .5); self.addChild(numberLabel); self.update = function () {}; self.down = function () { return; if (self.cell.type == 0 || self.cell.type == 1) { self.cell.type = self.cell.type == 1 ? 0 : 1; if (grid.pathFind()) { self.cell.type = self.cell.type == 1 ? 0 : 1; grid.pathFind(); var notification = game.addChild(new Notification("Path is blocked!")); notification.x = 2048 / 2; notification.y = grid.height - 50; } grid.renderDebug(); } }; self.removeArrows = function () { while (debugArrows.length) { self.removeChild(debugArrows.pop()); } }; self.render = function (data) { switch (data.type) { case 0: case 2: { if (data.pathId != pathId) { self.removeArrows(); numberLabel.setText("-"); cellGraphics.tint = 0x880000; return; } numberLabel.visible = true; var tint = Math.floor(data.score / maxScore * 0x88); var towerInRangeHighlight = false; if (selectedTower && data.towersInRange && data.towersInRange.indexOf(selectedTower) !== -1) { towerInRangeHighlight = true; cellGraphics.tint = 0x0088ff; } else { cellGraphics.tint = 0x88 - tint << 8 | tint; } while (debugArrows.length > data.targets.length) { self.removeChild(debugArrows.pop()); } for (var a = 0; a < data.targets.length; a++) { var destination = data.targets[a]; var ox = destination.x - data.x; var oy = destination.y - data.y; var angle = Math.atan2(oy, ox); if (!debugArrows[a]) { debugArrows[a] = LK.getAsset('arrow', { anchorX: -.5, anchorY: 0.5 }); debugArrows[a].alpha = .5; self.addChildAt(debugArrows[a], 1); } debugArrows[a].rotation = angle; } break; } case 1: { self.removeArrows(); cellGraphics.tint = 0xaaaaaa; numberLabel.visible = false; break; } case 3: { self.removeArrows(); cellGraphics.tint = 0x008800; numberLabel.visible = false; break; } } numberLabel.setText(Math.floor(data.score / 1000) / 10); }; }); var EffectIndicator = Container.expand(function (x, y, type) { var self = Container.call(this); self.x = x; self.y = y; var effectGraphics = self.attachAsset('rangeCircle', { anchorX: 0.5, anchorY: 0.5 }); effectGraphics.blendMode = 1; switch (type) { case 'splash': effectGraphics.tint = 0x33CC00; effectGraphics.width = effectGraphics.height = CELL_SIZE * 1.5; break; case 'slow': effectGraphics.tint = 0x9900FF; effectGraphics.width = effectGraphics.height = CELL_SIZE; break; case 'poison': effectGraphics.tint = 0x00FFAA; effectGraphics.width = effectGraphics.height = CELL_SIZE; break; case 'sniper': effectGraphics.tint = 0xFF5500; effectGraphics.width = effectGraphics.height = CELL_SIZE; break; } effectGraphics.alpha = 0.7; self.alpha = 0; tween(self, { alpha: 0.8, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); } }); return self; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'normal'; self.speed = .01; self.cellX = 0; self.cellY = 0; self.currentCellX = 0; self.currentCellY = 0; self.currentTarget = undefined; self.maxHealth = 100; self.health = self.maxHealth; self.bulletsTargetingThis = []; self.waveNumber = currentWave; self.isFlying = false; self.isImmune = false; self.isBoss = false; switch (self.type) { case 'fast': self.speed *= 2; self.maxHealth = 100; break; case 'immune': self.isImmune = true; self.maxHealth = 80; break; case 'flying': self.isFlying = true; self.maxHealth = 80; break; case 'swarm': self.maxHealth = 50; break; case 'normal': default: break; } if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') { self.isBoss = true; self.maxHealth *= 20; self.speed = self.speed * 0.7; } self.health = self.maxHealth; var assetId = 'enemy'; if (self.type !== 'normal') { assetId = 'enemy_' + self.type; } var enemyGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); if (self.isBoss) { enemyGraphics.scaleX = 1.8; enemyGraphics.scaleY = 1.8; } if (self.isFlying) { self.shadow = new Container(); var shadowGraphics = self.shadow.attachAsset(assetId || 'enemy', { anchorX: 0.5, anchorY: 0.5 }); shadowGraphics.tint = 0x000000; shadowGraphics.alpha = 0.4; if (self.isBoss) { shadowGraphics.scaleX = 1.8; shadowGraphics.scaleY = 1.8; } self.shadow.x = 20; self.shadow.y = 20; shadowGraphics.rotation = enemyGraphics.rotation; } var healthBarOutline = self.attachAsset('healthBarOutline', { anchorX: 0, anchorY: 0.5 }); var healthBarBG = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0.5 }); var healthBar = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0.5 }); healthBarBG.y = healthBarOutline.y = healthBar.y = -enemyGraphics.height / 2 - 10; healthBarOutline.x = -healthBarOutline.width / 2; healthBarBG.x = healthBar.x = -healthBar.width / 2 - .5; healthBar.tint = 0x00ff00; healthBarBG.tint = 0xff0000; self.healthBar = healthBar; self.update = function () { if (self.health <= 0) { self.health = 0; self.healthBar.width = 0; } if (self.isImmune) { self.slowed = false; self.slowEffect = false; self.poisoned = false; self.poisonEffect = false; if (self.originalSpeed !== undefined) { self.speed = self.originalSpeed; } } else { if (self.slowed) { if (!self.slowEffect) { self.slowEffect = true; } self.slowDuration--; if (self.slowDuration <= 0) { self.speed = self.originalSpeed; self.slowed = false; self.slowEffect = false; if (!self.poisoned) { enemyGraphics.tint = 0xFFFFFF; } } } if (self.poisoned) { if (!self.poisonEffect) { self.poisonEffect = true; } if (LK.ticks % 30 === 0) { self.health -= self.poisonDamage; if (self.health <= 0) { self.health = 0; } self.healthBar.width = self.health / self.maxHealth * 70; } self.poisonDuration--; if (self.poisonDuration <= 0) { self.poisoned = false; self.poisonEffect = false; if (!self.slowed) { enemyGraphics.tint = 0xFFFFFF; } } } } if (self.isImmune) { enemyGraphics.tint = 0xFFFFFF; } else if (self.poisoned && self.slowed) { enemyGraphics.tint = 0x4C7FD4; } else if (self.poisoned) { enemyGraphics.tint = 0x00FFAA; } else if (self.slowed) { enemyGraphics.tint = 0x9900FF; } else { enemyGraphics.tint = 0xFFFFFF; } if (self.currentTarget) { var ox = self.currentTarget.x - self.currentCellX; var oy = self.currentTarget.y - self.currentCellY; if (ox !== 0 || oy !== 0) { var angle = Math.atan2(oy, ox); if (enemyGraphics.targetRotation === undefined) { enemyGraphics.targetRotation = angle; enemyGraphics.rotation = angle; } else { if (Math.abs(angle - enemyGraphics.targetRotation) > 0.05) { tween.stop(enemyGraphics, { rotation: true }); var currentRotation = enemyGraphics.rotation; var angleDiff = angle - currentRotation; while (angleDiff > Math.PI) { angleDiff -= Math.PI * 2; } while (angleDiff < -Math.PI) { angleDiff += Math.PI * 2; } enemyGraphics.targetRotation = angle; tween(enemyGraphics, { rotation: currentRotation + angleDiff }, { duration: 250, easing: tween.easeOut }); } } } } healthBarOutline.y = healthBarBG.y = healthBar.y = -enemyGraphics.height / 2 - 10; }; return self; }); var GoldIndicator = Container.expand(function (value, x, y) { var self = Container.call(this); var shadowText = new Text2("+" + value, { size: 45, fill: 0x000000, weight: 800 }); shadowText.anchor.set(0.5, 0.5); shadowText.x = 2; shadowText.y = 2; self.addChild(shadowText); var goldText = new Text2("+" + value, { size: 45, fill: 0xFFD700, weight: 800 }); goldText.anchor.set(0.5, 0.5); self.addChild(goldText); self.x = x; self.y = y; self.alpha = 0; self.scaleX = 0.5; self.scaleY = 0.5; tween(self, { alpha: 1, scaleX: 1.2, scaleY: 1.2, y: y - 40 }, { duration: 50, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { alpha: 0, scaleX: 1.5, scaleY: 1.5, y: y - 80 }, { duration: 600, easing: tween.easeIn, delay: 800, onFinish: function onFinish() { self.destroy(); } }); } }); return self; }); var Grid = Container.expand(function (gridWidth, gridHeight) { var self = Container.call(this); self.cells = []; self.spawns = []; self.goals = []; for (var i = 0; i < gridWidth; i++) { self.cells[i] = []; for (var j = 0; j < gridHeight; j++) { self.cells[i][j] = { score: 0, pathId: 0, towersInRange: [], specialEffect: null }; } } for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { var cell = self.cells[i][j]; cell.x = i; cell.y = j; cell.upLeft = self.cells[i - 1] && self.cells[i - 1][j - 1]; cell.up = self.cells[i - 1] && self.cells[i - 1][j]; cell.upRight = self.cells[i - 1] && self.cells[i - 1][j + 1]; cell.left = self.cells[i][j - 1]; cell.right = self.cells[i][j + 1]; cell.downLeft = self.cells[i + 1] && self.cells[i + 1][j - 1]; cell.down = self.cells[i + 1] && self.cells[i + 1][j]; cell.downRight = self.cells[i + 1] && self.cells[i + 1][j + 1]; cell.neighbors = [cell.upLeft, cell.up, cell.upRight, cell.right, cell.downRight, cell.down, cell.downLeft, cell.left]; cell.targets = []; } } self.getCell = function (x, y) { return self.cells[x] && self.cells[x][y]; }; self.pathFind = function () { var before = new Date().getTime(); self.goals = []; for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { if (self.cells[i][j].type === 4) { // Cel to teraz type 4 self.goals.push(self.cells[i][j]); } } } var toProcess = self.goals.concat([]); maxScore = 0; pathId += 1; for (var a = 0; a < toProcess.length; a++) { toProcess[a].pathId = pathId; toProcess[a].score = 0; } function processNode(node, targetValue, targetNode) { // Ta logika sprawdza, którędy może iść wróg if (node && (node.type === 0 || node.type === 3 || node.type === 4)) { if (node.pathId < pathId || targetValue < node.score) { node.targets = [targetNode]; } else if (node.pathId == pathId && targetValue == node.score) { node.targets.push(targetNode); } if (node.pathId < pathId || targetValue < node.score) { node.score = targetValue; if (node.pathId != pathId) { toProcess.push(node); } node.pathId = pathId; if (targetValue > maxScore) { maxScore = targetValue; } } } } while (toProcess.length) { var nodes = toProcess; toProcess = []; for (var a = 0; a < nodes.length; a++) { var node = nodes[a]; var targetScore = node.score + 14142; if (node.up && node.left && (node.up.type === 0 || node.up.type === 3) && (node.left.type === 0 || node.left.type === 3)) { processNode(node.upLeft, targetScore, node); } if (node.up && node.right && (node.up.type === 0 || node.up.type === 3) && (node.right.type === 0 || node.right.type === 3)) { processNode(node.upRight, targetScore, node); } if (node.down && node.right && (node.down.type === 0 || node.down.type === 3) && (node.right.type === 0 || node.right.type === 3)) { processNode(node.downRight, targetScore, node); } if (node.down && node.left && (node.down.type === 0 || node.down.type === 3) && (node.left.type === 0 || node.left.type === 3)) { processNode(node.downLeft, targetScore, node); } targetScore = node.score + 10000; processNode(node.up, targetScore, node); processNode(node.right, targetScore, node); processNode(node.down, targetScore, node); processNode(node.left, targetScore, node); } } self.spawns = []; for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { if (self.cells[i][j].type === 3) { // ZMIANA: Szukamy spawnu type 3 self.spawns.push(self.cells[i][j]); } } } for (var a = 0; a < self.spawns.length; a++) { if (self.spawns[a].pathId != pathId) { console.warn("Spawn blocked"); return true; } } for (var a = 0; a < enemies.length; a++) { var enemy = enemies[a]; if (enemy.isFlying) { continue; } var target = self.getCell(enemy.cellX, enemy.cellY); if (enemy.currentTarget) { if (enemy.currentTarget.pathId != pathId) { if (!target || target.pathId != pathId) { console.warn("Enemy blocked 1 "); return true; } } } else if (!target || target.pathId != pathId) { console.warn("Enemy blocked 2"); return true; } } console.log("Pathfinding complete in:", new Date().getTime() - before, "ms"); }; self.renderDebug = function () { // Ta funkcja może pozostać pusta lub zostać usunięta, // bo nie używamy już starego debugowania siatki }; self.updateEnemy = function (enemy) { var cell = grid.getCell(enemy.cellX, enemy.cellY); if (cell && cell.type == 4) { // ZMIANA: Sprawdzamy, czy wróg dotarł do celu (type 4) return true; // Zwracamy 'true', żeby gra wiedziała, że wróg skończył trasę } if (enemy.isFlying && enemy.shadow) { enemy.shadow.x = enemy.x + 20; enemy.shadow.y = enemy.y + 20; if (enemy.children[0] && enemy.shadow.children[0]) { enemy.shadow.children[0].rotation = enemy.children[0].rotation; } } // Logika startu wroga - idzie prosto w dół do pierwszej komórki ścieżki if (enemy.currentCellY < 5) { enemy.currentCellY += enemy.speed; enemy.x = grid.x + enemy.currentCellX * CELL_SIZE; enemy.y = grid.y + enemy.currentCellY * CELL_SIZE; if (enemy.currentCellY >= 5) { enemy.cellX = Math.round(enemy.currentCellX); enemy.cellY = Math.round(enemy.currentCellY); } return false; } if (enemy.isFlying) { if (!enemy.flyingTarget) { enemy.flyingTarget = self.goals[Math.floor(Math.random() * self.goals.length)]; } var ox = enemy.flyingTarget.x - enemy.currentCellX; var oy = enemy.flyingTarget.y - enemy.currentCellY; var dist = Math.sqrt(ox * ox + oy * oy); if (dist < enemy.speed) { return true; } var angle = Math.atan2(oy, ox); enemy.currentCellX += Math.cos(angle) * enemy.speed; enemy.currentCellY += Math.sin(angle) * enemy.speed; enemy.x = grid.x + enemy.currentCellX * CELL_SIZE; enemy.y = grid.y + enemy.currentCellY * CELL_SIZE; enemy.cellX = Math.round(enemy.currentCellX); enemy.cellY = Math.round(enemy.currentCellY); return false; } if (!enemy.currentTarget) { if (cell) { enemy.currentTarget = cell.targets[Math.floor(Math.random() * cell.targets.length)]; } } if (enemy.currentTarget) { var ox = enemy.currentTarget.x - enemy.currentCellX; var oy = enemy.currentTarget.y - enemy.currentCellY; var dist = Math.sqrt(ox * ox + oy * oy); if (dist < enemy.speed) { enemy.currentCellX = enemy.currentTarget.x; enemy.currentCellY = enemy.currentTarget.y; enemy.cellX = Math.round(enemy.currentCellX); enemy.cellY = Math.round(enemy.currentCellY); enemy.currentTarget = undefined; return; } var angle = Math.atan2(oy, ox); enemy.currentCellX += Math.cos(angle) * enemy.speed; enemy.currentCellY += Math.sin(angle) * enemy.speed; } enemy.x = grid.x + enemy.currentCellX * CELL_SIZE; enemy.y = grid.y + enemy.currentCellY * CELL_SIZE; }; }); var Notification = Container.expand(function (message) { var self = Container.call(this); var notificationGraphics = self.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5 }); var notificationText = new Text2(message, { size: 50, fill: 0x000000, weight: 800 }); notificationText.anchor.set(0.5, 0.5); notificationGraphics.width = notificationText.width + 30; self.addChild(notificationText); self.alpha = 1; var fadeOutTime = 120; self.update = function () { if (fadeOutTime > 0) { fadeOutTime--; self.alpha = Math.min(fadeOutTime / 120 * 2, 1); } else { self.destroy(); } }; return self; }); var PlacementPreview = Container.expand(function () { var self = Container.call(this); self.itemType = 'tower'; // 'tower' or 'building' self.subType = 'default'; self.itemSize = { w: 2, h: 2 }; // in cells self.hasEnoughGold = true; var rangeIndicator = new Container(); self.addChild(rangeIndicator); var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', { anchorX: 0.5, anchorY: 0.5 }); rangeGraphics.alpha = 0.3; var previewGraphics = self.attachAsset('towerpreview', { anchorX: 0.5, anchorY: 0.5 }); self.canPlace = false; self.gridX = 0; self.gridY = 0; self.blockedByEnemy = false; self.update = function () { var cost = self.itemType === 'tower' ? getTowerCost(self.subType) : 100; // Placeholder for building cost var previousHasEnoughGold = self.hasEnoughGold; self.hasEnoughGold = gold >= cost; if (previousHasEnoughGold !== self.hasEnoughGold) { self.updateAppearance(); } }; self.updateAppearance = function () { previewGraphics.width = CELL_SIZE * self.itemSize.w; previewGraphics.height = CELL_SIZE * self.itemSize.h; rangeGraphics.visible = false; var tint = 0xAAAAAA; if (self.itemType === 'tower') { var tempTower = new Tower(self.subType); var previewRange = tempTower.getRange(); if (tempTower && tempTower.destroy) { tempTower.destroy(); } rangeGraphics.width = rangeGraphics.height = previewRange * 2; rangeGraphics.visible = true; switch (self.subType) { case 'rapid': tint = 0x00AAFF; break; case 'sniper': tint = 0xFF5500; break; case 'splash': tint = 0x33CC00; break; case 'slow': tint = 0x9900FF; break; case 'poison': tint = 0x00FFAA; break; } } else { // building switch (self.subType) { case 'home': tint = 0xCCCCCC; break; case 'workshop': tint = 0xD2691E; break; } } previewGraphics.tint = tint; if (!self.canPlace || !self.hasEnoughGold) { previewGraphics.tint = 0xFF0000; } }; self.updatePlacementStatus = function (targetGrid) { var validGridPlacement = true; var currentGrid = targetGrid || grid; if (self.itemType === 'tower') { if (self.gridY <= 4 || self.gridY + 1 >= currentGrid.cells[0].length - 4) { validGridPlacement = false; } } if (validGridPlacement) { for (var i = 0; i < self.itemSize.w; i++) { for (var j = 0; j < self.itemSize.h; j++) { var cell = currentGrid.getCell(self.gridX + i, self.gridY + j); if (!cell || cell.type !== 1) { validGridPlacement = false; break; } } if (!validGridPlacement) { break; } } } self.blockedByEnemy = false; if (validGridPlacement && self.itemType === 'tower') { for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (enemy.currentCellY < 4) { continue; } if (!enemy.isFlying) { if (enemy.cellX >= self.gridX && enemy.cellX < self.gridX + self.itemSize.w && enemy.cellY >= self.gridY && enemy.cellY < self.gridY + self.itemSize.h) { self.blockedByEnemy = true; break; } if (enemy.currentTarget) { var targetX = enemy.currentTarget.x; var targetY = enemy.currentTarget.y; if (targetX >= self.gridX && targetX < self.gridX + self.itemSize.w && targetY >= self.gridY && targetY < self.gridY + self.itemSize.h) { self.blockedByEnemy = true; break; } } } } } self.canPlace = validGridPlacement && !self.blockedByEnemy; var cost = self.itemType === 'tower' ? getTowerCost(self.subType) : 100; self.hasEnoughGold = gold >= cost; self.updateAppearance(); }; self.snapToGrid = function (x, y, targetGrid) { var currentGrid = targetGrid || grid; var gridPosX = x - currentGrid.x; var gridPosY = y - currentGrid.y; self.gridX = Math.floor(gridPosX / CELL_SIZE); self.gridY = Math.floor(gridPosY / CELL_SIZE); self.x = currentGrid.x + self.gridX * CELL_SIZE + previewGraphics.width / 2; self.y = currentGrid.y + self.gridY * CELL_SIZE + previewGraphics.height / 2; self.updatePlacementStatus(currentGrid); }; return self; }); var SourceBuilding = Container.expand(function (buildingType) { var self = Container.call(this); self.buildingType = buildingType || 'default'; var baseGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); switch (self.buildingType) { case 'home': baseGraphics.tint = 0xAAAAAA; break; case 'workshop': baseGraphics.tint = 0xD2691E; break; default: baseGraphics.tint = 0xAAAAAA; } var initialCost = 100; // Placeholder var typeLabelShadow = new Text2(self.buildingType.charAt(0).toUpperCase() + self.buildingType.slice(1), { size: 50, fill: 0x000000, weight: 800 }); typeLabelShadow.anchor.set(0.5, 0.5); typeLabelShadow.x = 4; typeLabelShadow.y = -20 + 4; self.addChild(typeLabelShadow); var typeLabel = new Text2(self.buildingType.charAt(0).toUpperCase() + self.buildingType.slice(1), { size: 50, fill: 0xFFFFFF, weight: 800 }); typeLabel.anchor.set(0.5, 0.5); typeLabel.y = -20; self.addChild(typeLabel); var costLabelShadow = new Text2(initialCost, { size: 50, fill: 0x000000, weight: 800 }); costLabelShadow.anchor.set(0.5, 0.5); costLabelShadow.x = 4; costLabelShadow.y = 24 + 12; self.addChild(costLabelShadow); var costLabel = new Text2(initialCost, { size: 50, fill: 0xFFD700, weight: 800 }); costLabel.anchor.set(0.5, 0.5); costLabel.y = 20 + 12; self.addChild(costLabel); self.update = function () { var canAfford = true; // Placeholder self.alpha = canAfford ? 1 : 0.5; }; return self; }); var SourceTower = Container.expand(function (towerType) { var self = Container.call(this); self.towerType = towerType || 'default'; var baseGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); switch (self.towerType) { case 'rapid': baseGraphics.tint = 0x00AAFF; break; case 'sniper': baseGraphics.tint = 0xFF5500; break; case 'splash': baseGraphics.tint = 0x33CC00; break; case 'slow': baseGraphics.tint = 0x9900FF; break; case 'poison': baseGraphics.tint = 0x00FFAA; break; default: baseGraphics.tint = 0xAAAAAA; } var initialCost = getTowerCost(self.towerType); var typeLabelShadow = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), { size: 50, fill: 0x000000, weight: 800 }); typeLabelShadow.anchor.set(0.5, 0.5); typeLabelShadow.x = 4; typeLabelShadow.y = -20 + 4; self.addChild(typeLabelShadow); var typeLabel = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), { size: 50, fill: 0xFFFFFF, weight: 800 }); typeLabel.anchor.set(0.5, 0.5); typeLabel.y = -20; self.addChild(typeLabel); var costLabelShadow = new Text2(initialCost, { size: 50, fill: 0x000000, weight: 800 }); costLabelShadow.anchor.set(0.5, 0.5); costLabelShadow.x = 4; costLabelShadow.y = 24 + 12; self.addChild(costLabelShadow); var costLabel = new Text2(initialCost, { size: 50, fill: 0xFFD700, weight: 800 }); costLabel.anchor.set(0.5, 0.5); costLabel.y = 20 + 12; self.addChild(costLabel); self.update = function () { var currentCost = getTowerCost(self.towerType); if (costLabel.text !== currentCost) { costLabel.setText(currentCost); costLabelShadow.setText(currentCost); } var canAfford = gold >= currentCost; self.alpha = canAfford ? 1 : 0.5; }; return self; }); var Tower = Container.expand(function (id) { var self = Container.call(this); self.id = id || 'default'; self.level = 1; self.maxLevel = 6; self.gridX = 0; self.gridY = 0; self.specialBuff = null; // Nowa właściwość na przechowywanie buffa // Podstawowe statystyki, które mogą być modyfikowane przez buffy self.baseDamage = 10; self.baseFireRate = 60; self.baseRange = 3 * CELL_SIZE; self.baseBulletSpeed = 5; switch (self.id) { case 'rapid': self.baseFireRate = 30; self.baseDamage = 5; self.baseRange = 2.5 * CELL_SIZE; self.baseBulletSpeed = 7; break; case 'sniper': self.baseFireRate = 90; self.baseDamage = 25; self.baseRange = 5 * CELL_SIZE; self.baseBulletSpeed = 25; break; case 'splash': self.baseFireRate = 75; self.baseDamage = 15; self.baseRange = 2 * CELL_SIZE; self.baseBulletSpeed = 4; break; case 'slow': self.baseFireRate = 50; self.baseDamage = 8; self.baseRange = 3.5 * CELL_SIZE; self.baseBulletSpeed = 5; break; case 'poison': self.baseFireRate = 70; self.baseDamage = 12; self.baseRange = 3.2 * CELL_SIZE; self.baseBulletSpeed = 5; break; } // Ustawiamy aktualne statystyki na podstawie bazowych self.damage = self.baseDamage; self.fireRate = self.baseFireRate; self.range = self.baseRange; self.bulletSpeed = self.baseBulletSpeed; self.lastFired = 0; self.targetEnemy = null; self.getRange = function () { var currentRange = self.range; // Logika zasięgu dla snajpera i innych wież pozostaje, ale operuje na 'self.range' if (self.id === 'sniper' && self.level === self.maxLevel) { currentRange = self.range * 2.4; // Przykładowe zwiększenie dla snajpera na max levelu } return currentRange; }; // ... reszta kodu (grafiki, wskaźniki poziomu) ... var baseGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); switch (self.id) { case 'rapid': baseGraphics.tint = 0x00AAFF; break; case 'sniper': baseGraphics.tint = 0xFF5500; break; case 'splash': baseGraphics.tint = 0x33CC00; break; case 'slow': baseGraphics.tint = 0x9900FF; break; case 'poison': baseGraphics.tint = 0x00FFAA; break; default: baseGraphics.tint = 0xAAAAAA; } var levelIndicators = []; var maxDots = self.maxLevel; var dotSpacing = baseGraphics.width / (maxDots + 1); var dotSize = CELL_SIZE / 6; for (var i = 0; i < maxDots; i++) { var dot = new Container(); var outlineCircle = dot.attachAsset('towerLevelIndicator', { anchorX: 0.5, anchorY: 0.5 }); outlineCircle.width = dotSize + 4; outlineCircle.height = dotSize + 4; outlineCircle.tint = 0x000000; var towerLevelIndicator = dot.attachAsset('towerLevelIndicator', { anchorX: 0.5, anchorY: 0.5 }); towerLevelIndicator.width = dotSize; towerLevelIndicator.height = dotSize; towerLevelIndicator.tint = 0xCCCCCC; dot.x = -CELL_SIZE + dotSpacing * (i + 1); dot.y = CELL_SIZE * 0.7; self.addChild(dot); levelIndicators.push(dot); } var gunContainer = new Container(); self.addChild(gunContainer); var gunGraphics = gunContainer.attachAsset('defense', { anchorX: 0.5, anchorY: 0.5 }); self.updateLevelIndicators = function () { // Ta funkcja bez zmian }; self.updateLevelIndicators(); // --- NOWA LOGIKA APLIKOWANIA BUFFÓW --- self.applyBuffs = function () { // Reset to base stats first self.damage = self.baseDamage; self.range = self.baseRange; if (self.specialBuff === 'amplifier') { self.damage = Math.round(self.damage * 1.25); // +25% Obrażeń self.range = self.range * 1.15; // +15% Zasięgu } // Re-calculate stats based on level after applying buffs self.recalculateLevelStats(); }; self.recalculateLevelStats = function () { // Ta funkcja będzie aktualizować statystyki po ulepszeniu, uwzględniając już aktywne buffy // Na razie prosta, do rozbudowy }; self.placeOnGrid = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = grid.x + (gridX + 1) * CELL_SIZE; self.y = grid.y + (gridY + 1) * CELL_SIZE; var firstCell = grid.getCell(gridX, gridY); if (firstCell && firstCell.specialEffect) { self.specialBuff = firstCell.specialEffect; console.log("Tower built on a special field:", self.specialBuff); } for (var i = 0; i < 2; i++) { for (var j = 0; j < 2; j++) { var cell = grid.getCell(gridX + i, gridY + j); if (cell) { cell.type = 5; } } } self.applyBuffs(); // Aplikujemy buffy zaraz po postawieniu self.refreshCellsInRange(); }; // ... reszta funkcji (findTarget, update, fire, etc.) bez większych zmian, // ale trzeba je tu wkleić, żeby klasa była kompletna. // Poniżej wklejam resztę klasy z drobnymi modyfikacjami, aby używała nowych statystyk self.refreshCellsInRange = function () {/* bez zmian */}; self.getTotalValue = function () {/* bez zmian */}; self.upgrade = function () {/* bez zmian, ale będzie potrzebował recalculateLevelStats */}; self.findTarget = function () {/* bez zmian */}; self.update = function () { self.targetEnemy = self.findTarget(); if (self.targetEnemy) { var dx = self.targetEnemy.x - self.x; var dy = self.targetEnemy.y - self.y; var angle = Math.atan2(dy, dx); gunContainer.rotation = angle; if (LK.ticks - self.lastFired >= self.fireRate) { self.fire(); self.lastFired = LK.ticks; } } }; self.fire = function () { if (self.targetEnemy && self.targetEnemy.health > 0) { var bulletX = self.x + Math.cos(gunContainer.rotation) * 40; var bulletY = self.y + Math.sin(gunContainer.rotation) * 40; var bullet = new Bullet(bulletX, bulletY, self.targetEnemy, self.damage, self.bulletSpeed); bullet.type = self.id; // Przekazujemy informację o buffie do pocisku if (self.specialBuff === 'catalyst') { bullet.isCatalyzed = true; } // ... reszta logiki fire() ... game.addChild(bullet); bullets.push(bullet); } }; self.down = function (x, y, obj) {/* bez zmian */}; return self; }); var UpgradeMenu = Container.expand(function (tower) { var self = Container.call(this); self.tower = tower; self.y = 2732 + 225; var menuBackground = self.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5 }); menuBackground.width = 2048; menuBackground.height = 500; menuBackground.tint = 0x444444; menuBackground.alpha = 0.9; var towerTypeText = new Text2(self.tower.id.charAt(0).toUpperCase() + self.tower.id.slice(1) + ' Tower', { size: 80, fill: 0xFFFFFF, weight: 800 }); towerTypeText.anchor.set(0, 0); towerTypeText.x = -840; towerTypeText.y = -160; self.addChild(towerTypeText); var statsText = new Text2('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s', { size: 70, fill: 0xFFFFFF, weight: 400 }); statsText.anchor.set(0, 0.5); statsText.x = -840; statsText.y = 50; self.addChild(statsText); var buttonsContainer = new Container(); buttonsContainer.x = 500; self.addChild(buttonsContainer); var upgradeButton = new Container(); buttonsContainer.addChild(upgradeButton); var buttonBackground = upgradeButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5 }); buttonBackground.width = 500; buttonBackground.height = 150; var buttonText = new Text2('', { size: 60, fill: 0xFFFFFF, weight: 800 }); buttonText.anchor.set(0.5, 0.5); upgradeButton.addChild(buttonText); var sellButton = new Container(); buttonsContainer.addChild(sellButton); var sellButtonBackground = sellButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5 }); sellButtonBackground.width = 500; sellButtonBackground.height = 150; sellButtonBackground.tint = 0xCC0000; var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0; var sellValue = getTowerSellValue(totalInvestment); var sellButtonText = new Text2('Sell: +' + sellValue + ' gold', { size: 60, fill: 0xFFFFFF, weight: 800 }); sellButtonText.anchor.set(0.5, 0.5); sellButton.addChild(sellButtonText); upgradeButton.y = -85; sellButton.y = 85; var closeButton = new Container(); self.addChild(closeButton); var closeBackground = closeButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5 }); closeBackground.width = 90; closeBackground.height = 90; closeBackground.tint = 0xAA0000; var closeText = new Text2('X', { size: 68, fill: 0xFFFFFF, weight: 800 }); closeText.anchor.set(0.5, 0.5); closeButton.addChild(closeText); closeButton.x = menuBackground.width / 2 - 57; closeButton.y = -menuBackground.height / 2 + 57; function getUpgradeCost() { if (self.tower.level >= self.tower.maxLevel) { return 0; } // Koszt ulepszenia bazuje na KOSZCIE PODSTAWOWYM wieży, bez mnożnika fazy walki var tempPhase = isBuildPhase; isBuildPhase = true; var baseTowerCost = getTowerCost(self.tower.id); isBuildPhase = tempPhase; var upgradeCost; if (self.tower.level === self.tower.maxLevel - 1) { upgradeCost = Math.floor(baseTowerCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2); } else { upgradeCost = Math.floor(baseTowerCost * Math.pow(2, self.tower.level - 1)); } // Dopiero na końcu dodajemy ewentualny mnożnik fazy walki if (!isBuildPhase) { upgradeCost = Math.floor(upgradeCost * 1.5); } return upgradeCost; } upgradeButton.down = function (x, y, obj) { if (self.tower.level >= self.tower.maxLevel) { var notification = game.addChild(new Notification("Tower is already at max level!")); notification.x = 2048 / 2; notification.y = grid.height - 50; return; } var currentUpgradeCost = getUpgradeCost(); if (gold >= currentUpgradeCost) { setGold(gold - currentUpgradeCost); self.tower.upgrade(); statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s'); var newTotalInvestment = self.tower.getTotalValue(); sellButtonText.setText('Sell: +' + getTowerSellValue(newTotalInvestment) + ' gold'); var rangeCircle = null; for (var i = 0; i < game.children.length; i++) { if (game.children[i].isTowerRange && game.children[i].tower === self.tower) { rangeCircle = game.children[i]; break; } } if (rangeCircle) { rangeCircle.children[0].width = rangeCircle.children[0].height = self.tower.getRange() * 2; } } else { var notification = game.addChild(new Notification("Not enough gold to upgrade!")); notification.x = 2048 / 2; notification.y = grid.height - 50; } }; sellButton.down = function (x, y, obj) { var sellValue = getTowerSellValue(self.tower.getTotalValue()); setGold(gold + sellValue); var gridX = self.tower.gridX; var gridY = self.tower.gridY; for (var i = 0; i < 2; i++) { for (var j = 0; j < 2; j++) { var cell = grid.getCell(gridX + i, gridY + j); if (cell) { cell.type = 1; } } } grid.pathFind(); if (selectedTower === self.tower) { selectedTower = null; } var towerIndex = towers.indexOf(self.tower); if (towerIndex !== -1) { towers.splice(towerIndex, 1); } for (var i = 0; i < game.children.length; i++) { if (game.children[i].isTowerRange && game.children[i].tower === self.tower) { game.removeChild(game.children[i]); break; } } towerLayer.removeChild(self.tower); self.destroy(); }; closeButton.down = function (x, y, obj) { hideUpgradeMenu(self); selectedTower = null; grid.renderDebug(); }; self.update = function () { if (self.tower.level >= self.tower.maxLevel) { buttonText.setText('Max Level'); buttonBackground.tint = 0x888888; return; } var currentUpgradeCost = getUpgradeCost(); buttonText.setText('Upgrade: ' + currentUpgradeCost + ' gold'); var canAfford = gold >= currentUpgradeCost; buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888; }; return self; }); /**** * Initialize Game ****/ /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x333333 }); /**** * Game Code ****/ /**** * Game Code ****/ var CELL_SIZE = 76; // --- GŁÓWNE ZMIENNE STANU GRY --- var isBuildPhase = false; var buildPhaseTimer = 0; // Timer do odliczania var startGameButton; // Przycisk "Start building" var timerText; var pathId; var maxScore; var enemies; var towers; var bullets; var selectedTower; var gold; var lives; var enemiesKilled; var enemiesInCurrentWave; var levelData; var currentWave; var totalWaves; var waveTimer; var waveInProgress; var waveSpawned; var nextWaveTime; var sourceTowers; var grid; var wavesText; var towerLayer; var enemyLayer; var debugLayer; var buildableTilesLayer; var specialTilesLayer; var enemyLayerBottom; var enemyLayerMiddle; var enemyLayerTop; var placementPreview; var buildPanelContainer; var buildButton; var isBuildPanelOpen; var currentActiveView; var gateContainer; var castleContainer; var viewToggleButton; var castleGrid; var castleBuildPanel; // --- GŁÓWNE ELEMENTY UI --- var goldText = new Text2('Gold: ' + 80, { size: 60, fill: 0xFFD700, weight: 800 }); goldText.anchor.set(0.5, 0.5); var livesText = new Text2('Lives: ' + 20, { size: 60, fill: 0x00FF00, weight: 800 }); livesText.anchor.set(0.5, 0.5); var enemiesText = new Text2('Enemies: 0/0', { size: 60, fill: 0xFF0000, weight: 800 }); enemiesText.anchor.set(0.5, 0.5); var timerText = new Text2('', { size: 50, fill: 0xFFFFFF, weight: 700 }); timerText.anchor.set(0.5, 0.5); timerText.visible = false; var topMargin = 50; var centerX = 2048 / 2; var spacing = 400; LK.gui.top.addChild(goldText); LK.gui.top.addChild(livesText); LK.gui.top.addChild(enemiesText); LK.gui.top.addChild(timerText); livesText.x = 0; livesText.y = topMargin; goldText.x = -spacing; goldText.y = topMargin; enemiesText.x = spacing; enemiesText.y = topMargin; timerText.x = -spacing; timerText.y = topMargin + 70; // --- ZARZĄDZANIE STANAMI GRY --- var currentScreenState = ''; var titleScreenContainer = null; var levelSelectContainer = null; // --- GLOBALNE FUNKCJE POMOCNICZE --- var isHidingUpgradeMenu = false; function hideUpgradeMenu(menu) { if (isHidingUpgradeMenu) { return; } isHidingUpgradeMenu = true; tween(menu, { y: 2732 + 225 }, { duration: 150, easing: tween.easeIn, onFinish: function onFinish() { menu.destroy(); isHidingUpgradeMenu = false; } }); } function updateUI() { goldText.setText('Gold: ' + gold); livesText.setText('Lives: ' + lives); enemiesText.setText('Enemies: ' + enemiesKilled + '/' + enemiesInCurrentWave); if (wavesText) { wavesText.setText('Wave: ' + currentWave + '/' + totalWaves); } } function setGold(value) { gold = value; updateUI(); } function getTowerCost(towerType) { var cost = 5; switch (towerType) { case 'rapid': cost = 15; break; case 'sniper': cost = 25; break; case 'splash': cost = 35; break; case 'slow': cost = 45; break; case 'poison': cost = 55; break; } if (!isBuildPhase && currentWave > 0) { // Jeśli trwa faza walki cost = Math.floor(cost * 1.5); } return cost; } function getTowerSellValue(totalValue) { return Math.floor(totalValue * 0.6); } // --- FUNKCJE EKRANÓW --- function showTitleScreen() { if (titleScreenContainer) { titleScreenContainer.destroy(); } titleScreenContainer = new Container(); game.addChild(titleScreenContainer); currentScreenState = 'title'; if (LK.gui.top) { LK.gui.top.visible = false; } var gameTitle = new Text2("OUR FANTASY TD", { size: 120, fill: 0xFFD700, weight: 800, align: 'center', stroke: 0x000000, strokeThickness: 8 }); gameTitle.anchor.set(0.5, 0.5); gameTitle.x = 2048 / 2; gameTitle.y = 2732 / 2 - 300; titleScreenContainer.addChild(gameTitle); var startButton = new Container(); startButton.x = 2048 / 2; startButton.y = 2732 / 2 + 100; titleScreenContainer.addChild(startButton); var startButtonBg = startButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 400, height: 150, tint: 0x00AA00 }); var startButtonText = new Text2("START", { size: 80, fill: 0xFFFFFF, weight: 'bold' }); startButtonText.anchor.set(0.5, 0.5); startButton.addChild(startButtonText); startButton.interactive = true; startButton.down = function () { if (titleScreenContainer) { titleScreenContainer.destroy(); } showLevelSelectScreen(); }; } function showLevelSelectScreen() { if (levelSelectContainer) { levelSelectContainer.destroy(); } levelSelectContainer = new Container(); game.addChild(levelSelectContainer); currentScreenState = 'levelSelect'; if (LK.gui.top) { LK.gui.top.visible = false; } var selectTitle = new Text2("SELECT LEVEL", { size: 100, fill: 0xFFFFFF, weight: 700 }); selectTitle.anchor.set(0.5, 0.5); selectTitle.x = 2048 / 2; selectTitle.y = 400; levelSelectContainer.addChild(selectTitle); var levelButton1 = new Container(); levelButton1.x = 2048 / 2; levelButton1.y = 800; levelSelectContainer.addChild(levelButton1); var levelButton1Bg = levelButton1.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 600, height: 200, tint: 0x0088CC }); var levelButton1Text = new Text2("Level 1: Royal Road", { size: 60, fill: 0xFFFFFF }); levelButton1Text.anchor.set(0.5, 0.5); levelButton1.addChild(levelButton1Text); levelButton1.interactive = true; levelButton1.down = function () { startGame(1); }; var backButton = new Container(); backButton.x = 2048 / 2; backButton.y = 2732 - 300; levelSelectContainer.addChild(backButton); var backButtonBg = backButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 120, tint: 0xAA0000 }); var backButtonText = new Text2("Back", { size: 60, fill: 0xFFFFFF }); backButtonText.anchor.set(0.5, 0.5); backButton.addChild(backButtonText); backButton.interactive = true; backButton.down = function () { if (levelSelectContainer) { levelSelectContainer.destroy(); } showTitleScreen(); }; } function toggleBuildPanel(panelOrState, stateOrPanel) { var panel, forceState; if (typeof panelOrState === 'string') { forceState = panelOrState; panel = stateOrPanel; } else { panel = panelOrState; forceState = stateOrPanel; } var targetY; var shouldBeOpen; if (!panel) { return; } if (forceState === 'open') { shouldBeOpen = true; } else if (forceState === 'close') { shouldBeOpen = false; } else { shouldBeOpen = !isBuildPanelOpen; } if (shouldBeOpen) { targetY = 2732 - 250; isBuildPanelOpen = true; } else { targetY = 2732 + 100; isBuildPanelOpen = false; } tween(panel, { y: targetY }, { duration: 300, easing: tween.backOut }); } function startGame(levelNumber) { console.log("Rozpoczynam ładowanie poziomu: " + levelNumber); if (titleScreenContainer) { titleScreenContainer.destroy(); titleScreenContainer = null; } if (levelSelectContainer) { levelSelectContainer.destroy(); levelSelectContainer = null; } currentScreenState = 'gameplay'; if (LK.gui.top) { LK.gui.top.visible = true; } gateContainer = new Container(); game.addChild(gateContainer); castleContainer = new Container(); game.addChild(castleContainer); castleContainer.visible = false; currentActiveView = 'gate'; var castleMainBg = LK.getAsset('castle_bg_image', {}); castleContainer.addChildAt(castleMainBg, 0); castleMainBg.x = -200; gateContainer.addChild(LK.getAsset('map1', { scaleMode: 'nearest' })); levelData = { levelName: "Level 1: Royal Road", initialGold: 100, initialLives: 20, mapLayout: ["22222222110S011222222222", "22222222AA00011222222222", "222222221100011222222222", "222222221100011222222222", "2222222211000AA222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "22222222110E011222222222"], castleMapLayout: ["111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111"], waves: [{ wave: 1, type: 'normal', count: 10 }], specialTiles: [] }; pathId = 1; maxScore = 0; enemies = []; towers = []; bullets = []; selectedTower = null; gold = levelData.initialGold; lives = levelData.initialLives; enemiesKilled = 0; enemiesInCurrentWave = 0; currentWave = 1; totalWaves = levelData.waves.length; waveInProgress = false; waveSpawned = false; waveTimer = 0; nextWaveTime = 1200; sourceTowers = []; isBuildPanelOpen = false; wavesText = new Text2('Wave: 0/' + totalWaves, { size: 60, fill: 0x00FFFF, weight: 800 }); wavesText.anchor.set(0.5, 0.5); LK.gui.top.addChild(wavesText); wavesText.x = spacing; wavesText.y = topMargin + 80; updateUI(); debugLayer = new Container(); specialTilesLayer = new Container(); towerLayer = new Container(); buildableTilesLayer = new Container(); enemyLayerBottom = new Container(); enemyLayerMiddle = new Container(); enemyLayerTop = new Container(); enemyLayer = new Container(); enemyLayer.addChild(enemyLayerBottom); enemyLayer.addChild(enemyLayerMiddle); enemyLayer.addChild(enemyLayerTop); grid = new Grid(24, 29 + 6); grid.x = 150; grid.y = 200 - CELL_SIZE * 4; gateContainer.addChild(buildableTilesLayer); buildableTilesLayer.visible = false; for (var y = 0; y < levelData.mapLayout.length; y++) { for (var x = 0; x < levelData.mapLayout[y].length; x++) { var tileChar = levelData.mapLayout[y][x]; var cell = grid.getCell(x, y + 5); if (cell) { cell.specialEffect = null; if (tileChar === '0') { cell.type = 0; } else if (tileChar === '1' || tileChar === 'A' || tileChar === 'C') { cell.type = 1; if (tileChar === 'A') { cell.specialEffect = 'amplifier'; } if (tileChar === 'C') { cell.specialEffect = 'catalyst'; } var tilePlaceholder = buildableTilesLayer.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); tilePlaceholder.alpha = 0.25; tilePlaceholder.x = grid.x + x * CELL_SIZE + CELL_SIZE / 2; tilePlaceholder.y = grid.y + (y + 5) * CELL_SIZE + CELL_SIZE / 2; } else if (tileChar === 'S') { cell.type = 3; } else if (tileChar === 'E') { cell.type = 4; } else { cell.type = 2; } } } } castleGrid = new Grid(12, 12); castleGrid.x = (2048 - 12 * CELL_SIZE) / 2; castleGrid.y = (2732 - 12 * CELL_SIZE) / 2 - 200; var castleBuildableTilesLayer = new Container(); castleContainer.addChild(castleBuildableTilesLayer); for (var y = 0; y < levelData.castleMapLayout.length; y++) { for (var x = 0; x < levelData.castleMapLayout[y].length; x++) { var tileChar = levelData.castleMapLayout[y][x]; var cell = castleGrid.getCell(x, y); if (cell) { if (tileChar === '1') { cell.type = 1; var tilePlaceholder = castleBuildableTilesLayer.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); tilePlaceholder.alpha = 0.25; tilePlaceholder.x = castleGrid.x + x * CELL_SIZE + CELL_SIZE / 2; tilePlaceholder.y = castleGrid.y + y * CELL_SIZE + CELL_SIZE / 2; } else { cell.type = 2; } } } } levelData.specialTiles.forEach(function (tile) { var cell = grid.getCell(tile.x, tile.y); if (cell) { cell.specialEffect = tile.type; var tilePlaceholder = specialTilesLayer.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); tilePlaceholder.x = grid.x + tile.x * CELL_SIZE + CELL_SIZE / 2; tilePlaceholder.y = grid.y + tile.y * CELL_SIZE + CELL_SIZE / 2; tilePlaceholder.alpha = 0.5; if (tile.type === 'amplify') { tilePlaceholder.tint = 0xFFD700; } else if (tile.type === 'synergy') { tilePlaceholder.tint = 0x9932CC; } } }); grid.pathFind(); gateContainer.addChild(debugLayer); gateContainer.addChild(specialTilesLayer); gateContainer.addChild(towerLayer); gateContainer.addChild(enemyLayer); placementPreview = new PlacementPreview(); gateContainer.addChild(placementPreview); placementPreview.visible = false; var isDragging = false; startGameButton = new Container(); var startBuildingBg = startGameButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 600, height: 150, tint: 0xFFD700 }); var startBuildingText = new Text2("Start Building", { size: 70, fill: 0x000000, weight: 'bold' }); startBuildingText.anchor.set(0.5, 0.5); startGameButton.addChild(startBuildingText); startGameButton.x = 2048 / 2; startGameButton.y = 2732 / 2; gateContainer.addChild(startGameButton); startGameButton.down = function () { isBuildPhase = true; buildPhaseTimer = 60 * 10; timerText.visible = true; startGameButton.destroy(); }; buildPanelContainer = new Container(); gateContainer.addChild(buildPanelContainer); buildPanelContainer.x = 2048 / 2; buildPanelContainer.y = 2732 + 100; var panelBackground = buildPanelContainer.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 1800, height: 400 }); panelBackground.tint = 0x222222; panelBackground.alpha = 0.9; var towerTypes = ['default', 'rapid', 'sniper', 'splash', 'slow', 'poison']; var towerIconSpacing = 280; var totalWidth = (towerTypes.length - 1) * towerIconSpacing; var towerStartX = -totalWidth / 2; for (var i = 0; i < towerTypes.length; i++) { var tower = new SourceTower(towerTypes[i]); tower.x = towerStartX + i * towerIconSpacing; tower.y = 0; buildPanelContainer.addChild(tower); sourceTowers.push(tower); } castleBuildPanel = new Container(); castleContainer.addChild(castleBuildPanel); castleBuildPanel.x = 2048 / 2; castleBuildPanel.y = 2732 + 100; var castlePanelBackground = castleBuildPanel.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 1800, height: 400 }); castlePanelBackground.tint = 0x332211; castlePanelBackground.alpha = 0.9; var buildingTypes = ['home', 'workshop']; var buildingIconSpacing = 280; var totalBuildingWidth = (buildingTypes.length - 1) * buildingIconSpacing; var buildingStartX = -totalBuildingWidth / 2; for (var i = 0; i < buildingTypes.length; i++) { var building = new SourceBuilding(buildingTypes[i]); building.x = buildingStartX + i * buildingIconSpacing; building.y = 0; castleBuildPanel.addChild(building); } buildButton = new Container(); game.addChild(buildButton); buildButton.x = 2048 / 2; buildButton.y = 2732 - 100; var buildButtonBg = buildButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 120 }); buildButtonBg.tint = 0xFFD700; var buildButtonText = new Text2("Build", { size: 60, fill: 0x000000, weight: 800 }); buildButtonText.anchor.set(0.5, 0.5); buildButton.addChild(buildButtonText); buildButton.down = function () { if (currentActiveView === 'gate') { toggleBuildPanel(buildPanelContainer); } else { toggleBuildPanel(castleBuildPanel); } }; viewToggleButton = new Container(); game.addChild(viewToggleButton); viewToggleButton.x = 250; viewToggleButton.y = 2732 - 100; var viewToggleButtonBg = viewToggleButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 120, tint: 0x4466AA }); var viewToggleButtonText = new Text2("Castle", { size: 60, fill: 0xFFFFFF, weight: 800 }); viewToggleButtonText.anchor.set(0.5, 0.5); viewToggleButton.addChild(viewToggleButtonText); viewToggleButton.down = function () { if (currentActiveView === 'gate') { currentActiveView = 'castle'; viewToggleButtonText.setText("Gate"); gateContainer.visible = false; castleContainer.visible = true; } else { currentActiveView = 'gate'; viewToggleButtonText.setText("Castle"); gateContainer.visible = true; castleContainer.visible = false; } }; function placeTower(gridX, gridY, towerType) { var towerCost = getTowerCost(towerType); if (gold >= towerCost) { var tower = new Tower(towerType || 'default'); tower.placeOnGrid(gridX, gridY); towerLayer.addChild(tower); towers.push(tower); setGold(gold - towerCost); grid.pathFind(); return true; } else { var notification = game.addChild(new Notification("Not enough gold!")); notification.x = 2048 / 2; notification.y = grid.height - 50; return false; } } game.down = function (x, y, obj) { var buildButtonBounds = buildButton.getBounds(); if (buildButtonBounds.contains(x, y)) { return; } var viewToggleButtonBounds = viewToggleButton.getBounds(); if (viewToggleButtonBounds.contains(x, y)) { return; } var upgradeMenuVisible = game.children.some(function (child) { return child instanceof UpgradeMenu; }); if (upgradeMenuVisible) { return; } if (isBuildPanelOpen) { var activePanel = currentActiveView === 'gate' ? buildPanelContainer : castleBuildPanel; var localClickPos = { x: x - activePanel.x, y: y - activePanel.y }; var clickedOnSourceItem = false; var sourceItems = currentActiveView === 'gate' ? sourceTowers : castleBuildPanel.children.filter(function (c) { return c instanceof SourceBuilding; }); for (var i = 0; i < sourceItems.length; i++) { var item = sourceItems[i]; var itemBounds = { left: item.x - item.width / 2, right: item.x + item.width / 2, top: item.y - item.height / 2, bottom: item.y + item.height / 2 }; if (localClickPos.x >= itemBounds.left && localClickPos.x <= itemBounds.right && localClickPos.y >= itemBounds.top && localClickPos.y <= itemBounds.bottom) { clickedOnSourceItem = true; isDragging = true; placementPreview.visible = true; var activeGrid = currentActiveView === 'gate' ? grid : castleGrid; var itemSubType; if (currentActiveView === 'gate') { placementPreview.itemType = 'tower'; itemSubType = item.towerType; placementPreview.itemSize = { w: 2, h: 2 }; } else { placementPreview.itemType = 'building'; itemSubType = item.buildingType; if (itemSubType === 'home') { placementPreview.itemSize = { w: 2, h: 2 }; } if (itemSubType === 'workshop') { placementPreview.itemSize = { w: 4, h: 2 }; } } placementPreview.subType = itemSubType; placementPreview.updateAppearance(); if (currentActiveView === 'gate') { buildableTilesLayer.visible = true; } var yOffset = currentActiveView === 'gate' ? CELL_SIZE * 1.5 : 0; placementPreview.snapToGrid(x, y - yOffset, activeGrid); return; } } if (!clickedOnSourceItem) { var targetPanel = currentActiveView === 'gate' ? buildPanelContainer : castleBuildPanel; toggleBuildPanel(targetPanel, 'close'); } } }; game.move = function (x, y, obj) { if (isDragging) { var activeGrid = currentActiveView === 'gate' ? grid : castleGrid; var yOffset = currentActiveView === 'gate' ? CELL_SIZE * 1.5 : 0; placementPreview.snapToGrid(x, y - yOffset, activeGrid); } }; game.up = function (x, y, obj) { if (isDragging) { isDragging = false; placementPreview.visible = false; if (currentActiveView === 'gate') { buildableTilesLayer.visible = false; if (placementPreview.canPlace) { placeTower(placementPreview.gridX, placementPreview.gridY, placementPreview.subType); } } else { if (placementPreview.canPlace) { console.log("Placing building:", placementPreview.subType, "at", placementPreview.gridX, placementPreview.gridY); } } var targetPanel = currentActiveView === 'gate' ? buildPanelContainer : castleBuildPanel; toggleBuildPanel(targetPanel, 'close'); } else { var clickedOnTower = false; for (var i = 0; i < towers.length; i++) { var tower = towers[i]; var towerBounds = tower.getBounds(); if (towerBounds.contains(x - tower.x + tower.width / 2, y - tower.y + tower.height / 2)) { clickedOnTower = true; break; } } var upgradeMenus = game.children.filter(function (child) { return child instanceof UpgradeMenu; }); if (upgradeMenus.length > 0 && !clickedOnTower) { var clickedOnMenu = false; for (var i = 0; i < upgradeMenus.length; i++) { var menu = upgradeMenus[i]; var menuBounds = menu.getBounds(); if (menuBounds.contains(x - menu.x + menu.width / 2, y - menu.y + menu.height / 2)) { clickedOnMenu = true; break; } } if (!clickedOnMenu) { for (var i = 0; i < upgradeMenus.length; i++) { hideUpgradeMenu(upgradeMenus[i]); } for (var i = game.children.length - 1; i >= 0; i--) { if (game.children[i].isTowerRange) { game.removeChild(game.children[i]); } } selectedTower = null; } } } }; } game.update = function () { if (currentScreenState !== 'gameplay') { return; } if (currentActiveView === 'gate') { if (isBuildPhase) { if (buildPhaseTimer > 0) { buildPhaseTimer--; timerText.setText("Build Time: " + Math.ceil(buildPhaseTimer / 60)); } else { isBuildPhase = false; timerText.visible = false; waveInProgress = true; waveSpawned = false; } } else if (waveInProgress) { if (!waveSpawned) { waveSpawned = true; enemiesKilled = 0; var waveData = levelData.waves[currentWave - 1]; if (waveData) { var enemyCount = waveData.count; var waveType = waveData.type; var isBoss = waveData.isBoss || false; enemiesInCurrentWave = enemyCount; updateUI(); for (var i = 0; i < enemyCount; i++) { var enemy = new Enemy(waveType); var spawnPoints = grid.spawns; var spawnX = spawnPoints && spawnPoints.length > 0 ? spawnPoints[Math.floor(Math.random() * spawnPoints.length)].x : Math.floor(grid.cells.length / 2); var spawnY = -1 - i * 2; enemy.currentCellX = spawnX; enemy.currentCellY = spawnY; enemy.cellX = spawnX; enemy.cellY = 5; enemy.waveNumber = currentWave; if (isBoss) { enemy.isBoss = true; } var healthMultiplier = Math.pow(1.12, currentWave); enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier); enemy.health = enemy.maxHealth; if (enemy.isFlying) { enemyLayerTop.addChild(enemy); if (enemy.shadow) { enemyLayerMiddle.addChild(enemy.shadow); } } else { enemyLayerBottom.addChild(enemy); } enemies.push(enemy); } } } else if (enemies.length === 0) { waveInProgress = false; currentWave++; if (currentWave > totalWaves) { LK.showYouWin(); } else { isBuildPhase = true; buildPhaseTimer = 60 * 10; } } } if (!isBuildPhase) { for (var a = enemies.length - 1; a >= 0; a--) { var enemy = enemies[a]; if (enemy.health <= 0) { enemiesKilled++; updateUI(); var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5); setGold(gold + goldEarned); game.addChild(new GoldIndicator(goldEarned, enemy.x, enemy.y)); for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) { enemy.bulletsTargetingThis[i].targetEnemy = null; } if (enemy.parent) { enemy.parent.removeChild(enemy); } if (enemy.shadow && enemy.shadow.parent) { enemy.shadow.parent.removeChild(enemy.shadow); } enemies.splice(a, 1); continue; } if (grid.updateEnemy(enemy)) { if (enemy.parent) { enemy.parent.removeChild(enemy); } if (enemy.shadow && enemy.shadow.parent) { enemy.shadow.parent.removeChild(enemy.shadow); } enemies.splice(a, 1); lives = Math.max(0, lives - 1); updateUI(); if (lives <= 0) { LK.showGameOver(); } } } for (var i = bullets.length - 1; i >= 0; i--) { if (!bullets[i].parent) { if (bullets[i].targetEnemy) { var targetEnemy = bullets[i].targetEnemy; var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]); if (bulletIndex !== -1) { targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1); } } bullets.splice(i, 1); } } } } if (placementPreview.visible) { var activeGrid = currentActiveView === 'gate' ? grid : castleGrid; placementPreview.updatePlacementStatus(activeGrid); } }; showTitleScreen();
===================================================================
--- original.js
+++ change.js
@@ -660,8 +660,208 @@
}
};
return self;
});
+var PlacementPreview = Container.expand(function () {
+ var self = Container.call(this);
+ self.itemType = 'tower'; // 'tower' or 'building'
+ self.subType = 'default';
+ self.itemSize = {
+ w: 2,
+ h: 2
+ }; // in cells
+ self.hasEnoughGold = true;
+ var rangeIndicator = new Container();
+ self.addChild(rangeIndicator);
+ var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ rangeGraphics.alpha = 0.3;
+ var previewGraphics = self.attachAsset('towerpreview', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.canPlace = false;
+ self.gridX = 0;
+ self.gridY = 0;
+ self.blockedByEnemy = false;
+ self.update = function () {
+ var cost = self.itemType === 'tower' ? getTowerCost(self.subType) : 100; // Placeholder for building cost
+ var previousHasEnoughGold = self.hasEnoughGold;
+ self.hasEnoughGold = gold >= cost;
+ if (previousHasEnoughGold !== self.hasEnoughGold) {
+ self.updateAppearance();
+ }
+ };
+ self.updateAppearance = function () {
+ previewGraphics.width = CELL_SIZE * self.itemSize.w;
+ previewGraphics.height = CELL_SIZE * self.itemSize.h;
+ rangeGraphics.visible = false;
+ var tint = 0xAAAAAA;
+ if (self.itemType === 'tower') {
+ var tempTower = new Tower(self.subType);
+ var previewRange = tempTower.getRange();
+ if (tempTower && tempTower.destroy) {
+ tempTower.destroy();
+ }
+ rangeGraphics.width = rangeGraphics.height = previewRange * 2;
+ rangeGraphics.visible = true;
+ switch (self.subType) {
+ case 'rapid':
+ tint = 0x00AAFF;
+ break;
+ case 'sniper':
+ tint = 0xFF5500;
+ break;
+ case 'splash':
+ tint = 0x33CC00;
+ break;
+ case 'slow':
+ tint = 0x9900FF;
+ break;
+ case 'poison':
+ tint = 0x00FFAA;
+ break;
+ }
+ } else {
+ // building
+ switch (self.subType) {
+ case 'home':
+ tint = 0xCCCCCC;
+ break;
+ case 'workshop':
+ tint = 0xD2691E;
+ break;
+ }
+ }
+ previewGraphics.tint = tint;
+ if (!self.canPlace || !self.hasEnoughGold) {
+ previewGraphics.tint = 0xFF0000;
+ }
+ };
+ self.updatePlacementStatus = function (targetGrid) {
+ var validGridPlacement = true;
+ var currentGrid = targetGrid || grid;
+ if (self.itemType === 'tower') {
+ if (self.gridY <= 4 || self.gridY + 1 >= currentGrid.cells[0].length - 4) {
+ validGridPlacement = false;
+ }
+ }
+ if (validGridPlacement) {
+ for (var i = 0; i < self.itemSize.w; i++) {
+ for (var j = 0; j < self.itemSize.h; j++) {
+ var cell = currentGrid.getCell(self.gridX + i, self.gridY + j);
+ if (!cell || cell.type !== 1) {
+ validGridPlacement = false;
+ break;
+ }
+ }
+ if (!validGridPlacement) {
+ break;
+ }
+ }
+ }
+ self.blockedByEnemy = false;
+ if (validGridPlacement && self.itemType === 'tower') {
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ if (enemy.currentCellY < 4) {
+ continue;
+ }
+ if (!enemy.isFlying) {
+ if (enemy.cellX >= self.gridX && enemy.cellX < self.gridX + self.itemSize.w && enemy.cellY >= self.gridY && enemy.cellY < self.gridY + self.itemSize.h) {
+ self.blockedByEnemy = true;
+ break;
+ }
+ if (enemy.currentTarget) {
+ var targetX = enemy.currentTarget.x;
+ var targetY = enemy.currentTarget.y;
+ if (targetX >= self.gridX && targetX < self.gridX + self.itemSize.w && targetY >= self.gridY && targetY < self.gridY + self.itemSize.h) {
+ self.blockedByEnemy = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ self.canPlace = validGridPlacement && !self.blockedByEnemy;
+ var cost = self.itemType === 'tower' ? getTowerCost(self.subType) : 100;
+ self.hasEnoughGold = gold >= cost;
+ self.updateAppearance();
+ };
+ self.snapToGrid = function (x, y, targetGrid) {
+ var currentGrid = targetGrid || grid;
+ var gridPosX = x - currentGrid.x;
+ var gridPosY = y - currentGrid.y;
+ self.gridX = Math.floor(gridPosX / CELL_SIZE);
+ self.gridY = Math.floor(gridPosY / CELL_SIZE);
+ self.x = currentGrid.x + self.gridX * CELL_SIZE + previewGraphics.width / 2;
+ self.y = currentGrid.y + self.gridY * CELL_SIZE + previewGraphics.height / 2;
+ self.updatePlacementStatus(currentGrid);
+ };
+ return self;
+});
+var SourceBuilding = Container.expand(function (buildingType) {
+ var self = Container.call(this);
+ self.buildingType = buildingType || 'default';
+ var baseGraphics = self.attachAsset('tower', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 1.3,
+ scaleY: 1.3
+ });
+ switch (self.buildingType) {
+ case 'home':
+ baseGraphics.tint = 0xAAAAAA;
+ break;
+ case 'workshop':
+ baseGraphics.tint = 0xD2691E;
+ break;
+ default:
+ baseGraphics.tint = 0xAAAAAA;
+ }
+ var initialCost = 100; // Placeholder
+ var typeLabelShadow = new Text2(self.buildingType.charAt(0).toUpperCase() + self.buildingType.slice(1), {
+ size: 50,
+ fill: 0x000000,
+ weight: 800
+ });
+ typeLabelShadow.anchor.set(0.5, 0.5);
+ typeLabelShadow.x = 4;
+ typeLabelShadow.y = -20 + 4;
+ self.addChild(typeLabelShadow);
+ var typeLabel = new Text2(self.buildingType.charAt(0).toUpperCase() + self.buildingType.slice(1), {
+ size: 50,
+ fill: 0xFFFFFF,
+ weight: 800
+ });
+ typeLabel.anchor.set(0.5, 0.5);
+ typeLabel.y = -20;
+ self.addChild(typeLabel);
+ var costLabelShadow = new Text2(initialCost, {
+ size: 50,
+ fill: 0x000000,
+ weight: 800
+ });
+ costLabelShadow.anchor.set(0.5, 0.5);
+ costLabelShadow.x = 4;
+ costLabelShadow.y = 24 + 12;
+ self.addChild(costLabelShadow);
+ var costLabel = new Text2(initialCost, {
+ size: 50,
+ fill: 0xFFD700,
+ weight: 800
+ });
+ costLabel.anchor.set(0.5, 0.5);
+ costLabel.y = 20 + 12;
+ self.addChild(costLabel);
+ self.update = function () {
+ var canAfford = true; // Placeholder
+ self.alpha = canAfford ? 1 : 0.5;
+ };
+ return self;
+});
var SourceTower = Container.expand(function (towerType) {
var self = Container.call(this);
self.towerType = towerType || 'default';
var baseGraphics = self.attachAsset('tower', {
@@ -928,131 +1128,8 @@
};
self.down = function (x, y, obj) {/* bez zmian */};
return self;
});
-var TowerPreview = Container.expand(function () {
- var self = Container.call(this);
- var towerRange = 3;
- var rangeInPixels = towerRange * CELL_SIZE;
- self.towerType = 'default';
- self.hasEnoughGold = true;
- var rangeIndicator = new Container();
- self.addChild(rangeIndicator);
- var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- rangeGraphics.alpha = 0.3;
- var previewGraphics = self.attachAsset('towerpreview', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- previewGraphics.width = CELL_SIZE * 2;
- previewGraphics.height = CELL_SIZE * 2;
- self.canPlace = false;
- self.gridX = 0;
- self.gridY = 0;
- self.blockedByEnemy = false;
- self.update = function () {
- var previousHasEnoughGold = self.hasEnoughGold;
- self.hasEnoughGold = gold >= getTowerCost(self.towerType);
- if (previousHasEnoughGold !== self.hasEnoughGold) {
- self.updateAppearance();
- }
- };
- self.updateAppearance = function () {
- var tempTower = new Tower(self.towerType);
- var previewRange = tempTower.getRange();
- if (tempTower && tempTower.destroy) {
- tempTower.destroy();
- }
- rangeGraphics.width = rangeGraphics.height = previewRange * 2;
- switch (self.towerType) {
- case 'rapid':
- previewGraphics.tint = 0x00AAFF;
- break;
- case 'sniper':
- previewGraphics.tint = 0xFF5500;
- break;
- case 'splash':
- previewGraphics.tint = 0x33CC00;
- break;
- case 'slow':
- previewGraphics.tint = 0x9900FF;
- break;
- case 'poison':
- previewGraphics.tint = 0x00FFAA;
- break;
- default:
- previewGraphics.tint = 0xAAAAAA;
- }
- if (!self.canPlace || !self.hasEnoughGold) {
- previewGraphics.tint = 0xFF0000;
- }
- };
- self.updatePlacementStatus = function () {
- var validGridPlacement = true;
- // Sprawdzamy, czy nie budujemy poza wyznaczonymi granicami
- if (self.gridY <= 4 || self.gridY + 1 >= grid.cells[0].length - 4) {
- validGridPlacement = false;
- } else {
- // Sprawdzamy, czy wszystkie 4 komórki są miejscem na budowę (type 1)
- for (var i = 0; i < 2; i++) {
- for (var j = 0; j < 2; j++) {
- var cell = grid.getCell(self.gridX + i, self.gridY + j);
- if (!cell || cell.type !== 1) {
- // ZMIANA: szukamy '1' zamiast '0'
- validGridPlacement = false;
- break;
- }
- }
- if (!validGridPlacement) {
- break;
- }
- }
- }
- // Logika sprawdzania wrogów pozostaje bez zmian
- self.blockedByEnemy = false;
- if (validGridPlacement) {
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- if (enemy.currentCellY < 4) {
- continue;
- }
- if (!enemy.isFlying) {
- if (enemy.cellX >= self.gridX && enemy.cellX < self.gridX + 2 && enemy.cellY >= self.gridY && enemy.cellY < self.gridY + 2) {
- self.blockedByEnemy = true;
- break;
- }
- if (enemy.currentTarget) {
- var targetX = enemy.currentTarget.x;
- var targetY = enemy.currentTarget.y;
- if (targetX >= self.gridX && targetX < self.gridX + 2 && targetY >= self.gridY && targetY < self.gridY + 2) {
- self.blockedByEnemy = true;
- break;
- }
- }
- }
- }
- }
- self.canPlace = validGridPlacement && !self.blockedByEnemy;
- self.hasEnoughGold = gold >= getTowerCost(self.towerType);
- self.updateAppearance();
- };
- self.checkPlacement = function () {
- self.updatePlacementStatus();
- };
- self.snapToGrid = function (x, y) {
- var gridPosX = x - grid.x;
- var gridPosY = y - grid.y;
- self.gridX = Math.floor(gridPosX / CELL_SIZE);
- self.gridY = Math.floor(gridPosY / CELL_SIZE);
- self.x = grid.x + self.gridX * CELL_SIZE + CELL_SIZE / 2;
- self.y = grid.y + self.gridY * CELL_SIZE + CELL_SIZE / 2;
- self.checkPlacement();
- };
- return self;
-});
var UpgradeMenu = Container.expand(function (tower) {
var self = Container.call(this);
self.tower = tower;
self.y = 2732 + 225;
@@ -1285,12 +1362,18 @@
var specialTilesLayer;
var enemyLayerBottom;
var enemyLayerMiddle;
var enemyLayerTop;
-var towerPreview;
+var placementPreview;
var buildPanelContainer;
var buildButton;
var isBuildPanelOpen;
+var currentActiveView;
+var gateContainer;
+var castleContainer;
+var viewToggleButton;
+var castleGrid;
+var castleBuildPanel;
// --- GŁÓWNE ELEMENTY UI ---
var goldText = new Text2('Gold: ' + 80, {
size: 60,
fill: 0xFFD700,
@@ -1506,36 +1589,45 @@
}
showTitleScreen();
};
}
-function toggleBuildPanel(forceState) {
+function toggleBuildPanel(panelOrState, stateOrPanel) {
+ var panel, forceState;
+ if (typeof panelOrState === 'string') {
+ forceState = panelOrState;
+ panel = stateOrPanel;
+ } else {
+ panel = panelOrState;
+ forceState = stateOrPanel;
+ }
var targetY;
var shouldBeOpen;
+ if (!panel) {
+ return;
+ }
if (forceState === 'open') {
shouldBeOpen = true;
} else if (forceState === 'close') {
shouldBeOpen = false;
} else {
shouldBeOpen = !isBuildPanelOpen;
}
if (shouldBeOpen) {
- targetY = 2732 - 250; // Pozycja panelu gdy jest otwarty
+ targetY = 2732 - 250;
isBuildPanelOpen = true;
} else {
- targetY = 2732 + 100; // Pozycja panelu gdy jest zamknięty (schowany)
+ targetY = 2732 + 100;
isBuildPanelOpen = false;
}
- tween(buildPanelContainer, {
+ tween(panel, {
y: targetY
}, {
duration: 300,
easing: tween.backOut
});
}
function startGame(levelNumber) {
- // --- CZYSZCZENIE EKRANU I INICJALIZACJA ---
console.log("Rozpoczynam ładowanie poziomu: " + levelNumber);
- game.addChildAt(LK.getAsset('map1', {}), 0);
if (titleScreenContainer) {
titleScreenContainer.destroy();
titleScreenContainer = null;
}
@@ -1546,55 +1638,30 @@
currentScreenState = 'gameplay';
if (LK.gui.top) {
LK.gui.top.visible = true;
}
- // --- WCZYTANIE DANYCH POZIOMU DO ZMIENNEJ GLOBALNEJ ---
+ gateContainer = new Container();
+ game.addChild(gateContainer);
+ castleContainer = new Container();
+ game.addChild(castleContainer);
+ castleContainer.visible = false;
+ currentActiveView = 'gate';
+ var castleMainBg = LK.getAsset('castle_bg_image', {});
+ castleContainer.addChildAt(castleMainBg, 0);
+ castleMainBg.x = -200;
+ gateContainer.addChild(LK.getAsset('map1', {
+ scaleMode: 'nearest'
+ }));
levelData = {
levelName: "Level 1: Royal Road",
initialGold: 100,
initialLives: 20,
mapLayout: ["22222222110S011222222222", "22222222AA00011222222222", "222222221100011222222222", "222222221100011222222222", "2222222211000AA222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "22222222110E011222222222"],
+ castleMapLayout: ["111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111", "111111111111"],
waves: [{
wave: 1,
type: 'normal',
count: 10
- }, {
- wave: 2,
- type: 'normal',
- count: 15
- }, {
- wave: 3,
- type: 'fast',
- count: 10
- }, {
- wave: 4,
- type: 'normal',
- count: 20
- }, {
- wave: 5,
- type: 'swarm',
- count: 30
- }, {
- wave: 6,
- type: 'normal',
- count: 10
- }, {
- wave: 7,
- type: 'fast',
- count: 15
- }, {
- wave: 8,
- type: 'immune',
- count: 10
- }, {
- wave: 9,
- type: 'flying',
- count: 10
- }, {
- wave: 10,
- type: 'normal',
- isBoss: true,
- count: 1
}],
specialTiles: []
};
pathId = 1;
@@ -1627,8 +1694,9 @@
updateUI();
debugLayer = new Container();
specialTilesLayer = new Container();
towerLayer = new Container();
+ buildableTilesLayer = new Container();
enemyLayerBottom = new Container();
enemyLayerMiddle = new Container();
enemyLayerTop = new Container();
enemyLayer = new Container();
@@ -1637,10 +1705,9 @@
enemyLayer.addChild(enemyLayerTop);
grid = new Grid(24, 29 + 6);
grid.x = 150;
grid.y = 200 - CELL_SIZE * 4;
- buildableTilesLayer = new Container();
- game.addChild(buildableTilesLayer);
+ gateContainer.addChild(buildableTilesLayer);
buildableTilesLayer.visible = false;
for (var y = 0; y < levelData.mapLayout.length; y++) {
for (var x = 0; x < levelData.mapLayout[y].length; x++) {
var tileChar = levelData.mapLayout[y][x];
@@ -1673,8 +1740,33 @@
}
}
}
}
+ castleGrid = new Grid(12, 12);
+ castleGrid.x = (2048 - 12 * CELL_SIZE) / 2;
+ castleGrid.y = (2732 - 12 * CELL_SIZE) / 2 - 200;
+ var castleBuildableTilesLayer = new Container();
+ castleContainer.addChild(castleBuildableTilesLayer);
+ for (var y = 0; y < levelData.castleMapLayout.length; y++) {
+ for (var x = 0; x < levelData.castleMapLayout[y].length; x++) {
+ var tileChar = levelData.castleMapLayout[y][x];
+ var cell = castleGrid.getCell(x, y);
+ if (cell) {
+ if (tileChar === '1') {
+ cell.type = 1;
+ var tilePlaceholder = castleBuildableTilesLayer.attachAsset('cell', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ tilePlaceholder.alpha = 0.25;
+ tilePlaceholder.x = castleGrid.x + x * CELL_SIZE + CELL_SIZE / 2;
+ tilePlaceholder.y = castleGrid.y + y * CELL_SIZE + CELL_SIZE / 2;
+ } else {
+ cell.type = 2;
+ }
+ }
+ }
+ }
levelData.specialTiles.forEach(function (tile) {
var cell = grid.getCell(tile.x, tile.y);
if (cell) {
cell.specialEffect = tile.type;
@@ -1692,17 +1784,16 @@
}
}
});
grid.pathFind();
- game.addChild(debugLayer);
- game.addChild(specialTilesLayer);
- game.addChild(towerLayer);
- game.addChild(enemyLayer);
- towerPreview = new TowerPreview();
- game.addChild(towerPreview);
- towerPreview.visible = false;
+ gateContainer.addChild(debugLayer);
+ gateContainer.addChild(specialTilesLayer);
+ gateContainer.addChild(towerLayer);
+ gateContainer.addChild(enemyLayer);
+ placementPreview = new PlacementPreview();
+ gateContainer.addChild(placementPreview);
+ placementPreview.visible = false;
var isDragging = false;
- // --- Logika Startu Gry i Fazy Budowy ---
startGameButton = new Container();
var startBuildingBg = startGameButton.attachAsset('notification', {
anchorX: 0.5,
anchorY: 0.5,
@@ -1718,34 +1809,17 @@
startBuildingText.anchor.set(0.5, 0.5);
startGameButton.addChild(startBuildingText);
startGameButton.x = 2048 / 2;
startGameButton.y = 2732 / 2;
- game.addChild(startGameButton);
+ gateContainer.addChild(startGameButton);
startGameButton.down = function () {
isBuildPhase = true;
buildPhaseTimer = 60 * 10;
timerText.visible = true;
startGameButton.destroy();
};
- function placeTower(gridX, gridY, towerType) {
- var towerCost = getTowerCost(towerType);
- if (gold >= towerCost) {
- var tower = new Tower(towerType || 'default');
- tower.placeOnGrid(gridX, gridY);
- towerLayer.addChild(tower);
- towers.push(tower);
- setGold(gold - towerCost);
- grid.pathFind();
- return true;
- } else {
- var notification = game.addChild(new Notification("Not enough gold!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 50;
- return false;
- }
- }
buildPanelContainer = new Container();
- game.addChild(buildPanelContainer);
+ gateContainer.addChild(buildPanelContainer);
buildPanelContainer.x = 2048 / 2;
buildPanelContainer.y = 2732 + 100;
var panelBackground = buildPanelContainer.attachAsset('notification', {
anchorX: 0.5,
@@ -1765,8 +1839,30 @@
tower.y = 0;
buildPanelContainer.addChild(tower);
sourceTowers.push(tower);
}
+ castleBuildPanel = new Container();
+ castleContainer.addChild(castleBuildPanel);
+ castleBuildPanel.x = 2048 / 2;
+ castleBuildPanel.y = 2732 + 100;
+ var castlePanelBackground = castleBuildPanel.attachAsset('notification', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 1800,
+ height: 400
+ });
+ castlePanelBackground.tint = 0x332211;
+ castlePanelBackground.alpha = 0.9;
+ var buildingTypes = ['home', 'workshop'];
+ var buildingIconSpacing = 280;
+ var totalBuildingWidth = (buildingTypes.length - 1) * buildingIconSpacing;
+ var buildingStartX = -totalBuildingWidth / 2;
+ for (var i = 0; i < buildingTypes.length; i++) {
+ var building = new SourceBuilding(buildingTypes[i]);
+ building.x = buildingStartX + i * buildingIconSpacing;
+ building.y = 0;
+ castleBuildPanel.addChild(building);
+ }
buildButton = new Container();
game.addChild(buildButton);
buildButton.x = 2048 / 2;
buildButton.y = 2732 - 100;
@@ -1784,76 +1880,163 @@
});
buildButtonText.anchor.set(0.5, 0.5);
buildButton.addChild(buildButtonText);
buildButton.down = function () {
- toggleBuildPanel();
+ if (currentActiveView === 'gate') {
+ toggleBuildPanel(buildPanelContainer);
+ } else {
+ toggleBuildPanel(castleBuildPanel);
+ }
};
+ viewToggleButton = new Container();
+ game.addChild(viewToggleButton);
+ viewToggleButton.x = 250;
+ viewToggleButton.y = 2732 - 100;
+ var viewToggleButtonBg = viewToggleButton.attachAsset('notification', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 300,
+ height: 120,
+ tint: 0x4466AA
+ });
+ var viewToggleButtonText = new Text2("Castle", {
+ size: 60,
+ fill: 0xFFFFFF,
+ weight: 800
+ });
+ viewToggleButtonText.anchor.set(0.5, 0.5);
+ viewToggleButton.addChild(viewToggleButtonText);
+ viewToggleButton.down = function () {
+ if (currentActiveView === 'gate') {
+ currentActiveView = 'castle';
+ viewToggleButtonText.setText("Gate");
+ gateContainer.visible = false;
+ castleContainer.visible = true;
+ } else {
+ currentActiveView = 'gate';
+ viewToggleButtonText.setText("Castle");
+ gateContainer.visible = true;
+ castleContainer.visible = false;
+ }
+ };
+ function placeTower(gridX, gridY, towerType) {
+ var towerCost = getTowerCost(towerType);
+ if (gold >= towerCost) {
+ var tower = new Tower(towerType || 'default');
+ tower.placeOnGrid(gridX, gridY);
+ towerLayer.addChild(tower);
+ towers.push(tower);
+ setGold(gold - towerCost);
+ grid.pathFind();
+ return true;
+ } else {
+ var notification = game.addChild(new Notification("Not enough gold!"));
+ notification.x = 2048 / 2;
+ notification.y = grid.height - 50;
+ return false;
+ }
+ }
game.down = function (x, y, obj) {
var buildButtonBounds = buildButton.getBounds();
if (buildButtonBounds.contains(x, y)) {
return;
}
+ var viewToggleButtonBounds = viewToggleButton.getBounds();
+ if (viewToggleButtonBounds.contains(x, y)) {
+ return;
+ }
var upgradeMenuVisible = game.children.some(function (child) {
return child instanceof UpgradeMenu;
});
if (upgradeMenuVisible) {
return;
}
if (isBuildPanelOpen) {
+ var activePanel = currentActiveView === 'gate' ? buildPanelContainer : castleBuildPanel;
var localClickPos = {
- x: x - buildPanelContainer.x,
- y: y - buildPanelContainer.y
+ x: x - activePanel.x,
+ y: y - activePanel.y
};
- var clickedOnSourceTower = false;
- for (var i = 0; i < sourceTowers.length; i++) {
- var tower = sourceTowers[i];
- var towerBounds = {
- left: tower.x - tower.width / 2,
- right: tower.x + tower.width / 2,
- top: tower.y - tower.height / 2,
- bottom: tower.y + tower.height / 2
+ var clickedOnSourceItem = false;
+ var sourceItems = currentActiveView === 'gate' ? sourceTowers : castleBuildPanel.children.filter(function (c) {
+ return c instanceof SourceBuilding;
+ });
+ for (var i = 0; i < sourceItems.length; i++) {
+ var item = sourceItems[i];
+ var itemBounds = {
+ left: item.x - item.width / 2,
+ right: item.x + item.width / 2,
+ top: item.y - item.height / 2,
+ bottom: item.y + item.height / 2
};
- if (localClickPos.x >= towerBounds.left && localClickPos.x <= towerBounds.right && localClickPos.y >= towerBounds.top && localClickPos.y <= towerBounds.bottom) {
- clickedOnSourceTower = true;
- if (gold < getTowerCost(tower.towerType)) {
- var notification = game.addChild(new Notification("Not enough gold!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 50;
- return;
- }
- towerPreview.visible = true;
+ if (localClickPos.x >= itemBounds.left && localClickPos.x <= itemBounds.right && localClickPos.y >= itemBounds.top && localClickPos.y <= itemBounds.bottom) {
+ clickedOnSourceItem = true;
isDragging = true;
- towerPreview.towerType = tower.towerType;
- towerPreview.updateAppearance();
- buildableTilesLayer.visible = true;
- towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
+ placementPreview.visible = true;
+ var activeGrid = currentActiveView === 'gate' ? grid : castleGrid;
+ var itemSubType;
+ if (currentActiveView === 'gate') {
+ placementPreview.itemType = 'tower';
+ itemSubType = item.towerType;
+ placementPreview.itemSize = {
+ w: 2,
+ h: 2
+ };
+ } else {
+ placementPreview.itemType = 'building';
+ itemSubType = item.buildingType;
+ if (itemSubType === 'home') {
+ placementPreview.itemSize = {
+ w: 2,
+ h: 2
+ };
+ }
+ if (itemSubType === 'workshop') {
+ placementPreview.itemSize = {
+ w: 4,
+ h: 2
+ };
+ }
+ }
+ placementPreview.subType = itemSubType;
+ placementPreview.updateAppearance();
+ if (currentActiveView === 'gate') {
+ buildableTilesLayer.visible = true;
+ }
+ var yOffset = currentActiveView === 'gate' ? CELL_SIZE * 1.5 : 0;
+ placementPreview.snapToGrid(x, y - yOffset, activeGrid);
return;
}
}
- if (!clickedOnSourceTower) {
- toggleBuildPanel('close');
+ if (!clickedOnSourceItem) {
+ var targetPanel = currentActiveView === 'gate' ? buildPanelContainer : castleBuildPanel;
+ toggleBuildPanel(targetPanel, 'close');
}
}
};
game.move = function (x, y, obj) {
if (isDragging) {
- towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
+ var activeGrid = currentActiveView === 'gate' ? grid : castleGrid;
+ var yOffset = currentActiveView === 'gate' ? CELL_SIZE * 1.5 : 0;
+ placementPreview.snapToGrid(x, y - yOffset, activeGrid);
}
};
game.up = function (x, y, obj) {
if (isDragging) {
isDragging = false;
- buildableTilesLayer.visible = false;
- if (towerPreview.canPlace) {
- // Usunęliśmy sprawdzanie blokowania, bo już nie jest potrzebne
- placeTower(towerPreview.gridX, towerPreview.gridY, towerPreview.towerType);
- } else if (towerPreview.blockedByEnemy) {
- var notification = game.addChild(new Notification("Cannot build: Enemy in the way!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 50;
+ placementPreview.visible = false;
+ if (currentActiveView === 'gate') {
+ buildableTilesLayer.visible = false;
+ if (placementPreview.canPlace) {
+ placeTower(placementPreview.gridX, placementPreview.gridY, placementPreview.subType);
+ }
+ } else {
+ if (placementPreview.canPlace) {
+ console.log("Placing building:", placementPreview.subType, "at", placementPreview.gridX, placementPreview.gridY);
+ }
}
- towerPreview.visible = false;
- toggleBuildPanel('close');
+ var targetPanel = currentActiveView === 'gate' ? buildPanelContainer : castleBuildPanel;
+ toggleBuildPanel(targetPanel, 'close');
} else {
var clickedOnTower = false;
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
@@ -1894,117 +2077,120 @@
game.update = function () {
if (currentScreenState !== 'gameplay') {
return;
}
- if (isBuildPhase) {
- if (buildPhaseTimer > 0) {
- buildPhaseTimer--;
- timerText.setText("Build Time: " + Math.ceil(buildPhaseTimer / 60));
- } else {
- isBuildPhase = false;
- timerText.visible = false;
- waveInProgress = true;
- waveSpawned = false;
- }
- } else if (waveInProgress) {
- if (!waveSpawned) {
- waveSpawned = true;
- enemiesKilled = 0;
- var waveData = levelData.waves[currentWave - 1];
- if (waveData) {
- var enemyCount = waveData.count;
- var waveType = waveData.type;
- var isBoss = waveData.isBoss || false;
- enemiesInCurrentWave = enemyCount;
- updateUI();
- for (var i = 0; i < enemyCount; i++) {
- var enemy = new Enemy(waveType);
- var spawnPoints = grid.spawns;
- var spawnX = spawnPoints && spawnPoints.length > 0 ? spawnPoints[Math.floor(Math.random() * spawnPoints.length)].x : Math.floor(grid.cells.length / 2);
- var spawnY = -1 - i * 2;
- enemy.currentCellX = spawnX;
- enemy.currentCellY = spawnY;
- enemy.cellX = spawnX;
- enemy.cellY = 5;
- enemy.waveNumber = currentWave;
- if (isBoss) {
- enemy.isBoss = true;
- }
- var healthMultiplier = Math.pow(1.12, currentWave);
- enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
- enemy.health = enemy.maxHealth;
- if (enemy.isFlying) {
- enemyLayerTop.addChild(enemy);
- if (enemy.shadow) {
- enemyLayerMiddle.addChild(enemy.shadow);
+ if (currentActiveView === 'gate') {
+ if (isBuildPhase) {
+ if (buildPhaseTimer > 0) {
+ buildPhaseTimer--;
+ timerText.setText("Build Time: " + Math.ceil(buildPhaseTimer / 60));
+ } else {
+ isBuildPhase = false;
+ timerText.visible = false;
+ waveInProgress = true;
+ waveSpawned = false;
+ }
+ } else if (waveInProgress) {
+ if (!waveSpawned) {
+ waveSpawned = true;
+ enemiesKilled = 0;
+ var waveData = levelData.waves[currentWave - 1];
+ if (waveData) {
+ var enemyCount = waveData.count;
+ var waveType = waveData.type;
+ var isBoss = waveData.isBoss || false;
+ enemiesInCurrentWave = enemyCount;
+ updateUI();
+ for (var i = 0; i < enemyCount; i++) {
+ var enemy = new Enemy(waveType);
+ var spawnPoints = grid.spawns;
+ var spawnX = spawnPoints && spawnPoints.length > 0 ? spawnPoints[Math.floor(Math.random() * spawnPoints.length)].x : Math.floor(grid.cells.length / 2);
+ var spawnY = -1 - i * 2;
+ enemy.currentCellX = spawnX;
+ enemy.currentCellY = spawnY;
+ enemy.cellX = spawnX;
+ enemy.cellY = 5;
+ enemy.waveNumber = currentWave;
+ if (isBoss) {
+ enemy.isBoss = true;
}
- } else {
- enemyLayerBottom.addChild(enemy);
+ var healthMultiplier = Math.pow(1.12, currentWave);
+ enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
+ enemy.health = enemy.maxHealth;
+ if (enemy.isFlying) {
+ enemyLayerTop.addChild(enemy);
+ if (enemy.shadow) {
+ enemyLayerMiddle.addChild(enemy.shadow);
+ }
+ } else {
+ enemyLayerBottom.addChild(enemy);
+ }
+ enemies.push(enemy);
}
- enemies.push(enemy);
}
+ } else if (enemies.length === 0) {
+ waveInProgress = false;
+ currentWave++;
+ if (currentWave > totalWaves) {
+ LK.showYouWin();
+ } else {
+ isBuildPhase = true;
+ buildPhaseTimer = 60 * 10;
+ }
}
- } else if (enemies.length === 0) {
- waveInProgress = false;
- currentWave++;
- if (currentWave > totalWaves) {
- LK.showYouWin();
- } else {
- isBuildPhase = true;
- buildPhaseTimer = 60 * 10;
- }
}
- }
- if (!isBuildPhase) {
- for (var a = enemies.length - 1; a >= 0; a--) {
- var enemy = enemies[a];
- if (enemy.health <= 0) {
- enemiesKilled++;
- updateUI();
- var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
- setGold(gold + goldEarned);
- game.addChild(new GoldIndicator(goldEarned, enemy.x, enemy.y));
- for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
- enemy.bulletsTargetingThis[i].targetEnemy = null;
+ if (!isBuildPhase) {
+ for (var a = enemies.length - 1; a >= 0; a--) {
+ var enemy = enemies[a];
+ if (enemy.health <= 0) {
+ enemiesKilled++;
+ updateUI();
+ var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
+ setGold(gold + goldEarned);
+ game.addChild(new GoldIndicator(goldEarned, enemy.x, enemy.y));
+ for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
+ enemy.bulletsTargetingThis[i].targetEnemy = null;
+ }
+ if (enemy.parent) {
+ enemy.parent.removeChild(enemy);
+ }
+ if (enemy.shadow && enemy.shadow.parent) {
+ enemy.shadow.parent.removeChild(enemy.shadow);
+ }
+ enemies.splice(a, 1);
+ continue;
}
- if (enemy.parent) {
- enemy.parent.removeChild(enemy);
+ if (grid.updateEnemy(enemy)) {
+ if (enemy.parent) {
+ enemy.parent.removeChild(enemy);
+ }
+ if (enemy.shadow && enemy.shadow.parent) {
+ enemy.shadow.parent.removeChild(enemy.shadow);
+ }
+ enemies.splice(a, 1);
+ lives = Math.max(0, lives - 1);
+ updateUI();
+ if (lives <= 0) {
+ LK.showGameOver();
+ }
}
- if (enemy.shadow && enemy.shadow.parent) {
- enemy.shadow.parent.removeChild(enemy.shadow);
- }
- enemies.splice(a, 1);
- continue;
}
- if (grid.updateEnemy(enemy)) {
- if (enemy.parent) {
- enemy.parent.removeChild(enemy);
- }
- if (enemy.shadow && enemy.shadow.parent) {
- enemy.shadow.parent.removeChild(enemy.shadow);
- }
- enemies.splice(a, 1);
- lives = Math.max(0, lives - 1);
- updateUI();
- if (lives <= 0) {
- LK.showGameOver();
- }
- }
- }
- for (var i = bullets.length - 1; i >= 0; i--) {
- if (!bullets[i].parent) {
- if (bullets[i].targetEnemy) {
- var targetEnemy = bullets[i].targetEnemy;
- var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
- if (bulletIndex !== -1) {
- targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ if (!bullets[i].parent) {
+ if (bullets[i].targetEnemy) {
+ var targetEnemy = bullets[i].targetEnemy;
+ var bulletIndex = targetEnemy.bulletsTargetingThis.indexOf(bullets[i]);
+ if (bulletIndex !== -1) {
+ targetEnemy.bulletsTargetingThis.splice(bulletIndex, 1);
+ }
}
+ bullets.splice(i, 1);
}
- bullets.splice(i, 1);
}
}
}
- if (towerPreview.visible) {
- towerPreview.checkPlacement();
+ if (placementPreview.visible) {
+ var activeGrid = currentActiveView === 'gate' ? grid : castleGrid;
+ placementPreview.updatePlacementStatus(activeGrid);
}
};
showTitleScreen();
\ No newline at end of file