/**** * 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; 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; if (self.targetEnemy.health <= 0) { self.targetEnemy.health = 0; } else { self.targetEnemy.healthBar.width = self.targetEnemy.health / self.targetEnemy.maxHealth * 70; } if (self.type === 'splash') { var splashEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'splash'); game.addChild(splashEffect); var splashRadius = CELL_SIZE * 1.5; for (var i = 0; i < enemies.length; i++) { var otherEnemy = enemies[i]; if (otherEnemy !== self.targetEnemy) { var splashDx = otherEnemy.x - self.targetEnemy.x; var splashDy = otherEnemy.y - self.targetEnemy.y; var splashDistance = Math.sqrt(splashDx * splashDx + splashDy * splashDy); if (splashDistance <= splashRadius) { otherEnemy.health -= self.damage * 0.5; if (otherEnemy.health <= 0) { otherEnemy.health = 0; } else { otherEnemy.healthBar.width = otherEnemy.health / otherEnemy.maxHealth * 70; } } } } } else if (self.type === 'slow') { if (!self.targetEnemy.isImmune) { var slowEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'slow'); game.addChild(slowEffect); var slowPct = 0.5; if (self.sourceTowerLevel !== undefined) { var slowLevels = [0.5, 0.6, 0.65, 0.7, 0.75, 0.8]; var idx = Math.max(0, Math.min(5, self.sourceTowerLevel - 1)); slowPct = slowLevels[idx]; } if (!self.targetEnemy.slowed) { self.targetEnemy.originalSpeed = self.targetEnemy.speed; self.targetEnemy.speed *= 1 - slowPct; self.targetEnemy.slowed = true; self.targetEnemy.slowDuration = 180; } else { self.targetEnemy.slowDuration = 180; } } } else if (self.type === 'poison') { if (!self.targetEnemy.isImmune) { var poisonEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'poison'); game.addChild(poisonEffect); self.targetEnemy.poisoned = true; self.targetEnemy.poisonDamage = self.damage * 0.2; self.targetEnemy.poisonDuration = 300; } } else if (self.type === 'sniper') { var sniperEffect = new EffectIndicator(self.targetEnemy.x, self.targetEnemy.y, 'sniper'); game.addChild(sniperEffect); } 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 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 towerCost = 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(towerCost, { 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(towerCost, { 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 = gold >= getTowerCost(self.towerType); 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.range = 3 * CELL_SIZE; self.getRange = function () { switch (self.id) { case 'sniper': if (self.level === self.maxLevel) { return 12 * CELL_SIZE; } return (5 + (self.level - 1) * 0.8) * CELL_SIZE; case 'splash': return (2 + (self.level - 1) * 0.2) * CELL_SIZE; case 'rapid': return (2.5 + (self.level - 1) * 0.5) * CELL_SIZE; case 'slow': return (3.5 + (self.level - 1) * 0.5) * CELL_SIZE; case 'poison': return (3.2 + (self.level - 1) * 0.5) * CELL_SIZE; default: return (3 + (self.level - 1) * 0.5) * CELL_SIZE; } }; self.cellsInRange = []; self.fireRate = 60; self.bulletSpeed = 5; self.damage = 10; self.lastFired = 0; self.targetEnemy = null; switch (self.id) { case 'rapid': self.fireRate = 30; self.damage = 5; self.range = 2.5 * CELL_SIZE; self.bulletSpeed = 7; break; case 'sniper': self.fireRate = 90; self.damage = 25; self.range = 5 * CELL_SIZE; self.bulletSpeed = 25; break; case 'splash': self.fireRate = 75; self.damage = 15; self.range = 2 * CELL_SIZE; self.bulletSpeed = 4; break; case 'slow': self.fireRate = 50; self.damage = 8; self.range = 3.5 * CELL_SIZE; self.bulletSpeed = 5; break; case 'poison': self.fireRate = 70; self.damage = 12; self.range = 3.2 * CELL_SIZE; self.bulletSpeed = 5; break; } 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 () { for (var i = 0; i < maxDots; i++) { var dot = levelIndicators[i]; var towerLevelIndicator = dot.children[1]; if (i < self.level) { towerLevelIndicator.tint = 0xFFFFFF; } else { switch (self.id) { case 'rapid': towerLevelIndicator.tint = 0x00AAFF; break; case 'sniper': towerLevelIndicator.tint = 0xFF5500; break; case 'splash': towerLevelIndicator.tint = 0x33CC00; break; case 'slow': towerLevelIndicator.tint = 0x9900FF; break; case 'poison': towerLevelIndicator.tint = 0x00FFAA; break; default: towerLevelIndicator.tint = 0xAAAAAA; } } } }; self.updateLevelIndicators(); self.refreshCellsInRange = function () { for (var i = 0; i < self.cellsInRange.length; i++) { var cell = self.cellsInRange[i]; var towerIndex = cell.towersInRange.indexOf(self); if (towerIndex !== -1) { cell.towersInRange.splice(towerIndex, 1); } } self.cellsInRange = []; var rangeRadius = self.getRange() / CELL_SIZE; var centerX = self.gridX + 1; var centerY = self.gridY + 1; var minI = Math.floor(centerX - rangeRadius - 0.5); var maxI = Math.ceil(centerX + rangeRadius + 0.5); var minJ = Math.floor(centerY - rangeRadius - 0.5); var maxJ = Math.ceil(centerY + rangeRadius + 0.5); for (var i = minI; i <= maxI; i++) { for (var j = minJ; j <= maxJ; j++) { var closestX = Math.max(i, Math.min(centerX, i + 1)); var closestY = Math.max(j, Math.min(centerY, j + 1)); var deltaX = closestX - centerX; var deltaY = closestY - centerY; var distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared <= rangeRadius * rangeRadius) { var cell = grid.getCell(i, j); if (cell) { self.cellsInRange.push(cell); cell.towersInRange.push(self); } } } } grid.renderDebug(); }; self.getTotalValue = function () { var baseTowerCost = getTowerCost(self.id); var totalInvestment = baseTowerCost; var baseUpgradeCost = baseTowerCost; for (var i = 1; i < self.level; i++) { totalInvestment += Math.floor(baseUpgradeCost * Math.pow(2, i - 1)); } return totalInvestment; }; self.upgrade = function () { if (self.level < self.maxLevel) { var baseUpgradeCost = getTowerCost(self.id); var upgradeCost; if (self.level === self.maxLevel - 1) { upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.level - 1) * 3.5 / 2); } else { upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.level - 1)); } if (gold >= upgradeCost) { setGold(gold - upgradeCost); self.level++; if (self.id === 'rapid') { if (self.level === self.maxLevel) { self.fireRate = Math.max(4, 30 - self.level * 9); self.damage = 5 + self.level * 10; self.bulletSpeed = 7 + self.level * 2.4; } else { self.fireRate = Math.max(15, 30 - self.level * 3); self.damage = 5 + self.level * 3; self.bulletSpeed = 7 + self.level * 0.7; } } else { if (self.level === self.maxLevel) { self.fireRate = Math.max(5, 60 - self.level * 24); self.damage = 10 + self.level * 20; self.bulletSpeed = 5 + self.level * 2.4; } else { self.fireRate = Math.max(20, 60 - self.level * 8); self.damage = 10 + self.level * 5; self.bulletSpeed = 5 + self.level * 0.5; } } self.refreshCellsInRange(); self.updateLevelIndicators(); if (self.level > 1) { var levelDot = levelIndicators[self.level - 1].children[1]; tween(levelDot, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.elasticOut, onFinish: function onFinish() { tween(levelDot, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } }); } return true; } else { var notification = game.addChild(new Notification("Not enough gold to upgrade!")); notification.x = 2048 / 2; notification.y = grid.height - 50; return false; } } return false; }; self.findTarget = function () { var closestEnemy = null; var closestScore = Infinity; 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 distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.getRange()) { if (enemy.isFlying) { if (enemy.flyingTarget) { var goalX = enemy.flyingTarget.x; var goalY = enemy.flyingTarget.y; var distToGoal = Math.sqrt((goalX - enemy.cellX) * (goalX - enemy.cellX) + (goalY - enemy.cellY) * (goalY - enemy.cellY)); if (distToGoal < closestScore) { closestScore = distToGoal; closestEnemy = enemy; } } else { if (distance < closestScore) { closestScore = distance; closestEnemy = enemy; } } } else { var cell = grid.getCell(enemy.cellX, enemy.cellY); if (cell && cell.pathId === pathId) { if (cell.score < closestScore) { closestScore = cell.score; closestEnemy = enemy; } } } } } if (!closestEnemy) { self.targetEnemy = null; } return closestEnemy; }; 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.down = function (x, y, obj) { var existingMenus = game.children.filter(function (child) { return child instanceof UpgradeMenu; }); var hasOwnMenu = false; var rangeCircle = null; for (var i = 0; i < game.children.length; i++) { if (game.children[i].isTowerRange && game.children[i].tower === self) { rangeCircle = game.children[i]; break; } } for (var i = 0; i < existingMenus.length; i++) { if (existingMenus[i].tower === self) { hasOwnMenu = true; break; } } if (hasOwnMenu) { for (var i = 0; i < existingMenus.length; i++) { if (existingMenus[i].tower === self) { hideUpgradeMenu(existingMenus[i]); } } if (rangeCircle) { game.removeChild(rangeCircle); } selectedTower = null; grid.renderDebug(); return; } for (var i = 0; i < existingMenus.length; i++) { existingMenus[i].destroy(); } for (var i = game.children.length - 1; i >= 0; i--) { if (game.children[i].isTowerRange) { game.removeChild(game.children[i]); } } selectedTower = self; var rangeIndicator = new Container(); rangeIndicator.isTowerRange = true; rangeIndicator.tower = self; game.addChild(rangeIndicator); rangeIndicator.x = self.x; rangeIndicator.y = self.y; var rangeGraphics = rangeIndicator.attachAsset('rangeCircle', { anchorX: 0.5, anchorY: 0.5 }); rangeGraphics.width = rangeGraphics.height = self.getRange() * 2; rangeGraphics.alpha = 0.3; var upgradeMenu = new UpgradeMenu(self); game.addChild(upgradeMenu); upgradeMenu.x = 2048 / 2; tween(upgradeMenu, { y: 2732 - 225 }, { duration: 200, easing: tween.backOut }); grid.renderDebug(); }; self.isInRange = function (enemy) { if (!enemy) { return false; } var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance <= self.getRange(); }; self.fire = function () { if (self.targetEnemy) { var potentialDamage = 0; for (var i = 0; i < self.targetEnemy.bulletsTargetingThis.length; i++) { potentialDamage += self.targetEnemy.bulletsTargetingThis[i].damage; } if (self.targetEnemy.health > potentialDamage) { 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; if (self.id === 'slow') { bullet.sourceTowerLevel = self.level; } switch (self.id) { case 'rapid': bullet.children[0].tint = 0x00AAFF; bullet.children[0].width = 20; bullet.children[0].height = 20; break; case 'sniper': bullet.children[0].tint = 0xFF5500; bullet.children[0].width = 15; bullet.children[0].height = 15; break; case 'splash': bullet.children[0].tint = 0x33CC00; bullet.children[0].width = 40; bullet.children[0].height = 40; break; case 'slow': bullet.children[0].tint = 0x9900FF; bullet.children[0].width = 35; bullet.children[0].height = 35; break; case 'poison': bullet.children[0].tint = 0x00FFAA; bullet.children[0].width = 35; bullet.children[0].height = 35; break; } game.addChild(bullet); bullets.push(bullet); self.targetEnemy.bulletsTargetingThis.push(bullet); tween.stop(gunContainer, { x: true, y: true, scaleX: true, scaleY: true }); if (gunContainer._restX === undefined) { gunContainer._restX = 0; } if (gunContainer._restY === undefined) { gunContainer._restY = 0; } if (gunContainer._restScaleX === undefined) { gunContainer._restScaleX = 1; } if (gunContainer._restScaleY === undefined) { gunContainer._restScaleY = 1; } gunContainer.x = gunContainer._restX; gunContainer.y = gunContainer._restY; gunContainer.scaleX = gunContainer._restScaleX; gunContainer.scaleY = gunContainer._restScaleY; var recoilDistance = 8; var recoilX = -Math.cos(gunContainer.rotation) * recoilDistance; var recoilY = -Math.sin(gunContainer.rotation) * recoilDistance; tween(gunContainer, { x: gunContainer._restX + recoilX, y: gunContainer._restY + recoilY }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(gunContainer, { x: gunContainer._restX, y: gunContainer._restY }, { duration: 90, easing: tween.cubicIn }); } }); } } }; 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; // ZMIANA: Ustawiamy pole jako 'zajęte' } } } self.refreshCellsInRange(); }; 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; 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 isMaxLevel = self.tower.level >= self.tower.maxLevel; var baseUpgradeCost = getTowerCost(self.tower.id); var upgradeCost; if (isMaxLevel) { upgradeCost = 0; } else if (self.tower.level === self.tower.maxLevel - 1) { upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2); } else { upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1)); } buttonBackground.tint = isMaxLevel ? 0x888888 : gold >= upgradeCost ? 0x00AA00 : 0x888888; var buttonText = new Text2(isMaxLevel ? 'Max Level' : 'Upgrade: ' + upgradeCost + ' gold', { 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; 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; } if (self.tower.upgrade()) { var baseUpgradeCost = getTowerCost(self.tower.id); if (self.tower.level >= self.tower.maxLevel) { upgradeCost = 0; } else if (self.tower.level === self.tower.maxLevel - 1) { upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2); } else { upgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1)); } statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s'); buttonText.setText('Upgrade: ' + upgradeCost + ' gold'); var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0; var sellValue = Math.floor(totalInvestment * 0.6); sellButtonText.setText('Sell: +' + sellValue + ' gold'); if (self.tower.level >= self.tower.maxLevel) { buttonBackground.tint = 0x888888; buttonText.setText('Max Level'); } 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) { var rangeGraphics = rangeCircle.children[0]; rangeGraphics.width = rangeGraphics.height = self.tower.getRange() * 2; } else { var newRangeIndicator = new Container(); newRangeIndicator.isTowerRange = true; newRangeIndicator.tower = self.tower; game.addChildAt(newRangeIndicator, 0); newRangeIndicator.x = self.tower.x; newRangeIndicator.y = self.tower.y; var rangeGraphics = newRangeIndicator.attachAsset('rangeCircle', { anchorX: 0.5, anchorY: 0.5 }); rangeGraphics.width = rangeGraphics.height = self.tower.getRange() * 2; rangeGraphics.alpha = 0.3; } tween(self, { scaleX: 1.05, scaleY: 1.05 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); } }); } }; sellButton.down = function (x, y, obj) { var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0; var sellValue = getTowerSellValue(totalInvestment); setGold(gold + sellValue); var notification = game.addChild(new Notification("Tower sold for " + sellValue + " gold!")); notification.x = 2048 / 2; notification.y = grid.height - 50; 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; // ZMIANA: Pole wraca do bycia 'miejscem na budowę' var towerIndex = cell.towersInRange.indexOf(self.tower); if (towerIndex !== -1) { cell.towersInRange.splice(towerIndex, 1); } } } } if (selectedTower === self.tower) { selectedTower = null; } var towerIndex = towers.indexOf(self.tower); if (towerIndex !== -1) { towers.splice(towerIndex, 1); } towerLayer.removeChild(self.tower); grid.pathFind(); grid.renderDebug(); self.destroy(); 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; } } }; closeButton.down = function (x, y, obj) { hideUpgradeMenu(self); selectedTower = null; grid.renderDebug(); }; self.update = function () { if (self.tower.level >= self.tower.maxLevel) { if (buttonText.text !== 'Max Level') { buttonText.setText('Max Level'); buttonBackground.tint = 0x888888; } return; } var baseUpgradeCost = getTowerCost(self.tower.id); var currentUpgradeCost; if (self.tower.level >= self.tower.maxLevel) { currentUpgradeCost = 0; } else if (self.tower.level === self.tower.maxLevel - 1) { currentUpgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2); } else { currentUpgradeCost = Math.floor(baseUpgradeCost * Math.pow(2, self.tower.level - 1)); } var canAfford = gold >= currentUpgradeCost; buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888; var newText = 'Upgrade: ' + currentUpgradeCost + ' gold'; if (buttonText.text !== newText) { buttonText.setText(newText); } }; 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 specialTilesLayer; var enemyLayerBottom; var enemyLayerMiddle; var enemyLayerTop; var towerPreview; var buildPanelContainer; var buildButton; var isBuildPanelOpen; // --- 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 topMargin = 50; var centerX = 2048 / 2; var spacing = 400; LK.gui.top.addChild(goldText); LK.gui.top.addChild(livesText); LK.gui.top.addChild(enemiesText); livesText.x = 0; livesText.y = topMargin; goldText.x = -spacing; goldText.y = topMargin; enemiesText.x = spacing; enemiesText.y = topMargin; // --- 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; } return cost; } function getTowerSellValue(totalValue) { var gameHasStarted = currentWave > 1 || enemies.length > 0; if (gameHasStarted) { return Math.floor(totalValue * 0.6); } else { return totalValue; } } // --- 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("NASZA 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 () { console.log("Przycisk START wciśnięty. Przechodzę do wyboru poziomu."); 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("WYBIERZ POZIOM", { 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("Poziom 1: Mroczny Las", { size: 60, fill: 0xFFFFFF }); levelButton1Text.anchor.set(0.5, 0.5); levelButton1.addChild(levelButton1Text); levelButton1.interactive = true; levelButton1.down = function () { console.log("Wybrano Poziom 1. Rozpoczynam grę..."); 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("Powrót", { size: 60, fill: 0xFFFFFF }); backButtonText.anchor.set(0.5, 0.5); backButton.addChild(backButtonText); backButton.interactive = true; backButton.down = function () { console.log("Powrót do menu głównego."); if (levelSelectContainer) { levelSelectContainer.destroy(); } showTitleScreen(); }; } function toggleBuildPanel(forceState) { var targetY; var shouldBeOpen; if (forceState === 'open') { shouldBeOpen = true; } else if (forceState === 'close') { shouldBeOpen = false; } else { shouldBeOpen = !isBuildPanelOpen; } if (shouldBeOpen) { targetY = 2732 - 250; // Pozycja panelu gdy jest otwarty isBuildPanelOpen = true; } else { targetY = 2732 + 100; // Pozycja panelu gdy jest zamknięty (schowany) isBuildPanelOpen = false; } tween(buildPanelContainer, { y: targetY }, { duration: 300, easing: tween.backOut }); } function startGame(levelNumber) { // --- CZYSZCZENIE EKRANU I INICJALIZACJA --- 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; } // --- WCZYTANIE DANYCH POZIOMU DO ZMIENNEJ GLOBALNEJ --- levelData = { levelName: "Poziom 1: Królewska Droga", initialGold: 100, initialLives: 20, mapLayout: ["22222222110S011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "22222222110E011222222222"], 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; maxScore = 0; enemies = []; towers = []; bullets = []; selectedTower = null; gold = levelData.initialGold; lives = levelData.initialLives; enemiesKilled = 0; enemiesInCurrentWave = 0; currentWave = 1; totalWaves = levelData.waves.length; waveInProgress = true; 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(); 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; 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) { if (tileChar === '0') { cell.type = 0; // Ścieżka } else if (tileChar === '1') { cell.type = 1; // Miejsce na budowę } else if (tileChar === 'S') { cell.type = 3; // Spawn } else if (tileChar === 'E') { cell.type = 4; // Cel } else { cell.type = 2; // Domyślnie traktuj resztę jako przeszkodę } } } } 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(); game.addChild(debugLayer); game.addChild(specialTilesLayer); game.addChild(towerLayer); game.addChild(enemyLayer); towerPreview = new TowerPreview(); game.addChild(towerPreview); towerPreview.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, 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; game.addChild(startGameButton); // Tekst timera, na początku niewidoczny timerText = new Text2("", { size: 100, fill: 0xFFFFFF, weight: 800, stroke: 0x000000, strokeThickness: 6 }); timerText.anchor.set(0.5, 0.5); timerText.x = 2048 / 2; timerText.y = 2732 / 2; timerText.visible = false; game.addChild(timerText); startGameButton.down = function () { isBuildPhase = true; buildPhaseTimer = 60 * 10; // 10 sekund przy 60 FPS timerText.visible = true; startGameButton.destroy(); // Niszczymy przycisk po użyciu }; 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); 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); } 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("Buduj", { size: 60, fill: 0x000000, weight: 800 }); buildButtonText.anchor.set(0.5, 0.5); buildButton.addChild(buildButtonText); buildButton.down = function () { toggleBuildPanel(); }; game.down = function (x, y, obj) { var buildButtonBounds = buildButton.getBounds(); if (buildButtonBounds.contains(x, y)) { return; } var upgradeMenuVisible = game.children.some(function (child) { return child instanceof UpgradeMenu; }); if (upgradeMenuVisible) { return; } if (isBuildPanelOpen) { var localClickPos = { x: x - buildPanelContainer.x, y: y - buildPanelContainer.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 }; 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; isDragging = true; towerPreview.towerType = tower.towerType; towerPreview.updateAppearance(); towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5); return; } } if (!clickedOnSourceTower) { toggleBuildPanel('close'); } } }; game.move = function (x, y, obj) { if (isDragging) { towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5); } }; game.up = function (x, y, obj) { if (isDragging) { isDragging = 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; } towerPreview.visible = false; toggleBuildPanel('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') { // --- NOWA LOGIKA FAL OPARTA NA levelData --- if (currentWave <= totalWaves && enemies.length === 0 && !waveInProgress) { waveTimer++; if (waveTimer >= nextWaveTime) { currentWave++; if (currentWave <= totalWaves) { waveInProgress = true; waveSpawned = false; var notification = game.addChild(new Notification("Wave " + currentWave + " incoming!")); notification.x = 2048 / 2; notification.y = grid.height - 150; } } } if (waveInProgress && !waveSpawned) { waveSpawned = true; enemiesKilled = 0; // Resetuj licznik zabitych dla nowej fali // Znajdź dane dla aktualnej fali var waveData = levelData.waves[currentWave - 1]; if (waveData) { var enemyCount = waveData.count; var waveType = waveData.type; var isBoss = waveData.isBoss || false; enemiesInCurrentWave = enemyCount; // Ustaw liczbę wrogów w fali updateUI(); if (isBoss) { var notification = game.addChild(new Notification("⚠️ BOSS WAVE! ⚠️")); notification.x = 2048 / 2; notification.y = grid.height - 200; } for (var i = 0; i < enemyCount; i++) { // --- POPRAWIONA, BEZPIECZNA LOGIKA SPAWNOWANIA --- var enemy = new Enemy(waveType); var spawnPoints = grid.spawns; var spawnX; if (spawnPoints && spawnPoints.length > 0) { spawnX = spawnPoints[Math.floor(Math.random() * spawnPoints.length)].x; } else { console.warn("Brak punktu startowego 'S' w mapie! Używam domyślnego na środku."); spawnX = Math.floor(grid.cells.length / 2); } var spawnY = -1 - i * 2; // Rozmieszczamy ich lekko w pionie, żeby się nie naкладывали enemy.currentCellX = spawnX; enemy.currentCellY = spawnY; enemy.cellX = spawnX; // Ustawiamy od razu, żeby wiedział dokąd iść enemy.cellY = 5; enemy.waveNumber = currentWave; if (isBoss) { enemy.isBoss = true; } // Upewniamy się, że flaga bossa jest ustawiona var healthMultiplier = Math.pow(1.12, currentWave); enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier); enemy.health = enemy.maxHealth; // Dodawanie do warstw if (enemy.isFlying) { enemyLayerTop.addChild(enemy); if (enemy.shadow) { enemyLayerMiddle.addChild(enemy.shadow); } } else { enemyLayerBottom.addChild(enemy); } enemies.push(enemy); } } else { console.warn("Brak danych dla fali numer: " + currentWave); waveInProgress = false; } } if (enemies.length === 0 && waveSpawned) { waveInProgress = false; waveSpawned = false; waveTimer = 0; // Rozpocznij odliczanie do następnej fali } // --- Reszta logiki (aktualizacja wrogów, wież, pocisków) --- 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); var goldIndicator = new GoldIndicator(goldEarned, enemy.x, enemy.y); game.addChild(goldIndicator); setGold(gold + goldEarned); if (enemy.isBoss) { var notification = game.addChild(new Notification("Boss defeated! +" + goldEarned + " gold!")); notification.x = 2048 / 2; notification.y = grid.height - 150; } for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) { enemy.bulletsTargetingThis[i].targetEnemy = null; } if (enemy.isFlying && enemy.shadow) { enemyLayerMiddle.removeChild(enemy.shadow); enemy.shadow = null; } if (enemy.isFlying) { enemyLayerTop.removeChild(enemy); } else { enemyLayerBottom.removeChild(enemy); } enemies.splice(a, 1); continue; } if (grid.updateEnemy(enemy)) { if (enemy.isFlying && enemy.shadow) { enemyLayerMiddle.removeChild(enemy.shadow); enemy.shadow = null; } if (enemy.isFlying) { enemyLayerTop.removeChild(enemy); } else { enemyLayerBottom.removeChild(enemy); } 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 (towerPreview.visible) { towerPreview.checkPlacement(); } if (currentWave >= totalWaves && enemies.length === 0 && !waveInProgress) { LK.showYouWin(); } } }; showTitleScreen();
===================================================================
--- original.js
+++ change.js
@@ -509,13 +509,13 @@
return self.cells[x] && self.cells[x][y];
};
self.pathFind = function () {
var before = new Date().getTime();
- // Znajdź wszystkie komórki końcowe (goals)
self.goals = [];
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
- if (self.cells[i][j].type === 3) {
+ if (self.cells[i][j].type === 4) {
+ // Cel to teraz type 4
self.goals.push(self.cells[i][j]);
}
}
}
@@ -523,13 +523,13 @@
maxScore = 0;
pathId += 1;
for (var a = 0; a < toProcess.length; a++) {
toProcess[a].pathId = pathId;
- toProcess[a].score = 0; // Reset score for pathfinding
+ toProcess[a].score = 0;
}
function processNode(node, targetValue, targetNode) {
- if (node && node.type != 1) {
- // Typ 1 to ściana
+ // 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);
@@ -550,22 +550,22 @@
var nodes = toProcess;
toProcess = [];
for (var a = 0; a < nodes.length; a++) {
var node = nodes[a];
- var targetScore = node.score + 14142; // Diagonal cost
- if (node.up && node.left && node.up.type != 1 && node.left.type != 1) {
+ 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 != 1 && node.right.type != 1) {
+ 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 != 1 && node.right.type != 1) {
+ 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 != 1 && node.left.type != 1) {
+ 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; // Straight cost
+ targetScore = node.score + 10000;
processNode(node.up, targetScore, node);
processNode(node.right, targetScore, node);
processNode(node.down, targetScore, node);
processNode(node.left, targetScore, node);
@@ -573,9 +573,10 @@
}
self.spawns = [];
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
- if (self.cells[i][j].type === 2) {
+ if (self.cells[i][j].type === 3) {
+ // ZMIANA: Szukamy spawnu type 3
self.spawns.push(self.cells[i][j]);
}
}
}
@@ -610,19 +611,20 @@
// bo nie używamy już starego debugowania siatki
};
self.updateEnemy = function (enemy) {
var cell = grid.getCell(enemy.cellX, enemy.cellY);
- if (cell && cell.type == 3) {
- return true;
+ 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;
}
}
- // Prosta logika startu wroga - idzie prosto w dół do pierwszej komórki ścieżki
+ // 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;
@@ -1242,15 +1244,15 @@
};
self.placeOnGrid = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
- self.x = grid.x + gridX * CELL_SIZE + CELL_SIZE / 2;
- self.y = grid.y + gridY * CELL_SIZE + CELL_SIZE / 2;
+ 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 = 1;
+ cell.type = 5; // ZMIANA: Ustawiamy pole jako 'zajęte'
}
}
}
self.refreshCellsInRange();
@@ -1318,15 +1320,18 @@
}
};
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 !== 0) {
+ if (!cell || cell.type !== 1) {
+ // ZMIANA: szukamy '1' zamiast '0'
validGridPlacement = false;
break;
}
}
@@ -1334,8 +1339,9 @@
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];
@@ -1552,9 +1558,9 @@
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 = 0;
+ cell.type = 1; // ZMIANA: Pole wraca do bycia 'miejscem na budowę'
var towerIndex = cell.towersInRange.indexOf(self.tower);
if (towerIndex !== -1) {
cell.towersInRange.splice(towerIndex, 1);
}
@@ -1626,8 +1632,12 @@
/**** * 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;
@@ -1636,8 +1646,9 @@
var gold;
var lives;
var enemiesKilled;
var enemiesInCurrentWave;
+var levelData;
var currentWave;
var totalWaves;
var waveTimer;
var waveInProgress;
@@ -1743,9 +1754,14 @@
}
return cost;
}
function getTowerSellValue(totalValue) {
- return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
+ var gameHasStarted = currentWave > 1 || enemies.length > 0;
+ if (gameHasStarted) {
+ return Math.floor(totalValue * 0.6);
+ } else {
+ return totalValue;
+ }
}
// --- FUNKCJE EKRANÓW ---
function showTitleScreen() {
if (titleScreenContainer) {
@@ -1862,68 +1878,8 @@
}
showTitleScreen();
};
}
-var level1Data = {
- levelName: "Mroczny Las (Test)",
- initialGold: 100,
- initialLives: 20,
- mapLayout: ["11111111111S111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "111111111110111111111111", "11111111111E111111111111"],
- // --- NOWE, PRAWDZIWE DEFINICJE FAL ---
- 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
- },
- // Boss na fali 10
- {
- 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: [{
- type: 'amplify',
- x: 10,
- y: 8
- }, {
- type: 'synergy',
- x: 12,
- y: 8
- }]
-};
function toggleBuildPanel(forceState) {
var targetY;
var shouldBeOpen;
if (forceState === 'open') {
@@ -1961,10 +1917,58 @@
currentScreenState = 'gameplay';
if (LK.gui.top) {
LK.gui.top.visible = true;
}
- // --- WCZYTANIE DANYCH POZIOMU ---
- var levelData = level1Data;
+ // --- WCZYTANIE DANYCH POZIOMU DO ZMIENNEJ GLOBALNEJ ---
+ levelData = {
+ levelName: "Poziom 1: Królewska Droga",
+ initialGold: 100,
+ initialLives: 20,
+ mapLayout: ["22222222110S011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "222222221100011222222222", "22222222110E011222222222"],
+ 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;
maxScore = 0;
enemies = [];
towers = [];
@@ -1972,19 +1976,18 @@
selectedTower = null;
gold = levelData.initialGold;
lives = levelData.initialLives;
enemiesKilled = 0;
- totalEnemiesInLevel = 50;
- // --- POPRAWIONA LOGIKA STARTOWA FAL ---
- currentWave = 1; // Zaczynamy od razu od fali 1
- waveInProgress = true; // Oznaczamy, że fala jest w toku
- waveSpawned = false; // Oznaczamy, że trzeba zespawnować wrogów
- waveTimer = 0; // Timer zaczyna liczyć czas do NASTĘPNEJ fali
- nextWaveTime = 1200; // Czas między falami (20 sekund przy 60fps)
+ enemiesInCurrentWave = 0;
+ currentWave = 1;
+ totalWaves = levelData.waves.length;
+ waveInProgress = true;
+ waveSpawned = false;
+ waveTimer = 0;
+ nextWaveTime = 1200;
sourceTowers = [];
isBuildPanelOpen = false;
- // --- TWORZENIE NOWEGO UI ---
- wavesText = new Text2('Wave: 0/50', {
+ wavesText = new Text2('Wave: 0/' + totalWaves, {
size: 60,
fill: 0x00FFFF,
weight: 800
});
@@ -1992,9 +1995,8 @@
LK.gui.top.addChild(wavesText);
wavesText.x = spacing;
wavesText.y = topMargin + 80;
updateUI();
- // --- TWORZENIE WARSTW I SIATKI ---
debugLayer = new Container();
specialTilesLayer = new Container();
towerLayer = new Container();
enemyLayerBottom = new Container();
@@ -2006,22 +2008,23 @@
enemyLayer.addChild(enemyLayerTop);
grid = new Grid(24, 29 + 6);
grid.x = 150;
grid.y = 200 - CELL_SIZE * 4;
- // --- WCZYTANIE UKŁADU MAPY ---
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) {
if (tileChar === '0') {
- cell.type = 0;
+ cell.type = 0; // Ścieżka
+ } else if (tileChar === '1') {
+ cell.type = 1; // Miejsce na budowę
} else if (tileChar === 'S') {
- cell.type = 2;
+ cell.type = 3; // Spawn
} else if (tileChar === 'E') {
- cell.type = 3;
+ cell.type = 4; // Cel
} else {
- cell.type = 1;
+ cell.type = 2; // Domyślnie traktuj resztę jako przeszkodę
}
}
}
}
@@ -2051,29 +2054,46 @@
towerPreview = new TowerPreview();
game.addChild(towerPreview);
towerPreview.visible = false;
var isDragging = false;
- function wouldBlockPath(gridX, gridY) {
- var cells = [];
- for (var i = 0; i < 2; i++) {
- for (var j = 0; j < 2; j++) {
- var cell = grid.getCell(gridX + i, gridY + j);
- if (cell) {
- cells.push({
- cell: cell,
- originalType: cell.type
- });
- cell.type = 1;
- }
- }
- }
- var blocked = grid.pathFind();
- for (var i = 0; i < cells.length; i++) {
- cells[i].cell.type = cells[i].originalType;
- }
- grid.pathFind();
- return blocked;
- }
+ // --- Logika Startu Gry i Fazy Budowy ---
+ 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;
+ game.addChild(startGameButton);
+ // Tekst timera, na początku niewidoczny
+ timerText = new Text2("", {
+ size: 100,
+ fill: 0xFFFFFF,
+ weight: 800,
+ stroke: 0x000000,
+ strokeThickness: 6
+ });
+ timerText.anchor.set(0.5, 0.5);
+ timerText.x = 2048 / 2;
+ timerText.y = 2732 / 2;
+ timerText.visible = false;
+ game.addChild(timerText);
+ startGameButton.down = function () {
+ isBuildPhase = true;
+ buildPhaseTimer = 60 * 10; // 10 sekund przy 60 FPS
+ timerText.visible = true;
+ startGameButton.destroy(); // Niszczymy przycisk po użyciu
+ };
function placeTower(gridX, gridY, towerType) {
var towerCost = getTowerCost(towerType);
if (gold >= towerCost) {
var tower = new Tower(towerType || 'default');
@@ -2134,193 +2154,203 @@
buildButton.down = function () {
toggleBuildPanel();
};
game.down = function (x, y, obj) {
+ var buildButtonBounds = buildButton.getBounds();
+ if (buildButtonBounds.contains(x, y)) {
+ return;
+ }
var upgradeMenuVisible = game.children.some(function (child) {
return child instanceof UpgradeMenu;
});
if (upgradeMenuVisible) {
return;
}
if (isBuildPanelOpen) {
+ var localClickPos = {
+ x: x - buildPanelContainer.x,
+ y: y - buildPanelContainer.y
+ };
+ var clickedOnSourceTower = false;
for (var i = 0; i < sourceTowers.length; i++) {
var tower = sourceTowers[i];
- var localClickPos = buildPanelContainer.toLocal({
- x: x,
- y: y
- });
- if (tower.getBounds().contains(localClickPos.x, localClickPos.y)) {
+ 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
+ };
+ 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;
isDragging = true;
towerPreview.towerType = tower.towerType;
towerPreview.updateAppearance();
towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
- toggleBuildPanel('close');
return;
}
}
+ if (!clickedOnSourceTower) {
+ toggleBuildPanel('close');
+ }
}
- var buildButtonBounds = buildButton.getBounds();
- if (isBuildPanelOpen && !buildButtonBounds.contains(x, y)) {
- toggleBuildPanel('close');
- }
};
game.move = function (x, y, obj) {
if (isDragging) {
towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
}
};
game.up = function (x, y, obj) {
- 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;
+ if (isDragging) {
+ isDragging = 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;
}
- }
- var upgradeMenus = game.children.filter(function (child) {
- return child instanceof UpgradeMenu;
- });
- if (upgradeMenus.length > 0 && !isDragging && !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;
+ towerPreview.visible = false;
+ toggleBuildPanel('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;
}
}
- if (!clickedOnMenu) {
+ 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++) {
- hideUpgradeMenu(upgradeMenus[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;
+ }
}
- for (var i = game.children.length - 1; i >= 0; i--) {
- if (game.children[i].isTowerRange) {
- game.removeChild(game.children[i]);
+ 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;
}
- selectedTower = null;
}
}
- if (isDragging) {
- isDragging = false;
- if (towerPreview.canPlace) {
- if (!wouldBlockPath(towerPreview.gridX, towerPreview.gridY)) {
- placeTower(towerPreview.gridX, towerPreview.gridY, towerPreview.towerType);
- } else {
- var notification = game.addChild(new Notification("Tower would block the path!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 50;
- }
- } 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;
- } else if (towerPreview.visible) {
- var notification = game.addChild(new Notification("Cannot build here!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 50;
- }
- towerPreview.visible = false;
- }
};
}
game.update = function () {
if (currentScreenState === 'gameplay') {
- // --- NOWA, UPROSZCZONA LOGIKA FAL ---
- if (currentWave < totalWaves) {
+ // --- NOWA LOGIKA FAL OPARTA NA levelData ---
+ if (currentWave <= totalWaves && enemies.length === 0 && !waveInProgress) {
waveTimer++;
- if (waveTimer >= nextWaveTime && !waveInProgress) {
- waveTimer = 0;
+ if (waveTimer >= nextWaveTime) {
currentWave++;
- waveInProgress = true;
- waveSpawned = false; // Resetujemy flagę, aby nowa fala mogła się zespawnować
- updateUI(); // Aktualizujemy UI od razu po zmianie fali
- var notification = game.addChild(new Notification("Wave " + currentWave + " incoming!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 150;
+ if (currentWave <= totalWaves) {
+ waveInProgress = true;
+ waveSpawned = false;
+ var notification = game.addChild(new Notification("Wave " + currentWave + " incoming!"));
+ notification.x = 2048 / 2;
+ notification.y = grid.height - 150;
+ }
}
}
- if (waveInProgress) {
- if (!waveSpawned) {
- waveSpawned = true;
- // Na razie prosta fala, 10 normalnych wrogów
- var enemyCount = 10;
- var waveType = 'normal';
- var isBossWave = currentWave % 10 === 0 && currentWave > 0;
- if (isBossWave && waveType !== 'swarm') {
- enemyCount = 1;
+ if (waveInProgress && !waveSpawned) {
+ waveSpawned = true;
+ enemiesKilled = 0; // Resetuj licznik zabitych dla nowej fali
+ // Znajdź dane dla aktualnej fali
+ var waveData = levelData.waves[currentWave - 1];
+ if (waveData) {
+ var enemyCount = waveData.count;
+ var waveType = waveData.type;
+ var isBoss = waveData.isBoss || false;
+ enemiesInCurrentWave = enemyCount; // Ustaw liczbę wrogów w fali
+ updateUI();
+ if (isBoss) {
var notification = game.addChild(new Notification("⚠️ BOSS WAVE! ⚠️"));
notification.x = 2048 / 2;
notification.y = grid.height - 200;
}
for (var i = 0; i < enemyCount; i++) {
+ // --- POPRAWIONA, BEZPIECZNA LOGIKA SPAWNOWANIA ---
var enemy = new Enemy(waveType);
- if (enemy.isFlying) {
- enemyLayerTop.addChild(enemy);
- if (enemy.shadow) {
- enemyLayerMiddle.addChild(enemy.shadow);
- }
- } else {
- enemyLayerBottom.addChild(enemy);
- }
- var healthMultiplier = Math.pow(1.12, currentWave);
- enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
- enemy.health = enemy.maxHealth;
- // Logika spawnowania
var spawnPoints = grid.spawns;
var spawnX;
- if (spawnPoints.length > 0) {
+ if (spawnPoints && spawnPoints.length > 0) {
spawnX = spawnPoints[Math.floor(Math.random() * spawnPoints.length)].x;
} else {
- // Fallback, jeśli nie zdefiniowano 'S' w mapie
+ console.warn("Brak punktu startowego 'S' w mapie! Używam domyślnego na środku.");
spawnX = Math.floor(grid.cells.length / 2);
}
- var spawnY = -1 - Math.random() * 5;
- enemy.cellX = spawnX;
- enemy.cellY = 5; // Startowa pozycja na siatce
+ var spawnY = -1 - i * 2; // Rozmieszczamy ich lekko w pionie, żeby się nie naкладывали
enemy.currentCellX = spawnX;
- enemy.currentCellY = spawnY; // Pozycja "w powietrzu" nad planszą
+ enemy.currentCellY = spawnY;
+ enemy.cellX = spawnX; // Ustawiamy od razu, żeby wiedział dokąd iść
+ enemy.cellY = 5;
enemy.waveNumber = currentWave;
+ if (isBoss) {
+ enemy.isBoss = true;
+ } // Upewniamy się, że flaga bossa jest ustawiona
+ var healthMultiplier = Math.pow(1.12, currentWave);
+ enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
+ enemy.health = enemy.maxHealth;
+ // Dodawanie do warstw
+ if (enemy.isFlying) {
+ enemyLayerTop.addChild(enemy);
+ if (enemy.shadow) {
+ enemyLayerMiddle.addChild(enemy.shadow);
+ }
+ } else {
+ enemyLayerBottom.addChild(enemy);
+ }
enemies.push(enemy);
}
- }
- // Sprawdzenie, czy fala się zakończyła
- var currentWaveEnemiesRemaining = false;
- for (var i = 0; i < enemies.length; i++) {
- if (enemies[i].waveNumber === currentWave) {
- currentWaveEnemiesRemaining = true;
- break;
- }
- }
- if (waveSpawned && !currentWaveEnemiesRemaining) {
+ } else {
+ console.warn("Brak danych dla fali numer: " + currentWave);
waveInProgress = false;
- waveSpawned = false;
- // Tutaj możemy dodać bonusowe złoto za przetrwanie fali
}
}
+ if (enemies.length === 0 && waveSpawned) {
+ waveInProgress = false;
+ waveSpawned = false;
+ waveTimer = 0; // Rozpocznij odliczanie do następnej fali
+ }
// --- Reszta logiki (aktualizacja wrogów, wież, pocisków) ---
for (var a = enemies.length - 1; a >= 0; a--) {
var enemy = enemies[a];
if (enemy.health <= 0) {
- for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
- var bullet = enemy.bulletsTargetingThis[i];
- bullet.targetEnemy = null;
- }
+ enemiesKilled++;
+ updateUI();
var goldEarned = enemy.isBoss ? Math.floor(50 + (enemy.waveNumber - 1) * 5) : Math.floor(1 + (enemy.waveNumber - 1) * 0.5);
var goldIndicator = new GoldIndicator(goldEarned, enemy.x, enemy.y);
game.addChild(goldIndicator);
setGold(gold + goldEarned);
- enemiesKilled++;
if (enemy.isBoss) {
var notification = game.addChild(new Notification("Boss defeated! +" + goldEarned + " gold!"));
notification.x = 2048 / 2;
notification.y = grid.height - 150;
}
- updateUI();
+ for (var i = 0; i < enemy.bulletsTargetingThis.length; i++) {
+ enemy.bulletsTargetingThis[i].targetEnemy = null;
+ }
if (enemy.isFlying && enemy.shadow) {
enemyLayerMiddle.removeChild(enemy.shadow);
enemy.shadow = null;
}