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
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 ****/ var Building = Container.expand(function (id, size) { var self = Container.call(this); self.id = id || 'default'; self.size = size || { w: 2, h: 2 }; var baseGraphics = self.attachAsset('towerpreview', { anchorX: 0, anchorY: 0 }); baseGraphics.width = CELL_SIZE * self.size.w; baseGraphics.height = CELL_SIZE * self.size.h; switch (self.id) { case 'home': baseGraphics.tint = 0xAAAAAA; break; case 'workshop': baseGraphics.tint = 0xD2691E; break; case 'magic_academy': baseGraphics.tint = 0x9400D3; break; default: baseGraphics.tint = 0xAAAAAA; } return self; }); /**** * Classes ****/ var Bullet = Container.expand(function (startX, startY, targetEnemy, towerProps) { var self = Container.call(this); self.targetEnemy = targetEnemy; self.props = towerProps; // Przekazujemy właściwości wieży (obrażenia, prędkość, typ itp.) self.x = startX; self.y = startY; var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); if (self.props.bulletType === 'splash') { bulletGraphics.tint = 0xFF8C00; } if (self.props.bulletType === 'slow') { bulletGraphics.tint = 0xADD8E6; } if (self.props.bulletType === 'chain') { bulletGraphics.tint = 0xFFFF00; } self.update = function () { if (!self.targetEnemy || !self.targetEnemy.parent || self.targetEnemy.health <= 0) { 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.props.bulletSpeed) { // --- LOGIKA TRAFIENIA --- self.targetEnemy.health -= self.props.damage; self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70; switch (self.props.bulletType) { case 'slow': self.targetEnemy.slowDuration = self.props.slowDuration; break; case 'splash': game.addChild(new EffectIndicator(self.x, self.y, 'splash')); enemies.forEach(function (enemy) { if (enemy !== self.targetEnemy) { var distToSplash = Math.sqrt(Math.pow(self.targetEnemy.x - enemy.x, 2) + Math.pow(self.targetEnemy.y - enemy.y, 2)); if (distToSplash < self.props.splashRadius) { enemy.health -= self.props.splashDamage; enemy.healthBar.width = enemy.health / enemy.maxHealth * 70; } } }); break; case 'chain': var chainedTargets = [self.targetEnemy]; var lastTarget = self.targetEnemy; var damage = self.props.damage; for (var i = 0; i < self.props.chainTargets; i++) { damage -= self.props.chainDamageFalloff; if (damage <= 0) { break; } var nextTarget = null; var minChainDist = Infinity; enemies.forEach(function (enemy) { if (!chainedTargets.includes(enemy)) { var distToChain = Math.sqrt(Math.pow(lastTarget.x - enemy.x, 2) + Math.pow(lastTarget.y - enemy.y, 2)); if (distToChain < self.props.range / 2 && distToChain < minChainDist) { minChainDist = distToChain; nextTarget = enemy; } } }); if (nextTarget) { nextTarget.health -= damage; nextTarget.healthBar.width = nextTarget.health / nextTarget.maxHealth * 70; chainedTargets.push(nextTarget); lastTarget = nextTarget; } else { break; } } break; } self.destroy(); } else { var angle = Math.atan2(dy, dx); self.x += Math.cos(angle) * self.props.bulletSpeed; self.y += Math.sin(angle) * self.props.bulletSpeed; } }; 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.originalSpeed = self.speed; self.slowed = false; self.slowDuration = 0; 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; self.manaCategory = 'strong'; switch (self.type) { case 'fast': self.speed *= 2; self.maxHealth = 100; self.manaCategory = 'strong'; break; case 'immune': self.isImmune = true; self.maxHealth = 80; self.manaCategory = 'special'; break; case 'flying': self.isFlying = true; self.maxHealth = 80; self.manaCategory = 'special'; break; case 'swarm': self.maxHealth = 50; self.manaCategory = 'weak'; break; case 'normal': default: self.manaCategory = 'strong'; break; } self.originalSpeed = self.speed; if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') { self.isBoss = true; self.maxHealth *= 20; self.speed *= 0.7; self.originalSpeed = self.speed; self.manaCategory = 'boss'; } self.health = self.maxHealth; var assetId = self.type === 'normal' ? 'enemy' : '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) { if (self.slowDuration > 0) { self.slowDuration--; if (!self.slowed) { self.slowed = true; self.speed *= 1 - TOWER_DATA.mage['2W'].slowAmount; enemyGraphics.tint = 0x99CCFF; } } else if (self.slowed) { self.slowed = false; self.speed = self.originalSpeed; 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); enemyGraphics.rotation = angle; } } 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 = 'guard'; 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; function getCost() { var cost = 0; if (self.itemType === 'tower' && TOWER_DATA[self.subType]) { cost = TOWER_DATA[self.subType][1].cost; if (!isBuildPhase && currentWave > 0) { cost = Math.floor(cost * 1.5); } } else if (self.itemType === 'building') { // Logika kosztu budynków } return cost; } self.update = function () { var cost = getCost(); 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 stats = TOWER_DATA[self.subType] ? TOWER_DATA[self.subType][1] : null; if (stats) { var previewRange = stats.range; rangeGraphics.width = rangeGraphics.height = previewRange * 2; rangeGraphics.visible = true; // TODO: Zmienić assety w zależności od typu wieży, na razie tylko tint switch (self.subType) { case 'guard': tint = 0xCCCCCC; break; case 'crossbow': tint = 0xD2691E; break; case 'mage': tint = 0x0000FF; break; case 'banner': tint = 0xFFFF00; break; } } } else { // logika dla budynków } previewGraphics.tint = tint; if (!self.canPlace || !self.hasEnoughGold) { previewGraphics.tint = 0xFF0000; } }; self.updatePlacementStatus = function (targetGrid) { var validGridPlacement = true; var currentGrid = targetGrid || grid; 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; // Sprawdzanie kolizji z wrogami zostaje bez zmian self.canPlace = validGridPlacement && !self.blockedByEnemy; self.hasEnoughGold = gold >= getCost(); 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 currentCost = getBuildingCost(self.buildingType); if (costLabel.text !== currentCost.gold) { costLabel.setText(currentCost.gold); costLabelShadow.setText(currentCost.gold); } var canAfford = gold >= currentCost.gold; 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 }); // TODO: Zmienić assety w zależności od typu wieży, na razie tylko tint switch (self.towerType) { case 'guard': baseGraphics.tint = 0xCCCCCC; break; case 'crossbow': baseGraphics.tint = 0xD2691E; break; case 'mage': baseGraphics.tint = 0x0000FF; break; case 'banner': baseGraphics.tint = 0xFFFF00; break; default: baseGraphics.tint = 0xAAAAAA; break; } var stats = TOWER_DATA[self.towerType][1]; // Pobierz dane dla poziomu 1 var towerName = stats.name; var initialCost = stats.cost; var typeLabelShadow = new Text2(towerName, { size: 40, fill: 0x000000, weight: 800 }); typeLabelShadow.anchor.set(0.5, 0.5); typeLabelShadow.x = 2; typeLabelShadow.y = -20 + 2; self.addChild(typeLabelShadow); var typeLabel = new Text2(towerName, { size: 40, 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 () { // Ta funkcja będzie aktualizować koszt w przyszłości, gdy wprowadzimy dynamiczne zmiany var currentCost = TOWER_DATA[self.towerType][1].cost; if (!isBuildPhase && currentWave > 0) { currentCost = Math.floor(currentCost * 1.5); } 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 (towerType) { var self = Container.call(this); self.towerType = towerType; self.level = 1; self.levelPath = ''; self.maxLevel = 3; self.gridX = 0; self.gridY = 0; self.targetEnemy = null; self.lastFired = 0; self.totalValue = 0; self.baseStats = {}; self.buffs = []; self.towersInAura = []; function applyStats(stats) { self.baseStats = Object.assign({}, stats); // Kopiowanie wszystkich właściwości ze stats do self Object.assign(self, stats); self.recalculateStats(); } self.recalculateStats = function () { self.damage = self.baseStats.damage; self.fireRate = self.baseStats.fireRate; self.buffs.forEach(function (buff) { if (buff.effect.damage) { self.damage *= buff.effect.damage; } if (buff.effect.attackSpeed) { self.fireRate /= buff.effect.attackSpeed; } }); }; self.addBuff = function (buff) { if (!self.buffs.find(function (b) { return b.source === buff.source; })) { self.buffs.push(buff); self.recalculateStats(); } }; self.removeBuff = function (buffSource) { self.buffs = self.buffs.filter(function (b) { return b.source !== buffSource; }); self.recalculateStats(); }; var initialStats = TOWER_DATA[self.towerType][self.level]; self.cost = initialStats.cost; self.totalValue = self.cost; applyStats(initialStats); var baseGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); baseGraphics.width = CELL_SIZE * 2; baseGraphics.height = CELL_SIZE * 2; switch (self.towerType) { case 'guard': baseGraphics.tint = 0xCCCCCC; break; case 'crossbow': baseGraphics.tint = 0xD2691E; break; case 'mage': baseGraphics.tint = 0x0000FF; break; case 'banner': baseGraphics.tint = 0xFFFF00; break; } var gunContainer = new Container(); self.addChild(gunContainer); var gunGraphics = gunContainer.attachAsset('defense', { anchorX: 0.5, anchorY: 0.5 }); if (self.towerType === 'banner') { gunContainer.visible = false; } self.getRange = function () { return self.range; }; self.getTotalValue = function () { return self.totalValue; }; self.upgrade = function (path) { path = path || ''; var nextLevelKey = self.level + 1 + path; var upgradeData = TOWER_DATA[self.towerType][nextLevelKey]; if (!upgradeData) { return; } if (self.aura) { self.removeAuraFromTowers(); } self.level++; self.levelPath = path; self.totalValue += upgradeData.cost; applyStats(upgradeData); if (self.aura) { self.applyAuraToTowers(); } }; self.destroyAura = function () { if (self.aura) { self.removeAuraFromTowers(); } }; 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; 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; } } } if (self.aura) { self.applyAuraToTowers(); } }; self.findTarget = function () { if (self.damage === 0) { return null; } if (self.bulletType === 'slow') { var potentialTargets = []; enemies.forEach(function (enemy) { if (!enemy.slowed) { var dx = enemy.x - self.x; var dy = enemy.y - self.y; if (dx * dx + dy * dy < self.range * self.range) { potentialTargets.push(enemy); } } }); if (potentialTargets.length === 0) { // Jeśli wszyscy są spowolnieni, wybierz dowolnego enemies.forEach(function (enemy) { var dx = enemy.x - self.x; var dy = enemy.y - self.y; if (dx * dx + dy * dy < self.range * self.range) { potentialTargets.push(enemy); } }); } if (potentialTargets.length > 0) { return potentialTargets[Math.floor(Math.random() * potentialTargets.length)]; } } var closestEnemy = null; var minDistance = self.range * self.range; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distanceSq = dx * dx + dy * dy; if (distanceSq < minDistance) { minDistance = distanceSq; closestEnemy = enemy; } } return closestEnemy; }; 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); game.addChild(bullet); bullets.push(bullet); } }; self.applyAuraToTowers = function () { self.removeAuraFromTowers(); towers.forEach(function (tower) { if (tower === self) { return; } var dx = tower.x - self.x; var dy = tower.y - self.y; if (dx * dx + dy * dy < self.range * self.range) { tower.addBuff({ source: self, effect: self.aura }); self.towersInAura.push(tower); } }); }; self.removeAuraFromTowers = function () { self.towersInAura.forEach(function (tower) { tower.removeBuff(self); }); self.towersInAura = []; }; self.update = function () { if (self.aura) { return; } if (self.buffs.length > 0) { gunGraphics.alpha = 0.7 + Math.sin(LK.ticks / 10) * 0.3; } else { gunGraphics.alpha = 1; } 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 (self.fireRate > 0 && LK.ticks - self.lastFired >= self.fireRate) { self.fire(); self.lastFired = LK.ticks; } } }; self.down = function (x, y, obj) { if (isMenuTransitioning) { return; } // Sprawdź blokadę na samym początku if (selectedTower === self) { closeActiveUpgradeMenu(); return; } closeActiveUpgradeMenu(); selectedTower = self; var upgradeMenu = game.addChild(new UpgradeMenu(self)); upgradeMenu.x = 2048 / 2; // Ustawiamy blokadę na czas animacji wysuwania isMenuTransitioning = true; tween(upgradeMenu, { y: 2732 - 250 }, { duration: 200, easing: tween.backOut, onFinish: function onFinish() { isMenuTransitioning = false; // Wyłącz blokadę po zakończeniu } }); var rangeCircle = new Container(); rangeCircle.isTowerRange = true; rangeCircle.tower = self; var graphics = rangeCircle.attachAsset('rangeCircle', { anchorX: 0.5, anchorY: 0.5 }); graphics.width = graphics.height = self.getRange() * 2; graphics.alpha = 0.2; graphics.tint = 0xFFFFFF; rangeCircle.x = self.x; rangeCircle.y = self.y; gateContainer.addChildAt(rangeCircle, gateContainer.children.indexOf(towerLayer)); }; 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.name, { size: 80, fill: 0xFFFFFF, weight: 800 }); towerTypeText.anchor.set(0, 0); towerTypeText.x = -840; towerTypeText.y = -160; self.addChild(towerTypeText); function getTowerFireRate() { if (self.tower.fireRate > 0) { return (60 / self.tower.fireRate).toFixed(1) + '/s'; } return 'N/A'; } var statsText = new Text2('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + getTowerFireRate(), { size: 70, fill: 0xFFFFFF, weight: 400 }); statsText.anchor.set(0, 0.5); statsText.x = -840; statsText.y = 50; self.addChild(statsText); var sellButton = new Container(); var sellButtonBackground = sellButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 400, height: 120, tint: 0xCC0000 }); var sellValue = getTowerSellValue(self.tower.getTotalValue()); var sellButtonText = new Text2('Sell: +' + sellValue, { size: 50, fill: 0xFFFFFF, weight: 800 }); sellButtonText.anchor.set(0.5, 0.5); sellButton.addChild(sellButtonText); sellButton.x = 650; sellButton.y = 120; self.addChild(sellButton); sellButton.down = function () { // NOWA LINIA - usuwa aurę przed zniszczeniem wieży if (self.tower.aura) { self.tower.destroyAura(); } setGold(gold + getTowerSellValue(self.tower.getTotalValue())); 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); } towerLayer.removeChild(self.tower); hideUpgradeMenu(self); }; var closeButton = new Container(); var closeBackground = closeButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 90, height: 90, 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; self.addChild(closeButton); closeButton.down = function () { hideUpgradeMenu(self); }; function createUpgradeButton(upgradeKey, position, totalButtons) { var upgradeData = TOWER_DATA[self.tower.towerType][upgradeKey]; if (!upgradeData) { return; } var button = new Container(); var bg = button.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5 }); bg.width = 450; bg.height = 180 / totalButtons + 60 / totalButtons; var buttonTextContent = 'Upgrade: ' + upgradeData.cost + 'g'; if (upgradeData.name) { buttonTextContent = upgradeData.name + '\n' + upgradeData.cost + 'g'; if (upgradeData.description) { buttonTextContent += '\n' + upgradeData.description; } } var text = new Text2(buttonTextContent, { size: 40, fill: 0xFFFFFF, weight: 800, align: 'center' }); text.anchor.set(0.5, 0.5); button.addChild(text); var canAfford = gold >= upgradeData.cost; bg.tint = canAfford ? 0x00AA00 : 0x888888; button.alpha = canAfford ? 1 : 0.7; button.down = function () { if (gold >= upgradeData.cost) { setGold(gold - upgradeData.cost); self.tower.upgrade(upgradeKey.replace((self.tower.level + 1).toString(), '')); // Przekaż ścieżkę 'A' lub 'B' hideUpgradeMenu(self); } else { var notification = game.addChild(new Notification("Not enough gold!")); notification.x = 2048 / 2; notification.y = grid.height - 50; } }; button.x = position.x; button.y = position.y; self.addChild(button); } function populateUpgradeButtons() { if (self.tower.level >= self.tower.maxLevel) { var maxLevelText = new Text2('Max Level', { size: 80, fill: 0xFFD700, weight: 800 }); maxLevelText.anchor.set(0.5, 0.5); maxLevelText.x = 50; self.addChild(maxLevelText); return; } var nextLevel = self.tower.level + 1; var upgradeKeys = Object.keys(TOWER_DATA[self.tower.towerType]).filter(function (key) { return key.startsWith(nextLevel.toString()); }); if (upgradeKeys.length === 1) { createUpgradeButton(upgradeKeys[0], { x: 50, y: 0 }, 1); } else if (upgradeKeys.length > 1) { for (var i = 0; i < upgradeKeys.length; i++) { var yPos = -85 + i * 170; createUpgradeButton(upgradeKeys[i], { x: 50, y: yPos }, upgradeKeys.length); } } } populateUpgradeButtons(); self.update = function () { // Ta funkcja jest teraz pusta, cała logika dzieje się przy tworzeniu. // Można ją rozbudować o dynamiczne odświeżanie, jeśli będzie taka potrzeba. }; // Nadpisanie funkcji, aby poprawnie ukrywała też okrąg zasięgu var originalDestroy = self.destroy; self.destroy = function () { for (var i = game.children.length - 1; i >= 0; i--) { if (game.children[i].isTowerRange && game.children[i].tower === self.tower) { game.removeChild(game.children[i]); } } if (selectedTower === self.tower) { selectedTower = null; } originalDestroy.call(self); }; return self; }); /**** * Initialize Game ****/ /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x333333 }); /**** * Game Code ****/ /**** * Game Code ****/ var CELL_SIZE = 76; var TOWER_DATA = { 'guard': { 1: { name: 'Guard Tower', cost: 30, damage: 4, fireRate: 60, range: 4 * CELL_SIZE, bulletSpeed: 7 }, 2: { name: 'Veteran Guard', cost: 60, damage: 8, fireRate: 60, range: 4 * CELL_SIZE, bulletSpeed: 7 } }, 'crossbow': { 1: { name: 'Crossbow Tower', cost: 50, damage: 12, fireRate: 150, range: 7 * CELL_SIZE, bulletSpeed: 15 }, 2: { name: 'Heavy Crossbow', cost: 100, damage: 24, fireRate: 150, range: 7 * CELL_SIZE, bulletSpeed: 15 } }, 'mage': { 1: { name: 'Mage Tower', cost: 40, damage: 6, fireRate: 90, range: 4 * CELL_SIZE, bulletSpeed: 8, bulletType: 'normal' }, '2F': { name: 'Fire Mage', cost: 80, damage: 6, fireRate: 120, range: 5 * CELL_SIZE, bulletSpeed: 8, bulletType: 'splash', splashDamage: 3, splashRadius: 1 * CELL_SIZE }, '2W': { name: 'Water Mage', cost: 80, damage: 4, fireRate: 120, range: 5 * CELL_SIZE, bulletSpeed: 8, bulletType: 'slow', slowAmount: 0.6, slowDuration: 120 }, '2L': { name: 'Lightning Mage', cost: 80, damage: 7, fireRate: 150, range: 6 * CELL_SIZE, bulletSpeed: 20, bulletType: 'chain', chainTargets: 2, chainDamageFalloff: 2 } }, 'banner': { 1: { name: 'War Banner', cost: 50, damage: 0, range: 4 * CELL_SIZE, aura: { 'attackSpeed': 1.15 } }, '2A': { name: 'Banner of Fury', cost: 100, range: 4 * CELL_SIZE, aura: { 'attackSpeed': 1.30 } }, '2B': { name: 'Banner of Command', cost: 100, range: 4 * CELL_SIZE, aura: { 'attackSpeed': 1.15, 'damage': 1.15 } } } }; var isBuildPhase = false; var buildPhaseTimer = 0; var startGameButton; var timerText; var pathId; var buildingDeck; var buildingHand; var castleBuildings; var castleBuildingsLayer; var maxScore; var enemies; var towers; var bullets; var selectedTower; var gold; var lives; var mana; var isManaUnlocked; 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; 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 manaText = new Text2('Mana: 0', { size: 60, fill: 0x00BFFF, weight: 800 }); manaText.anchor.set(0.5, 0.5); manaText.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); LK.gui.top.addChild(manaText); 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; manaText.x = -spacing * 2 - 100; manaText.y = topMargin; var currentScreenState = ''; var titleScreenContainer = null; var levelSelectContainer = null; var isHidingUpgradeMenu = false; var isMenuTransitioning = false; function hideUpgradeMenu(menu) { if (isHidingUpgradeMenu) { return; } isHidingUpgradeMenu = true; isMenuTransitioning = true; tween(menu, { y: 2732 + 225 }, { duration: 150, easing: tween.easeIn, onFinish: function onFinish() { menu.destroy(); isHidingUpgradeMenu = false; isMenuTransitioning = false; } }); } function closeActiveUpgradeMenu() { if (isMenuTransitioning) { return; } game.children.forEach(function (child) { if (child instanceof UpgradeMenu) { hideUpgradeMenu(child); } }); for (var i = gateContainer.children.length - 1; i >= 0; i--) { if (gateContainer.children[i].isTowerRange) { gateContainer.removeChild(gateContainer.children[i]); } } selectedTower = null; } function updateUI() { goldText.setText('Gold: ' + gold); livesText.setText('Lives: ' + lives); enemiesText.setText('Enemies: ' + enemiesKilled + '/' + enemiesInCurrentWave); if (isManaUnlocked) { manaText.setText('Mana: ' + mana); } if (wavesText) { wavesText.setText('Wave: ' + currentWave + '/' + totalWaves); } } function setGold(value) { gold = value; updateUI(); } function setMana(value) { if (isManaUnlocked) { mana = value; updateUI(); } } function getTowerCost(towerType) { var cost = 0; if (TOWER_DATA[towerType] && TOWER_DATA[towerType][1]) { cost = TOWER_DATA[towerType][1].cost; } if (!isBuildPhase && currentWave > 0) { cost = Math.floor(cost * 1.5); } return cost; } function getTowerSellValue(totalValue) { return Math.floor(totalValue * 0.6); } function getBuildingCost(buildingType) { var count = 0; for (var i = 0; i < castleBuildings.length; i++) { if (castleBuildings[i].id === buildingType) { count++; } } var baseCost = { gold: 0, people: 0 }; switch (buildingType) { case 'home': baseCost.gold = 100; break; case 'workshop': baseCost.gold = 250; break; case 'magic_academy': baseCost.gold = 300; break; } var finalCost = { gold: Math.floor(baseCost.gold * Math.pow(1.2, count)), people: baseCost.people }; return finalCost; } // --- 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(); castleBuildingsLayer = new Container(); castleContainer.addChild(castleBuildingsLayer); game.addChild(castleContainer); castleContainer.visible = false; currentActiveView = 'gate'; var castleMainBg = LK.getAsset('castle_bg_image', {}); castleContainer.addChildAt(castleMainBg, 0); castleMainBg.x = -100; gateContainer.addChild(LK.getAsset('map1', { scaleMode: 'nearest' })); var castleGridWidth = 16; var castleGridHeight = 15; var tempCastleLayout = []; for (var h = 0; h < castleGridHeight; h++) { tempCastleLayout.push("1".repeat(castleGridWidth)); } 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: tempCastleLayout, waves: [{ wave: 1, type: 'normal', count: 10 }], specialTiles: [] }; pathId = 1; maxScore = 0; enemies = []; towers = []; bullets = []; selectedTower = null; gold = levelData.initialGold; castleBuildings = []; lives = levelData.initialLives; mana = 0; isManaUnlocked = false; enemiesKilled = 0; enemiesInCurrentWave = 0; currentWave = 1; totalWaves = levelData.waves.length; waveInProgress = false; waveSpawned = false; waveTimer = 0; nextWaveTime = 1200; sourceTowers = []; isBuildPanelOpen = false; people = 5; maxPeople = 5; 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; peopleText = new Text2('People: 5/5', { size: 60, fill: 0xADD8E6, weight: 800 }); peopleText.anchor.set(0.5, 0.5); LK.gui.top.addChild(peopleText); peopleText.x = -spacing * 2; peopleText.y = topMargin; 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(castleGridWidth, castleGridHeight); castleGrid.x = (2048 - castleGridWidth * CELL_SIZE) / 2 - 122; castleGrid.y = (2732 - castleGridHeight * CELL_SIZE) / 2 + 170; 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); 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 towerIconSpacing = 280; var towerTypes = ['guard', 'crossbow', 'mage', 'banner']; 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; buildButton = new Container(); buildingDeck = ['home', 'workshop', 'smithy', 'marketplace', 'magic_academy', 'tavern']; buildingHand = []; drawNewBuildingHand(); var rerollButton = new Container(); rerollButton.x = 2048 - 250; rerollButton.y = 2732 - 100; game.addChild(rerollButton); var rerollButtonBg = rerollButton.attachAsset('notification', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 120, tint: 0xCC0000 }); var rerollButtonText = new Text2("Re-roll", { size: 60, fill: 0xFFFFFF, weight: 800 }); rerollButtonText.anchor.set(0.5, 0.5); rerollButton.addChild(rerollButtonText); rerollButton.down = function () { if (currentActiveView === 'castle') { drawNewBuildingHand(); } }; 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; } }; placementPreview = new PlacementPreview(); game.addChild(placementPreview); placementPreview.visible = false; } 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); } } 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); if (isManaUnlocked) { var manaEarned = 0; switch (enemy.manaCategory) { case 'weak': manaEarned = 1; break; case 'strong': manaEarned = 2; break; case 'special': manaEarned = 5; break; case 'boss': manaEarned = 25; break; } setMana(mana + manaEarned); } 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
@@ -25,54 +25,101 @@
break;
case 'workshop':
baseGraphics.tint = 0xD2691E;
break;
+ case 'magic_academy':
+ baseGraphics.tint = 0x9400D3;
+ break;
default:
baseGraphics.tint = 0xAAAAAA;
}
return self;
});
/**** * Classes
****/
-var Bullet = Container.expand(function (startX, startY, targetEnemy, damage, speed) {
+var Bullet = Container.expand(function (startX, startY, targetEnemy, towerProps) {
var self = Container.call(this);
self.targetEnemy = targetEnemy;
- self.damage = damage || 10;
- self.speed = speed || 5;
+ self.props = towerProps; // Przekazujemy właściwości wieży (obrażenia, prędkość, typ itp.)
self.x = startX;
self.y = startY;
- self.isCatalyzed = false; // Nowa właściwość
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
+ if (self.props.bulletType === 'splash') {
+ bulletGraphics.tint = 0xFF8C00;
+ }
+ if (self.props.bulletType === 'slow') {
+ bulletGraphics.tint = 0xADD8E6;
+ }
+ if (self.props.bulletType === 'chain') {
+ bulletGraphics.tint = 0xFFFF00;
+ }
self.update = function () {
- if (!self.targetEnemy || !self.targetEnemy.parent) {
+ if (!self.targetEnemy || !self.targetEnemy.parent || self.targetEnemy.health <= 0) {
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;
+ if (distance < self.props.bulletSpeed) {
+ // --- LOGIKA TRAFIENIA ---
+ self.targetEnemy.health -= self.props.damage;
+ self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70;
+ switch (self.props.bulletType) {
+ case 'slow':
+ self.targetEnemy.slowDuration = self.props.slowDuration;
+ break;
+ case 'splash':
+ game.addChild(new EffectIndicator(self.x, self.y, 'splash'));
+ enemies.forEach(function (enemy) {
+ if (enemy !== self.targetEnemy) {
+ var distToSplash = Math.sqrt(Math.pow(self.targetEnemy.x - enemy.x, 2) + Math.pow(self.targetEnemy.y - enemy.y, 2));
+ if (distToSplash < self.props.splashRadius) {
+ enemy.health -= self.props.splashDamage;
+ enemy.healthBar.width = enemy.health / enemy.maxHealth * 70;
+ }
+ }
+ });
+ break;
+ case 'chain':
+ var chainedTargets = [self.targetEnemy];
+ var lastTarget = self.targetEnemy;
+ var damage = self.props.damage;
+ for (var i = 0; i < self.props.chainTargets; i++) {
+ damage -= self.props.chainDamageFalloff;
+ if (damage <= 0) {
+ break;
+ }
+ var nextTarget = null;
+ var minChainDist = Infinity;
+ enemies.forEach(function (enemy) {
+ if (!chainedTargets.includes(enemy)) {
+ var distToChain = Math.sqrt(Math.pow(lastTarget.x - enemy.x, 2) + Math.pow(lastTarget.y - enemy.y, 2));
+ if (distToChain < self.props.range / 2 && distToChain < minChainDist) {
+ minChainDist = distToChain;
+ nextTarget = enemy;
+ }
+ }
+ });
+ if (nextTarget) {
+ nextTarget.health -= damage;
+ nextTarget.healthBar.width = nextTarget.health / nextTarget.maxHealth * 70;
+ chainedTargets.push(nextTarget);
+ lastTarget = nextTarget;
+ } else {
+ break;
+ }
+ }
+ break;
}
- // 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;
+ self.x += Math.cos(angle) * self.props.bulletSpeed;
+ self.y += Math.sin(angle) * self.props.bulletSpeed;
}
};
return self;
});
@@ -224,8 +271,11 @@
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'normal';
self.speed = .01;
+ self.originalSpeed = self.speed;
+ self.slowed = false;
+ self.slowDuration = 0;
self.cellX = 0;
self.cellY = 0;
self.currentCellX = 0;
self.currentCellY = 0;
@@ -236,38 +286,44 @@
self.waveNumber = currentWave;
self.isFlying = false;
self.isImmune = false;
self.isBoss = false;
+ self.manaCategory = 'strong';
switch (self.type) {
case 'fast':
self.speed *= 2;
self.maxHealth = 100;
+ self.manaCategory = 'strong';
break;
case 'immune':
self.isImmune = true;
self.maxHealth = 80;
+ self.manaCategory = 'special';
break;
case 'flying':
self.isFlying = true;
self.maxHealth = 80;
+ self.manaCategory = 'special';
break;
case 'swarm':
self.maxHealth = 50;
+ self.manaCategory = 'weak';
break;
case 'normal':
default:
+ self.manaCategory = 'strong';
break;
}
+ self.originalSpeed = self.speed;
if (currentWave % 10 === 0 && currentWave > 0 && type !== 'swarm') {
self.isBoss = true;
self.maxHealth *= 20;
- self.speed = self.speed * 0.7;
+ self.speed *= 0.7;
+ self.originalSpeed = self.speed;
+ self.manaCategory = 'boss';
}
self.health = self.maxHealth;
- var assetId = 'enemy';
- if (self.type !== 'normal') {
- assetId = 'enemy_' + self.type;
- }
+ var assetId = self.type === 'normal' ? 'enemy' : 'enemy_' + self.type;
var enemyGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
@@ -313,93 +369,28 @@
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;
- }
+ if (!self.isImmune) {
+ if (self.slowDuration > 0) {
self.slowDuration--;
- if (self.slowDuration <= 0) {
- self.speed = self.originalSpeed;
- self.slowed = false;
- self.slowEffect = false;
- if (!self.poisoned) {
- enemyGraphics.tint = 0xFFFFFF;
- }
+ if (!self.slowed) {
+ self.slowed = true;
+ self.speed *= 1 - TOWER_DATA.mage['2W'].slowAmount;
+ enemyGraphics.tint = 0x99CCFF;
}
+ } else if (self.slowed) {
+ self.slowed = false;
+ self.speed = self.originalSpeed;
+ 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
- });
- }
- }
+ enemyGraphics.rotation = angle;
}
}
healthBarOutline.y = healthBarBG.y = healthBar.y = -enemyGraphics.height / 2 - 10;
};
@@ -951,47 +942,36 @@
var self = Container.call(this);
self.towerType = towerType;
self.level = 1;
self.levelPath = '';
- self.maxLevel = 2;
+ self.maxLevel = 3;
self.gridX = 0;
self.gridY = 0;
self.targetEnemy = null;
self.lastFired = 0;
self.totalValue = 0;
- // --- NOWA LOGIKA AUR I BUFFÓW ---
- self.baseStats = {}; // Przechowuje statystyki bez modyfikatorów
- self.buffs = []; // Lista aktywnych buffów na tej wieży
- self.towersInAura = []; // Lista wież, które TEN sztandar wzmacnia
+ self.baseStats = {};
+ self.buffs = [];
+ self.towersInAura = [];
function applyStats(stats) {
- self.baseStats = Object.assign({}, stats); // Kopiujemy statystyki jako bazowe
- self.cost = stats.cost;
- self.damage = stats.damage;
- self.fireRate = stats.fireRate;
- self.range = stats.range;
- self.bulletSpeed = stats.bulletSpeed;
- self.aura = stats.aura;
- self.name = stats.name;
+ self.baseStats = Object.assign({}, stats);
+ // Kopiowanie wszystkich właściwości ze stats do self
+ Object.assign(self, stats);
self.recalculateStats();
}
self.recalculateStats = function () {
- // Reset do statystyk bazowych
self.damage = self.baseStats.damage;
self.fireRate = self.baseStats.fireRate;
- // ... inne statystyki w przyszłości
- // Aplikuj wszystkie aktywne buffy
self.buffs.forEach(function (buff) {
if (buff.effect.damage) {
self.damage *= buff.effect.damage;
}
if (buff.effect.attackSpeed) {
- // Mniejsza wartość fireRate oznacza szybszy atak
self.fireRate /= buff.effect.attackSpeed;
}
});
};
self.addBuff = function (buff) {
- // Zapobiegaj kumulowaniu się buffów z tego samego źródła
if (!self.buffs.find(function (b) {
return b.source === buff.source;
})) {
self.buffs.push(buff);
@@ -1003,12 +983,12 @@
return b.source !== buffSource;
});
self.recalculateStats();
};
- // --- KONIEC LOGIKI AUR ---
var initialStats = TOWER_DATA[self.towerType][self.level];
- applyStats(initialStats);
+ self.cost = initialStats.cost;
self.totalValue = self.cost;
+ applyStats(initialStats);
var baseGraphics = self.attachAsset('tower', {
anchorX: 0.5,
anchorY: 0.5
});
@@ -1044,22 +1024,28 @@
return self.totalValue;
};
self.upgrade = function (path) {
path = path || '';
- var nextLevel = self.level + 1;
- var upgradeData = TOWER_DATA[self.towerType][nextLevel + path];
- if (!upgradeData) return;
- // Usuń stary buff przed ulepszeniem sztandaru
- if (self.aura) self.removeAuraFromTowers();
- self.level = nextLevel;
+ var nextLevelKey = self.level + 1 + path;
+ var upgradeData = TOWER_DATA[self.towerType][nextLevelKey];
+ if (!upgradeData) {
+ return;
+ }
+ if (self.aura) {
+ self.removeAuraFromTowers();
+ }
+ self.level++;
self.levelPath = path;
self.totalValue += upgradeData.cost;
applyStats(upgradeData);
- // Aplikuj nowy buff po ulepszeniu sztandaru
- if (self.aura) self.applyAuraToTowers();
+ if (self.aura) {
+ self.applyAuraToTowers();
+ }
};
self.destroyAura = function () {
- if (self.aura) self.removeAuraFromTowers();
+ if (self.aura) {
+ self.removeAuraFromTowers();
+ }
};
self.placeOnGrid = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
@@ -1067,17 +1053,46 @@
self.y = grid.y + (gridY + 1) * CELL_SIZE;
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;
+ if (cell) {
+ cell.type = 5;
+ }
}
}
if (self.aura) {
self.applyAuraToTowers();
}
};
self.findTarget = function () {
- if (self.damage === 0) return null;
+ if (self.damage === 0) {
+ return null;
+ }
+ if (self.bulletType === 'slow') {
+ var potentialTargets = [];
+ enemies.forEach(function (enemy) {
+ if (!enemy.slowed) {
+ var dx = enemy.x - self.x;
+ var dy = enemy.y - self.y;
+ if (dx * dx + dy * dy < self.range * self.range) {
+ potentialTargets.push(enemy);
+ }
+ }
+ });
+ if (potentialTargets.length === 0) {
+ // Jeśli wszyscy są spowolnieni, wybierz dowolnego
+ enemies.forEach(function (enemy) {
+ var dx = enemy.x - self.x;
+ var dy = enemy.y - self.y;
+ if (dx * dx + dy * dy < self.range * self.range) {
+ potentialTargets.push(enemy);
+ }
+ });
+ }
+ if (potentialTargets.length > 0) {
+ return potentialTargets[Math.floor(Math.random() * potentialTargets.length)];
+ }
+ }
var closestEnemy = null;
var minDistance = self.range * self.range;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
@@ -1094,17 +1109,19 @@
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);
+ var bullet = new Bullet(bulletX, bulletY, self.targetEnemy, self);
game.addChild(bullet);
bullets.push(bullet);
}
};
self.applyAuraToTowers = function () {
- self.removeAuraFromTowers(); // Upewnij się, że stara aura jest usunięta
+ self.removeAuraFromTowers();
towers.forEach(function (tower) {
- if (tower === self) return; // Sztandar nie buffuje sam siebie
+ if (tower === self) {
+ return;
+ }
var dx = tower.x - self.x;
var dy = tower.y - self.y;
if (dx * dx + dy * dy < self.range * self.range) {
tower.addBuff({
@@ -1121,14 +1138,11 @@
});
self.towersInAura = [];
};
self.update = function () {
- // Logika aury dla sztandaru
if (self.aura) {
- // Można dodać tu cykliczne skanowanie, jeśli wieże będą się ruszać
return;
}
- // Wizualizacja buffa
if (self.buffs.length > 0) {
gunGraphics.alpha = 0.7 + Math.sin(LK.ticks / 10) * 0.3;
} else {
gunGraphics.alpha = 1;
@@ -1145,20 +1159,29 @@
}
}
};
self.down = function (x, y, obj) {
- if (selectedTower === self) return;
- game.children.forEach(function (child) {
- if (child instanceof UpgradeMenu) hideUpgradeMenu(child);
- });
+ if (isMenuTransitioning) {
+ return;
+ } // Sprawdź blokadę na samym początku
+ if (selectedTower === self) {
+ closeActiveUpgradeMenu();
+ return;
+ }
+ closeActiveUpgradeMenu();
selectedTower = self;
var upgradeMenu = game.addChild(new UpgradeMenu(self));
upgradeMenu.x = 2048 / 2;
+ // Ustawiamy blokadę na czas animacji wysuwania
+ isMenuTransitioning = true;
tween(upgradeMenu, {
y: 2732 - 250
}, {
duration: 200,
- easing: tween.backOut
+ easing: tween.backOut,
+ onFinish: function onFinish() {
+ isMenuTransitioning = false; // Wyłącz blokadę po zakończeniu
+ }
});
var rangeCircle = new Container();
rangeCircle.isTowerRange = true;
rangeCircle.tower = self;
@@ -1230,9 +1253,12 @@
sellButton.x = 650;
sellButton.y = 120;
self.addChild(sellButton);
sellButton.down = function () {
- // Logika sprzedaży
+ // NOWA LINIA - usuwa aurę przed zniszczeniem wieży
+ if (self.tower.aura) {
+ self.tower.destroyAura();
+ }
setGold(gold + getTowerSellValue(self.tower.getTotalValue()));
var gridX = self.tower.gridX;
var gridY = self.tower.gridY;
for (var i = 0; i < 2; i++) {
@@ -1386,9 +1412,8 @@
****/
/**** * Game Code
****/
var CELL_SIZE = 76;
-// --- GŁÓWNE ZMIENNE STANU GRY ---
var TOWER_DATA = {
'guard': {
1: {
name: 'Guard Tower',
@@ -1405,9 +1430,8 @@
fireRate: 60,
range: 4 * CELL_SIZE,
bulletSpeed: 7
}
- // Poziom 3 dodamy w przyszłości
},
'crossbow': {
1: {
name: 'Crossbow Tower',
@@ -1432,11 +1456,44 @@
cost: 40,
damage: 6,
fireRate: 90,
range: 4 * CELL_SIZE,
- bulletSpeed: 8
+ bulletSpeed: 8,
+ bulletType: 'normal'
+ },
+ '2F': {
+ name: 'Fire Mage',
+ cost: 80,
+ damage: 6,
+ fireRate: 120,
+ range: 5 * CELL_SIZE,
+ bulletSpeed: 8,
+ bulletType: 'splash',
+ splashDamage: 3,
+ splashRadius: 1 * CELL_SIZE
+ },
+ '2W': {
+ name: 'Water Mage',
+ cost: 80,
+ damage: 4,
+ fireRate: 120,
+ range: 5 * CELL_SIZE,
+ bulletSpeed: 8,
+ bulletType: 'slow',
+ slowAmount: 0.6,
+ slowDuration: 120
+ },
+ '2L': {
+ name: 'Lightning Mage',
+ cost: 80,
+ damage: 7,
+ fireRate: 150,
+ range: 6 * CELL_SIZE,
+ bulletSpeed: 20,
+ bulletType: 'chain',
+ chainTargets: 2,
+ chainDamageFalloff: 2
}
- // Ulepszenia dla maga dodamy później
},
'banner': {
1: {
name: 'War Banner',
@@ -1446,33 +1503,30 @@
aura: {
'attackSpeed': 1.15
}
},
- // Rozgałęzione ulepszenia dla Sztandaru
'2A': {
name: 'Banner of Fury',
cost: 100,
range: 4 * CELL_SIZE,
aura: {
'attackSpeed': 1.30
- },
- description: "+30% Szybkości Ataku"
+ }
},
'2B': {
name: 'Banner of Command',
cost: 100,
range: 4 * CELL_SIZE,
aura: {
'attackSpeed': 1.15,
'damage': 1.15
- },
- description: "+15% Szyb. Ataku i +15% Obrażeń"
+ }
}
}
};
var isBuildPhase = false;
-var buildPhaseTimer = 0; // Timer do odliczania
-var startGameButton; // Przycisk "Start building"
+var buildPhaseTimer = 0;
+var startGameButton;
var timerText;
var pathId;
var buildingDeck;
var buildingHand;
@@ -1484,8 +1538,10 @@
var bullets;
var selectedTower;
var gold;
var lives;
+var mana;
+var isManaUnlocked;
var enemiesKilled;
var enemiesInCurrentWave;
var levelData;
var currentWave;
@@ -1514,9 +1570,8 @@
var castleContainer;
var viewToggleButton;
var castleGrid;
var castleBuildPanel;
-// --- GŁÓWNE ELEMENTY UI ---
var goldText = new Text2('Gold: ' + 80, {
size: 60,
fill: 0xFFD700,
weight: 800
@@ -1540,57 +1595,93 @@
weight: 700
});
timerText.anchor.set(0.5, 0.5);
timerText.visible = false;
+var manaText = new Text2('Mana: 0', {
+ size: 60,
+ fill: 0x00BFFF,
+ weight: 800
+});
+manaText.anchor.set(0.5, 0.5);
+manaText.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);
+LK.gui.top.addChild(manaText);
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 ---
+manaText.x = -spacing * 2 - 100;
+manaText.y = topMargin;
var currentScreenState = '';
var titleScreenContainer = null;
var levelSelectContainer = null;
-// --- GLOBALNE FUNKCJE POMOCNICZE ---
var isHidingUpgradeMenu = false;
+var isMenuTransitioning = false;
function hideUpgradeMenu(menu) {
if (isHidingUpgradeMenu) {
return;
}
isHidingUpgradeMenu = true;
+ isMenuTransitioning = true;
tween(menu, {
y: 2732 + 225
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
menu.destroy();
isHidingUpgradeMenu = false;
+ isMenuTransitioning = false;
}
});
}
+function closeActiveUpgradeMenu() {
+ if (isMenuTransitioning) {
+ return;
+ }
+ game.children.forEach(function (child) {
+ if (child instanceof UpgradeMenu) {
+ hideUpgradeMenu(child);
+ }
+ });
+ for (var i = gateContainer.children.length - 1; i >= 0; i--) {
+ if (gateContainer.children[i].isTowerRange) {
+ gateContainer.removeChild(gateContainer.children[i]);
+ }
+ }
+ selectedTower = null;
+}
function updateUI() {
goldText.setText('Gold: ' + gold);
livesText.setText('Lives: ' + lives);
enemiesText.setText('Enemies: ' + enemiesKilled + '/' + enemiesInCurrentWave);
+ if (isManaUnlocked) {
+ manaText.setText('Mana: ' + mana);
+ }
if (wavesText) {
wavesText.setText('Wave: ' + currentWave + '/' + totalWaves);
}
}
function setGold(value) {
gold = value;
updateUI();
}
+function setMana(value) {
+ if (isManaUnlocked) {
+ mana = value;
+ updateUI();
+ }
+}
function getTowerCost(towerType) {
var cost = 0;
if (TOWER_DATA[towerType] && TOWER_DATA[towerType][1]) {
cost = TOWER_DATA[towerType][1].cost;
@@ -1620,8 +1711,11 @@
break;
case 'workshop':
baseCost.gold = 250;
break;
+ case 'magic_academy':
+ baseCost.gold = 300;
+ break;
}
var finalCost = {
gold: Math.floor(baseCost.gold * Math.pow(1.2, count)),
people: baseCost.people
@@ -1832,8 +1926,10 @@
selectedTower = null;
gold = levelData.initialGold;
castleBuildings = [];
lives = levelData.initialLives;
+ mana = 0;
+ isManaUnlocked = false;
enemiesKilled = 0;
enemiesInCurrentWave = 0;
currentWave = 1;
totalWaves = levelData.waves.length;
@@ -2045,9 +2141,8 @@
rerollButtonText.anchor.set(0.5, 0.5);
rerollButton.addChild(rerollButtonText);
rerollButton.down = function () {
if (currentActiveView === 'castle') {
- // Na razie re-roll jest darmowy, koszt dodamy później
drawNewBuildingHand();
}
};
game.addChild(buildButton);
@@ -2107,241 +2202,8 @@
};
placementPreview = new PlacementPreview();
game.addChild(placementPreview);
placementPreview.visible = false;
- function placeBuilding(buildingType, gridX, gridY) {
- var cost = getBuildingCost(buildingType);
- var buildingSize = {
- w: 2,
- h: 2
- };
- if (buildingType === 'workshop') {
- buildingSize = {
- w: 4,
- h: 2
- };
- }
- // Tutaj w przyszłości dodamy inne rozmiary dla innych budynków
- if (gold >= cost.gold) {
- setGold(gold - cost.gold);
- var newBuilding = new Building(buildingType, buildingSize);
- newBuilding.x = castleGrid.x + gridX * CELL_SIZE;
- newBuilding.y = castleGrid.y + gridY * CELL_SIZE;
- castleBuildingsLayer.addChild(newBuilding);
- castleBuildings.push(newBuilding);
- for (var i = 0; i < buildingSize.w; i++) {
- for (var j = 0; j < buildingSize.h; j++) {
- var cell = castleGrid.getCell(gridX + i, gridY + j);
- if (cell) {
- cell.type = 5;
- }
- }
- }
- if (buildingType === 'home') {
- maxPeople += 5;
- updateUI();
- }
- var handIndex = buildingHand.indexOf(buildingType);
- if (handIndex > -1) {
- buildingHand.splice(handIndex, 1);
- }
- for (var i = castleBuildPanel.children.length - 1; i >= 0; i--) {
- var child = castleBuildPanel.children[i];
- if (child.buildingType === buildingType) {
- child.destroy();
- break;
- }
- }
- if (buildingHand.length === 0) {
- drawNewBuildingHand();
- }
- return true;
- } else {
- var notification = game.addChild(new Notification("Not enough gold!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 50;
- return false;
- }
- }
- function drawNewBuildingHand() {
- while (castleBuildPanel.children.length > 1) {
- castleBuildPanel.removeChildAt(1);
- }
- buildingHand = [];
- var availableBuildings = buildingDeck.slice();
- for (var i = 0; i < 3; i++) {
- if (availableBuildings.length === 0) {
- break;
- }
- var randomIndex = Math.floor(Math.random() * availableBuildings.length);
- var drawnBuilding = availableBuildings.splice(randomIndex, 1)[0];
- buildingHand.push(drawnBuilding);
- }
- var buildingIconSpacing = 280;
- var totalBuildingWidth = (buildingHand.length - 1) * buildingIconSpacing;
- var buildingStartX = -totalBuildingWidth / 2;
- for (var i = 0; i < buildingHand.length; i++) {
- var building = new SourceBuilding(buildingHand[i]);
- building.x = buildingStartX + i * buildingIconSpacing;
- building.y = 0;
- castleBuildPanel.addChild(building);
- }
- }
- 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) {
- placeBuilding(placementPreview.subType, 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;
@@ -2412,8 +2274,26 @@
enemiesKilled++;
updateUI();
var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
setGold(gold + goldEarned);
+ if (isManaUnlocked) {
+ var manaEarned = 0;
+ switch (enemy.manaCategory) {
+ case 'weak':
+ manaEarned = 1;
+ break;
+ case 'strong':
+ manaEarned = 2;
+ break;
+ case 'special':
+ manaEarned = 5;
+ break;
+ case 'boss':
+ manaEarned = 25;
+ break;
+ }
+ setMana(mana + manaEarned);
+ }
game.addChild(new GoldIndicator(goldEarned, enemy.x, enemy.y));
for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
enemy.bulletsTargetingThis[i].targetEnemy = null;
}