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
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Remix started
Copy Tower Defense Template
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
/**** * Classes
****/
var Bullet = Container.expand(function (startX, startY, targetEnemy, damage, speed) {
var self = Container.call(this);
self.targetEnemy = targetEnemy;
self.damage = damage || 10;
self.speed = speed || 5;
self.x = startX;
self.y = startY;
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 initialCost = getTowerCost(self.towerType);
var typeLabelShadow = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
size: 50,
fill: 0x000000,
weight: 800
});
typeLabelShadow.anchor.set(0.5, 0.5);
typeLabelShadow.x = 4;
typeLabelShadow.y = -20 + 4;
self.addChild(typeLabelShadow);
var typeLabel = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
size: 50,
fill: 0xFFFFFF,
weight: 800
});
typeLabel.anchor.set(0.5, 0.5);
typeLabel.y = -20;
self.addChild(typeLabel);
var costLabelShadow = new Text2(initialCost, {
size: 50,
fill: 0x000000,
weight: 800
});
costLabelShadow.anchor.set(0.5, 0.5);
costLabelShadow.x = 4;
costLabelShadow.y = 24 + 12;
self.addChild(costLabelShadow);
var costLabel = new Text2(initialCost, {
size: 50,
fill: 0xFFD700,
weight: 800
});
costLabel.anchor.set(0.5, 0.5);
costLabel.y = 20 + 12;
self.addChild(costLabel);
self.update = function () {
var currentCost = getTowerCost(self.towerType);
if (costLabel.text !== currentCost) {
costLabel.setText(currentCost);
costLabelShadow.setText(currentCost);
}
var canAfford = gold >= currentCost;
self.alpha = canAfford ? 1 : 0.5;
};
return self;
});
var Tower = Container.expand(function (id) {
var self = Container.call(this);
self.id = id || 'default';
self.level = 1;
self.maxLevel = 6;
self.gridX = 0;
self.gridY = 0;
self.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 buttonText = new Text2('', {
size: 60,
fill: 0xFFFFFF,
weight: 800
});
buttonText.anchor.set(0.5, 0.5);
upgradeButton.addChild(buttonText);
var sellButton = new Container();
buttonsContainer.addChild(sellButton);
var sellButtonBackground = sellButton.attachAsset('notification', {
anchorX: 0.5,
anchorY: 0.5
});
sellButtonBackground.width = 500;
sellButtonBackground.height = 150;
sellButtonBackground.tint = 0xCC0000;
var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
var sellValue = getTowerSellValue(totalInvestment);
var sellButtonText = new Text2('Sell: +' + sellValue + ' gold', {
size: 60,
fill: 0xFFFFFF,
weight: 800
});
sellButtonText.anchor.set(0.5, 0.5);
sellButton.addChild(sellButtonText);
upgradeButton.y = -85;
sellButton.y = 85;
var closeButton = new Container();
self.addChild(closeButton);
var closeBackground = closeButton.attachAsset('notification', {
anchorX: 0.5,
anchorY: 0.5
});
closeBackground.width = 90;
closeBackground.height = 90;
closeBackground.tint = 0xAA0000;
var closeText = new Text2('X', {
size: 68,
fill: 0xFFFFFF,
weight: 800
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = menuBackground.width / 2 - 57;
closeButton.y = -menuBackground.height / 2 + 57;
function getUpgradeCost() {
if (self.tower.level >= self.tower.maxLevel) return 0;
// Koszt ulepszenia bazuje na KOSZCIE PODSTAWOWYM wieży, bez mnożnika fazy walki
var tempPhase = isBuildPhase;
isBuildPhase = true;
var baseTowerCost = getTowerCost(self.tower.id);
isBuildPhase = tempPhase;
var upgradeCost;
if (self.tower.level === self.tower.maxLevel - 1) {
upgradeCost = Math.floor(baseTowerCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
} else {
upgradeCost = Math.floor(baseTowerCost * Math.pow(2, self.tower.level - 1));
}
// Dopiero na końcu dodajemy ewentualny mnożnik fazy walki
if (!isBuildPhase) {
upgradeCost = Math.floor(upgradeCost * 1.5);
}
return upgradeCost;
}
upgradeButton.down = function (x, y, obj) {
if (self.tower.level >= self.tower.maxLevel) {
var notification = game.addChild(new Notification("Tower is already at max level!"));
notification.x = 2048 / 2;
notification.y = grid.height - 50;
return;
}
var currentUpgradeCost = getUpgradeCost();
if (gold >= currentUpgradeCost) {
setGold(gold - currentUpgradeCost);
self.tower.upgrade();
statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s');
var newTotalInvestment = self.tower.getTotalValue();
sellButtonText.setText('Sell: +' + getTowerSellValue(newTotalInvestment) + ' gold');
var rangeCircle = null;
for (var i = 0; i < game.children.length; i++) {
if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
rangeCircle = game.children[i];
break;
}
}
if (rangeCircle) {
rangeCircle.children[0].width = rangeCircle.children[0].height = self.tower.getRange() * 2;
}
} else {
var notification = game.addChild(new Notification("Not enough gold to upgrade!"));
notification.x = 2048 / 2;
notification.y = grid.height - 50;
}
};
sellButton.down = function (x, y, obj) {
var sellValue = getTowerSellValue(self.tower.getTotalValue());
setGold(gold + sellValue);
var gridX = self.tower.gridX;
var gridY = self.tower.gridY;
for (var i = 0; i < 2; i++) {
for (var j = 0; j < 2; j++) {
var cell = grid.getCell(gridX + i, gridY + j);
if (cell) {
cell.type = 1;
}
}
}
grid.pathFind();
if (selectedTower === self.tower) selectedTower = null;
var towerIndex = towers.indexOf(self.tower);
if (towerIndex !== -1) towers.splice(towerIndex, 1);
for (var i = 0; i < game.children.length; i++) {
if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
game.removeChild(game.children[i]);
break;
}
}
towerLayer.removeChild(self.tower);
self.destroy();
};
closeButton.down = function (x, y, obj) {
hideUpgradeMenu(self);
selectedTower = null;
grid.renderDebug();
};
self.update = function () {
if (self.tower.level >= self.tower.maxLevel) {
buttonText.setText('Max Level');
buttonBackground.tint = 0x888888;
return;
}
var currentUpgradeCost = getUpgradeCost();
buttonText.setText('Upgrade: ' + currentUpgradeCost + ' gold');
var canAfford = gold >= currentUpgradeCost;
buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888;
};
return self;
});
/****
* Initialize Game
****/
/**** * Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x333333
});
/****
* Game Code
****/
/**** * Game Code
****/
var CELL_SIZE = 76;
// --- GŁÓWNE ZMIENNE STANU GRY ---
var isBuildPhase = false;
var buildPhaseTimer = 0; // Timer do odliczania
var startGameButton; // Przycisk "Start building"
var timerText;
var pathId;
var maxScore;
var enemies;
var towers;
var bullets;
var selectedTower;
var gold;
var lives;
var enemiesKilled;
var enemiesInCurrentWave;
var levelData;
var currentWave;
var totalWaves;
var waveTimer;
var waveInProgress;
var waveSpawned;
var nextWaveTime;
var sourceTowers;
var grid;
var wavesText;
var towerLayer;
var enemyLayer;
var debugLayer;
var 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;
}
if (!isBuildPhase && currentWave > 0) {
// Jeśli trwa faza walki
cost = Math.floor(cost * 1.5);
}
return cost;
}
function getTowerSellValue(totalValue) {
return Math.floor(totalValue * 0.6);
}
// --- FUNKCJE EKRANÓW ---
function showTitleScreen() {
if (titleScreenContainer) {
titleScreenContainer.destroy();
}
titleScreenContainer = new Container();
game.addChild(titleScreenContainer);
currentScreenState = 'title';
if (LK.gui.top) {
LK.gui.top.visible = false;
}
var gameTitle = new Text2("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;
@@ -729,9 +731,9 @@
break;
default:
baseGraphics.tint = 0xAAAAAA;
}
- var towerCost = getTowerCost(self.towerType);
+ var initialCost = getTowerCost(self.towerType);
var typeLabelShadow = new Text2(self.towerType.charAt(0).toUpperCase() + self.towerType.slice(1), {
size: 50,
fill: 0x000000,
weight: 800
@@ -747,27 +749,32 @@
});
typeLabel.anchor.set(0.5, 0.5);
typeLabel.y = -20;
self.addChild(typeLabel);
- var costLabelShadow = new Text2(towerCost, {
+ 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(towerCost, {
+ var costLabel = new Text2(initialCost, {
size: 50,
fill: 0xFFD700,
weight: 800
});
costLabel.anchor.set(0.5, 0.5);
costLabel.y = 20 + 12;
self.addChild(costLabel);
self.update = function () {
- var canAfford = gold >= getTowerCost(self.towerType);
+ var currentCost = getTowerCost(self.towerType);
+ if (costLabel.text !== currentCost) {
+ costLabel.setText(currentCost);
+ costLabelShadow.setText(currentCost);
+ }
+ var canAfford = gold >= currentCost;
self.alpha = canAfford ? 1 : 0.5;
};
return self;
});
@@ -1242,15 +1249,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 +1325,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 +1344,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];
@@ -1416,20 +1427,9 @@
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', {
+ var buttonText = new Text2('', {
size: 60,
fill: 0xFFFFFF,
weight: 800
});
@@ -1472,142 +1472,98 @@
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = menuBackground.width / 2 - 57;
closeButton.y = -menuBackground.height / 2 + 57;
+ function getUpgradeCost() {
+ if (self.tower.level >= self.tower.maxLevel) return 0;
+ // Koszt ulepszenia bazuje na KOSZCIE PODSTAWOWYM wieży, bez mnożnika fazy walki
+ var tempPhase = isBuildPhase;
+ isBuildPhase = true;
+ var baseTowerCost = getTowerCost(self.tower.id);
+ isBuildPhase = tempPhase;
+ var upgradeCost;
+ if (self.tower.level === self.tower.maxLevel - 1) {
+ upgradeCost = Math.floor(baseTowerCost * Math.pow(2, self.tower.level - 1) * 3.5 / 2);
+ } else {
+ upgradeCost = Math.floor(baseTowerCost * Math.pow(2, self.tower.level - 1));
+ }
+ // Dopiero na końcu dodajemy ewentualny mnożnik fazy walki
+ if (!isBuildPhase) {
+ upgradeCost = Math.floor(upgradeCost * 1.5);
+ }
+ return upgradeCost;
+ }
upgradeButton.down = function (x, y, obj) {
if (self.tower.level >= self.tower.maxLevel) {
var notification = game.addChild(new Notification("Tower is already at max level!"));
notification.x = 2048 / 2;
notification.y = grid.height - 50;
return;
}
- 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));
- }
+ var currentUpgradeCost = getUpgradeCost();
+ if (gold >= currentUpgradeCost) {
+ setGold(gold - currentUpgradeCost);
+ self.tower.upgrade();
statsText.setText('Level: ' + self.tower.level + '/' + self.tower.maxLevel + '\nDamage: ' + self.tower.damage + '\nFire Rate: ' + (60 / self.tower.fireRate).toFixed(1) + '/s');
- 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 newTotalInvestment = self.tower.getTotalValue();
+ sellButtonText.setText('Sell: +' + getTowerSellValue(newTotalInvestment) + ' gold');
var rangeCircle = null;
for (var i = 0; i < game.children.length; i++) {
if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
rangeCircle = game.children[i];
break;
}
}
if (rangeCircle) {
- 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;
+ rangeCircle.children[0].width = rangeCircle.children[0].height = self.tower.getRange() * 2;
}
- 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
- });
- }
- });
+ } else {
+ var notification = game.addChild(new Notification("Not enough gold to upgrade!"));
+ notification.x = 2048 / 2;
+ notification.y = grid.height - 50;
}
};
sellButton.down = function (x, y, obj) {
- var totalInvestment = self.tower.getTotalValue ? self.tower.getTotalValue() : 0;
- var sellValue = getTowerSellValue(totalInvestment);
+ var sellValue = getTowerSellValue(self.tower.getTotalValue());
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 = 0;
- var towerIndex = cell.towersInRange.indexOf(self.tower);
- if (towerIndex !== -1) {
- cell.towersInRange.splice(towerIndex, 1);
- }
+ cell.type = 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();
+ if (selectedTower === self.tower) selectedTower = null;
+ var towerIndex = towers.indexOf(self.tower);
+ if (towerIndex !== -1) towers.splice(towerIndex, 1);
for (var i = 0; i < game.children.length; i++) {
if (game.children[i].isTowerRange && game.children[i].tower === self.tower) {
game.removeChild(game.children[i]);
break;
}
}
+ towerLayer.removeChild(self.tower);
+ self.destroy();
};
closeButton.down = function (x, y, obj) {
hideUpgradeMenu(self);
selectedTower = null;
grid.renderDebug();
};
self.update = function () {
if (self.tower.level >= self.tower.maxLevel) {
- if (buttonText.text !== 'Max Level') {
- buttonText.setText('Max Level');
- buttonBackground.tint = 0x888888;
- }
+ 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 currentUpgradeCost = getUpgradeCost();
+ buttonText.setText('Upgrade: ' + currentUpgradeCost + ' gold');
var canAfford = gold >= currentUpgradeCost;
buttonBackground.tint = canAfford ? 0x00AA00 : 0x888888;
- var newText = 'Upgrade: ' + currentUpgradeCost + ' gold';
- if (buttonText.text !== newText) {
- buttonText.setText(newText);
- }
};
return self;
});
@@ -1626,8 +1582,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;
@@ -1741,12 +1701,16 @@
case 'poison':
cost = 55;
break;
}
+ if (!isBuildPhase && currentWave > 0) {
+ // Jeśli trwa faza walki
+ cost = Math.floor(cost * 1.5);
+ }
return cost;
}
function getTowerSellValue(totalValue) {
- return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
+ return Math.floor(totalValue * 0.6);
}
// --- FUNKCJE EKRANÓW ---
function showTitleScreen() {
if (titleScreenContainer) {
@@ -1863,68 +1827,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') {
@@ -1962,10 +1866,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 = [];
@@ -1973,19 +1925,17 @@
selectedTower = null;
gold = levelData.initialGold;
lives = levelData.initialLives;
enemiesKilled = 0;
- enemiesInCurrentWave = 0; // Nowa zmienna
- // Ustawienia fal na podstawie levelData
+ 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/' + totalWaves, {
size: 60,
fill: 0x00FFFF,
weight: 800
@@ -1994,10 +1944,8 @@
LK.gui.top.addChild(wavesText);
wavesText.x = spacing;
wavesText.y = topMargin + 80;
updateUI();
- // ... reszta funkcji startGame pozostaje taka sama jak w ostatniej wersji ...
- // (Poniższy kod jest identyczny, ale wklejam dla pewności całość)
debugLayer = new Container();
specialTilesLayer = new Container();
towerLayer = new Container();
enemyLayerBottom = new Container();
@@ -2015,15 +1963,17 @@
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ę
}
}
}
}
@@ -2053,29 +2003,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');
@@ -2136,98 +2103,107 @@
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') {