/****
* 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();
// 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) {
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; // Reset score for pathfinding
}
function processNode(node, targetValue, targetNode) {
if (node && node.type != 1) {
// Typ 1 to ściana
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; // Diagonal cost
if (node.up && node.left && node.up.type != 1 && node.left.type != 1) {
processNode(node.upLeft, targetScore, node);
}
if (node.up && node.right && node.up.type != 1 && node.right.type != 1) {
processNode(node.upRight, targetScore, node);
}
if (node.down && node.right && node.down.type != 1 && node.right.type != 1) {
processNode(node.downRight, targetScore, node);
}
if (node.down && node.left && node.down.type != 1 && node.left.type != 1) {
processNode(node.downLeft, targetScore, node);
}
targetScore = node.score + 10000; // Straight cost
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 === 2) {
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 == 3) {
return true;
}
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
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 * CELL_SIZE + CELL_SIZE / 2;
self.y = grid.y + gridY * CELL_SIZE + CELL_SIZE / 2;
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;
}
}
}
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;
if (self.gridY <= 4 || self.gridY + 1 >= grid.cells[0].length - 4) {
validGridPlacement = false;
} else {
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) {
validGridPlacement = false;
break;
}
}
if (!validGridPlacement) {
break;
}
}
}
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 = 0;
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 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) {
return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : 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();
};
}
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') {
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 ---
var levelData = level1Data;
pathId = 1;
maxScore = 0;
enemies = [];
towers = [];
bullets = [];
selectedTower = null;
gold = levelData.initialGold;
lives = levelData.initialLives;
enemiesKilled = 0;
enemiesInCurrentWave = 0; // Nowa zmienna
// Ustawienia fal na podstawie levelData
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
});
wavesText.anchor.set(0.5, 0.5);
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();
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;
} else if (tileChar === 'S') {
cell.type = 2;
} else if (tileChar === 'E') {
cell.type = 3;
} else {
cell.type = 1;
}
}
}
}
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;
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;
}
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 upgradeMenuVisible = game.children.some(function (child) {
return child instanceof UpgradeMenu;
});
if (upgradeMenuVisible) {
return;
}
if (isBuildPanelOpen) {
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)) {
towerPreview.visible = true;
isDragging = true;
towerPreview.towerType = tower.towerType;
towerPreview.updateAppearance();
towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
toggleBuildPanel('close');
return;
}
}
}
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;
}
}
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;
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;
}
}
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 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
@@ -482,30 +482,16 @@
for (var j = 0; j < gridHeight; j++) {
self.cells[i][j] = {
score: 0,
pathId: 0,
- towersInRange: []
+ towersInRange: [],
+ specialEffect: null
};
}
}
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
var cell = self.cells[i][j];
- var cellType = i === 0 || i === gridWidth - 1 || j <= 4 || j >= gridHeight - 4 ? 1 : 0;
- if (i > 11 - 3 && i <= 11 + 3) {
- if (j === 0) {
- cellType = 2;
- self.spawns.push(cell);
- } else if (j <= 4) {
- cellType = 0;
- } else if (j === gridHeight - 1) {
- cellType = 3;
- self.goals.push(cell);
- } else if (j >= gridHeight - 4) {
- cellType = 0;
- }
- }
- cell.type = cellType;
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];
@@ -516,31 +502,34 @@
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 = [];
- if (j > 3 && j <= gridHeight - 4) {
- var debugCell = new DebugCell();
- self.addChild(debugCell);
- debugCell.cell = cell;
- debugCell.x = i * CELL_SIZE;
- debugCell.y = j * CELL_SIZE;
- cell.debugCell = debugCell;
- }
}
}
self.getCell = function (x, y) {
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) {
+ 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; // Reset score for pathfinding
}
function processNode(node, targetValue, targetNode) {
if (node && node.type != 1) {
+ // Typ 1 to ściana
if (node.pathId < pathId || targetValue < node.score) {
node.targets = [targetNode];
} else if (node.pathId == pathId && targetValue == node.score) {
node.targets.push(targetNode);
@@ -561,9 +550,9 @@
var nodes = toProcess;
toProcess = [];
for (var a = 0; a < nodes.length; a++) {
var node = nodes[a];
- var targetScore = node.score + 14142;
+ var targetScore = node.score + 14142; // Diagonal cost
if (node.up && node.left && node.up.type != 1 && node.left.type != 1) {
processNode(node.upLeft, targetScore, node);
}
if (node.up && node.right && node.up.type != 1 && node.right.type != 1) {
@@ -574,26 +563,31 @@
}
if (node.down && node.left && node.down.type != 1 && node.left.type != 1) {
processNode(node.downLeft, targetScore, node);
}
- targetScore = node.score + 10000;
+ targetScore = node.score + 10000; // Straight cost
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 === 2) {
+ 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.currentCellY < 4) {
- continue;
- }
if (enemy.isFlying) {
continue;
}
var target = self.getCell(enemy.cellX, enemy.cellY);
@@ -608,23 +602,17 @@
console.warn("Enemy blocked 2");
return true;
}
}
- console.log("Speed", new Date().getTime() - before);
+ console.log("Pathfinding complete in:", new Date().getTime() - before, "ms");
};
self.renderDebug = function () {
- for (var i = 0; i < gridWidth; i++) {
- for (var j = 0; j < gridHeight; j++) {
- var debugCell = self.cells[i][j].debugCell;
- if (debugCell) {
- debugCell.render(self.cells[i][j]);
- }
- }
- }
+ // 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.type == 3) {
+ if (cell && cell.type == 3) {
return true;
}
if (enemy.isFlying && enemy.shadow) {
enemy.shadow.x = enemy.x + 20;
@@ -632,113 +620,50 @@
if (enemy.children[0] && enemy.shadow.children[0]) {
enemy.shadow.children[0].rotation = enemy.children[0].rotation;
}
}
- var hasReachedEntryArea = enemy.currentCellY >= 4;
- if (!hasReachedEntryArea) {
+ // Prosta logika startu wroga - idzie prosto w dół do pierwszej komórki ścieżki
+ if (enemy.currentCellY < 5) {
enemy.currentCellY += enemy.speed;
- var angle = Math.PI / 2;
- if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
- enemy.children[0].targetRotation = angle;
- enemy.children[0].rotation = angle;
- } else if (enemy.children[0]) {
- if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
- tween.stop(enemy.children[0], {
- rotation: true
- });
- var currentRotation = enemy.children[0].rotation;
- var angleDiff = angle - currentRotation;
- while (angleDiff > Math.PI) {
- angleDiff -= Math.PI * 2;
- }
- while (angleDiff < -Math.PI) {
- angleDiff += Math.PI * 2;
- }
- enemy.children[0].targetRotation = angle;
- tween(enemy.children[0], {
- rotation: currentRotation + angleDiff
- }, {
- duration: 250,
- easing: tween.easeOut
- });
- }
- }
enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
- if (enemy.currentCellY >= 4) {
+ 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[0];
- if (self.goals.length > 1) {
- var closestDist = Infinity;
- for (var i = 0; i < self.goals.length; i++) {
- var goal = self.goals[i];
- var dx = goal.x - enemy.cellX;
- var dy = goal.y - enemy.cellY;
- var dist = dx * dx + dy * dy;
- if (dist < closestDist) {
- closestDist = dist;
- enemy.flyingTarget = goal;
- }
- }
- }
+ 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);
- if (enemy.children[0] && enemy.children[0].targetRotation === undefined) {
- enemy.children[0].targetRotation = angle;
- enemy.children[0].rotation = angle;
- } else if (enemy.children[0]) {
- if (Math.abs(angle - enemy.children[0].targetRotation) > 0.05) {
- tween.stop(enemy.children[0], {
- rotation: true
- });
- var currentRotation = enemy.children[0].rotation;
- var angleDiff = angle - currentRotation;
- while (angleDiff > Math.PI) {
- angleDiff -= Math.PI * 2;
- }
- while (angleDiff < -Math.PI) {
- angleDiff += Math.PI * 2;
- }
- enemy.children[0].targetRotation = angle;
- tween(enemy.children[0], {
- rotation: currentRotation + angleDiff
- }, {
- duration: 250,
- easing: tween.easeOut
- });
- }
- }
- enemy.cellX = Math.round(enemy.currentCellX);
- enemy.cellY = Math.round(enemy.currentCellY);
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) {
- enemy.currentTarget = cell.targets[0];
+ if (cell) {
+ enemy.currentTarget = cell.targets[Math.floor(Math.random() * cell.targets.length)];
+ }
}
if (enemy.currentTarget) {
- if (cell.score < enemy.currentTarget.score) {
- enemy.currentTarget = cell;
- }
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;
@@ -750,57 +675,8 @@
enemy.x = grid.x + enemy.currentCellX * CELL_SIZE;
enemy.y = grid.y + enemy.currentCellY * CELL_SIZE;
};
});
-var NextWaveButton = Container.expand(function () {
- var self = Container.call(this);
- var buttonBackground = self.attachAsset('notification', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- buttonBackground.width = 300;
- buttonBackground.height = 100;
- buttonBackground.tint = 0x0088FF;
- var buttonText = new Text2("Next Wave", {
- size: 50,
- fill: 0xFFFFFF,
- weight: 800
- });
- buttonText.anchor.set(0.5, 0.5);
- self.addChild(buttonText);
- self.enabled = false;
- self.visible = false;
- self.update = function () {
- if (waveIndicator && waveIndicator.gameStarted && currentWave < totalWaves) {
- self.enabled = true;
- self.visible = true;
- buttonBackground.tint = 0x0088FF;
- self.alpha = 1;
- } else {
- self.enabled = false;
- self.visible = false;
- buttonBackground.tint = 0x888888;
- self.alpha = 0.7;
- }
- };
- self.down = function () {
- if (!self.enabled) {
- return;
- }
- if (waveIndicator.gameStarted && currentWave < totalWaves) {
- currentWave++;
- waveTimer = 0;
- waveInProgress = true;
- waveSpawned = false;
- var waveType = waveIndicator.getWaveTypeName(currentWave);
- var enemyCount = waveIndicator.getEnemyCount(currentWave);
- var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) activated!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 150;
- }
- };
- return self;
-});
var Notification = Container.expand(function (message) {
var self = Container.call(this);
var notificationGraphics = self.attachAsset('notification', {
anchorX: 0.5,
@@ -1733,319 +1609,8 @@
}
};
return self;
});
-var WaveIndicator = Container.expand(function () {
- var self = Container.call(this);
- self.gameStarted = false;
- self.waveMarkers = [];
- self.waveTypes = [];
- self.enemyCounts = [];
- self.indicatorWidth = 0;
- self.lastBossType = null;
- var blockWidth = 400;
- var totalBlocksWidth = blockWidth * totalWaves;
- var startMarker = new Container();
- var startBlock = startMarker.attachAsset('notification', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- startBlock.width = blockWidth - 10;
- startBlock.height = 70 * 2;
- startBlock.tint = 0x00AA00;
- var startTextShadow = new Text2("Start Game", {
- size: 50,
- fill: 0x000000,
- weight: 800
- });
- startTextShadow.anchor.set(0.5, 0.5);
- startTextShadow.x = 4;
- startTextShadow.y = 4;
- startMarker.addChild(startTextShadow);
- var startText = new Text2("Start Game", {
- size: 50,
- fill: 0xFFFFFF,
- weight: 800
- });
- startText.anchor.set(0.5, 0.5);
- startMarker.addChild(startText);
- startMarker.x = -self.indicatorWidth;
- self.addChild(startMarker);
- self.waveMarkers.push(startMarker);
- startMarker.down = function () {
- if (!self.gameStarted) {
- self.gameStarted = true;
- currentWave = 0;
- waveTimer = nextWaveTime;
- startBlock.tint = 0x00FF00;
- startText.setText("Started!");
- startTextShadow.setText("Started!");
- startTextShadow.x = 4;
- startTextShadow.y = 4;
- var notification = game.addChild(new Notification("Game started! Wave 1 incoming!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 150;
- }
- };
- for (var i = 0; i < totalWaves; i++) {
- var marker = new Container();
- var block = marker.attachAsset('notification', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- block.width = blockWidth - 10;
- block.height = 70 * 2;
- var waveType = "normal";
- var enemyType = "normal";
- var enemyCount = 10;
- var isBossWave = (i + 1) % 10 === 0;
- if (i === 0) {
- block.tint = 0xAAAAAA;
- waveType = "Normal";
- enemyType = "normal";
- enemyCount = 10;
- } else if (i === 1) {
- block.tint = 0x00AAFF;
- waveType = "Fast";
- enemyType = "fast";
- enemyCount = 10;
- } else if (i === 2) {
- block.tint = 0xAA0000;
- waveType = "Immune";
- enemyType = "immune";
- enemyCount = 10;
- } else if (i === 3) {
- block.tint = 0xFFFF00;
- waveType = "Flying";
- enemyType = "flying";
- enemyCount = 10;
- } else if (i === 4) {
- block.tint = 0xFF00FF;
- waveType = "Swarm";
- enemyType = "swarm";
- enemyCount = 30;
- } else if (isBossWave) {
- var bossTypes = ['normal', 'fast', 'immune', 'flying'];
- var bossTypeIndex = Math.floor((i + 1) / 10) - 1;
- if (i === totalWaves - 1) {
- enemyType = 'flying';
- waveType = "Boss Flying";
- block.tint = 0xFFFF00;
- } else {
- enemyType = bossTypes[bossTypeIndex % bossTypes.length];
- switch (enemyType) {
- case 'normal':
- block.tint = 0xAAAAAA;
- waveType = "Boss Normal";
- break;
- case 'fast':
- block.tint = 0x00AAFF;
- waveType = "Boss Fast";
- break;
- case 'immune':
- block.tint = 0xAA0000;
- waveType = "Boss Immune";
- break;
- case 'flying':
- block.tint = 0xFFFF00;
- waveType = "Boss Flying";
- break;
- }
- }
- enemyCount = 1;
- switch (enemyType) {
- case 'normal':
- block.tint = 0xAAAAAA;
- break;
- case 'fast':
- block.tint = 0x00AAFF;
- break;
- case 'immune':
- block.tint = 0xAA0000;
- break;
- case 'flying':
- block.tint = 0xFFFF00;
- break;
- default:
- block.tint = 0xFF0000;
- break;
- }
- } else if ((i + 1) % 5 === 0) {
- block.tint = 0x00AAFF;
- waveType = "Fast";
- enemyType = "fast";
- enemyCount = 10;
- } else if ((i + 1) % 4 === 0) {
- block.tint = 0xAA0000;
- waveType = "Immune";
- enemyType = "immune";
- enemyCount = 10;
- } else if ((i + 1) % 7 === 0) {
- block.tint = 0xFFFF00;
- waveType = "Flying";
- enemyType = "flying";
- enemyCount = 10;
- } else if ((i + 1) % 3 === 0) {
- block.tint = 0xFF00FF;
- waveType = "Swarm";
- enemyType = "swarm";
- enemyCount = 30;
- } else {
- block.tint = 0xAAAAAA;
- waveType = "Normal";
- enemyType = "normal";
- enemyCount = 10;
- }
- if (isBossWave && enemyType !== 'swarm') {
- var bossIndicator = marker.attachAsset('towerLevelIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- bossIndicator.width = 30;
- bossIndicator.height = 30;
- bossIndicator.tint = 0xFFD700;
- bossIndicator.y = -block.height / 2 - 15;
- waveType = "BOSS";
- }
- self.waveTypes[i] = enemyType;
- self.enemyCounts[i] = enemyCount;
- var waveTypeShadow = new Text2(waveType, {
- size: 56,
- fill: 0x000000,
- weight: 800
- });
- waveTypeShadow.anchor.set(0.5, 0.5);
- waveTypeShadow.x = 4;
- waveTypeShadow.y = 4;
- marker.addChild(waveTypeShadow);
- var waveTypeText = new Text2(waveType, {
- size: 56,
- fill: 0xFFFFFF,
- weight: 800
- });
- waveTypeText.anchor.set(0.5, 0.5);
- waveTypeText.y = 0;
- marker.addChild(waveTypeText);
- var waveNumShadow = new Text2((i + 1).toString(), {
- size: 48,
- fill: 0x000000,
- weight: 800
- });
- waveNumShadow.anchor.set(1.0, 1.0);
- waveNumShadow.x = blockWidth / 2 - 16 + 5;
- waveNumShadow.y = block.height / 2 - 12 + 5;
- marker.addChild(waveNumShadow);
- var waveNum = new Text2((i + 1).toString(), {
- size: 48,
- fill: 0xFFFFFF,
- weight: 800
- });
- waveNum.anchor.set(1.0, 1.0);
- waveNum.x = blockWidth / 2 - 16;
- waveNum.y = block.height / 2 - 12;
- marker.addChild(waveNum);
- marker.x = -self.indicatorWidth + (i + 1) * blockWidth;
- self.addChild(marker);
- self.waveMarkers.push(marker);
- }
- self.getWaveType = function (waveNumber) {
- if (waveNumber < 1 || waveNumber > totalWaves) {
- return "normal";
- }
- var waveType = self.waveTypes[waveNumber - 1];
- return waveType;
- };
- self.getEnemyCount = function (waveNumber) {
- if (waveNumber < 1 || waveNumber > totalWaves) {
- return 10;
- }
- return self.enemyCounts[waveNumber - 1];
- };
- self.getWaveTypeName = function (waveNumber) {
- var type = self.getWaveType(waveNumber);
- var typeName = type.charAt(0).toUpperCase() + type.slice(1);
- if (waveNumber % 10 === 0 && waveNumber > 0 && type !== 'swarm') {
- typeName = "BOSS";
- }
- return typeName;
- };
- self.positionIndicator = new Container();
- var indicator = self.positionIndicator.attachAsset('towerLevelIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- indicator.width = blockWidth - 10;
- indicator.height = 16;
- indicator.tint = 0xffad0e;
- indicator.y = -65;
- var indicator2 = self.positionIndicator.attachAsset('towerLevelIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- indicator2.width = blockWidth - 10;
- indicator2.height = 16;
- indicator2.tint = 0xffad0e;
- indicator2.y = 65;
- var leftWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- leftWall.width = 16;
- leftWall.height = 146;
- leftWall.tint = 0xffad0e;
- leftWall.x = -(blockWidth - 16) / 2;
- var rightWall = self.positionIndicator.attachAsset('towerLevelIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- rightWall.width = 16;
- rightWall.height = 146;
- rightWall.tint = 0xffad0e;
- rightWall.x = (blockWidth - 16) / 2;
- self.addChild(self.positionIndicator);
- self.update = function () {
- var progress = waveTimer / nextWaveTime;
- var moveAmount = (progress + currentWave) * blockWidth;
- for (var i = 0; i < self.waveMarkers.length; i++) {
- var marker = self.waveMarkers[i];
- marker.x = -moveAmount + i * blockWidth;
- }
- self.positionIndicator.x = 0;
- for (var i = 0; i < totalWaves + 1; i++) {
- var marker = self.waveMarkers[i];
- if (i === 0) {
- continue;
- }
- var block = marker.children[0];
- if (i - 1 < currentWave) {
- block.alpha = .5;
- }
- }
- self.handleWaveProgression = function () {
- if (!self.gameStarted) {
- return;
- }
- if (currentWave < totalWaves) {
- waveTimer++;
- if (waveTimer >= nextWaveTime) {
- waveTimer = 0;
- currentWave++;
- waveInProgress = true;
- waveSpawned = false;
- if (currentWave != 1) {
- var waveType = self.getWaveTypeName(currentWave);
- var enemyCount = self.getEnemyCount(currentWave);
- var notification = game.addChild(new Notification("Wave " + currentWave + " (" + waveType + " - " + enemyCount + " enemies) incoming!"));
- notification.x = 2048 / 2;
- notification.y = grid.height - 150;
- }
- }
- }
- };
- self.handleWaveProgression();
- };
- return self;
-});
/****
* Initialize Game
****/
@@ -2057,26 +1622,44 @@
/****
* Game Code
****/
+/**** * Game Code
+****/
var CELL_SIZE = 76;
-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;
- }
- });
-}
+// --- GŁÓWNE ZMIENNE STANU GRY ---
+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
@@ -2087,9 +1670,8 @@
fill: 0x00FF00,
weight: 800
});
livesText.anchor.set(0.5, 0.5);
-// ZMIANA: scoreText na enemiesText
var enemiesText = new Text2('Enemies: 0/0', {
size: 60,
fill: 0xFF0000,
weight: 800
@@ -2099,18 +1681,74 @@
var centerX = 2048 / 2;
var spacing = 400;
LK.gui.top.addChild(goldText);
LK.gui.top.addChild(livesText);
-LK.gui.top.addChild(enemiesText); // ZMIANA: dodajemy nowy tekst
+LK.gui.top.addChild(enemiesText);
livesText.x = 0;
livesText.y = topMargin;
goldText.x = -spacing;
goldText.y = topMargin;
-enemiesText.x = spacing; // ZMIANA: pozycjonujemy nowy tekst
+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) {
+ return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
+}
+// --- FUNKCJE EKRANÓW ---
function showTitleScreen() {
if (titleScreenContainer) {
titleScreenContainer.destroy();
}
@@ -2165,13 +1803,11 @@
}
levelSelectContainer = new Container();
game.addChild(levelSelectContainer);
currentScreenState = 'levelSelect';
- // Poprawka: Ukrywamy górne UI w menu wyboru poziomu
if (LK.gui.top) {
LK.gui.top.visible = false;
}
- // Nagłówek (placeholder)
var selectTitle = new Text2("WYBIERZ POZIOM", {
size: 100,
fill: 0xFFFFFF,
weight: 700
@@ -2179,9 +1815,8 @@
selectTitle.anchor.set(0.5, 0.5);
selectTitle.x = 2048 / 2;
selectTitle.y = 400;
levelSelectContainer.addChild(selectTitle);
- // Przyciski poziomów (placeholdery)
var levelButton1 = new Container();
levelButton1.x = 2048 / 2;
levelButton1.y = 800;
levelSelectContainer.addChild(levelButton1);
@@ -2202,9 +1837,8 @@
levelButton1.down = function () {
console.log("Wybrano Poziom 1. Rozpoczynam grę...");
startGame(1);
};
- // Przycisk "Powrót"
var backButton = new Container();
backButton.x = 2048 / 2;
backButton.y = 2732 - 300;
levelSelectContainer.addChild(backButton);
@@ -2229,9 +1863,94 @@
}
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') {
+ 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;
@@ -2243,60 +1962,96 @@
currentScreenState = 'gameplay';
if (LK.gui.top) {
LK.gui.top.visible = true;
}
- var pathId = 1;
- var maxScore = 0;
- var enemies = [];
- var towers = [];
- var bullets = [];
- var defenses = [];
- var selectedTower = null;
- var gold = 80;
- var lives = 20;
- // ZMIANA: usunęliśmy 'score', dodajemy liczniki wrogów
- var enemiesKilled = 0;
- var totalEnemiesInLevel = 50; // Placeholder dla poziomu 1
- var currentWave = 0;
- var totalWaves = 50;
- var waveTimer = 0;
- var waveInProgress = false;
- var waveSpawned = false;
- var nextWaveTime = 12000 / 2;
- var sourceTower = null;
- var enemiesToSpawn = 10;
- // ZMIANA: updateUI będzie teraz aktualizować nowy licznik
- function updateUI() {
- goldText.setText('Gold: ' + gold);
- livesText.setText('Lives: ' + lives);
- enemiesText.setText('Enemies: ' + enemiesKilled + '/' + totalEnemiesInLevel);
- }
- // Inicjalizujemy UI na starcie poziomu
+ // --- WCZYTANIE DANYCH POZIOMU ---
+ var levelData = level1Data;
+ pathId = 1;
+ maxScore = 0;
+ enemies = [];
+ towers = [];
+ bullets = [];
+ selectedTower = null;
+ gold = levelData.initialGold;
+ lives = levelData.initialLives;
+ enemiesKilled = 0;
+ enemiesInCurrentWave = 0; // Nowa zmienna
+ // Ustawienia fal na podstawie levelData
+ 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
+ });
+ wavesText.anchor.set(0.5, 0.5);
+ LK.gui.top.addChild(wavesText);
+ wavesText.x = spacing;
+ wavesText.y = topMargin + 80;
updateUI();
- function setGold(value) {
- gold = value;
- updateUI();
- }
- var debugLayer = new Container();
- var towerLayer = new Container();
- var enemyLayerBottom = new Container();
- var enemyLayerMiddle = new Container();
- var enemyLayerTop = new Container();
- var enemyLayer = new Container();
+ // ... 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();
+ enemyLayerMiddle = new Container();
+ enemyLayerTop = new Container();
+ enemyLayer = new Container();
enemyLayer.addChild(enemyLayerBottom);
enemyLayer.addChild(enemyLayerMiddle);
enemyLayer.addChild(enemyLayerTop);
- var grid = new Grid(24, 29 + 6);
+ 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;
+ } else if (tileChar === 'S') {
+ cell.type = 2;
+ } else if (tileChar === 'E') {
+ cell.type = 3;
+ } else {
+ cell.type = 1;
+ }
+ }
+ }
+ }
+ 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();
- grid.renderDebug();
- debugLayer.addChild(grid);
game.addChild(debugLayer);
+ game.addChild(specialTilesLayer);
game.addChild(towerLayer);
game.addChild(enemyLayer);
- var offset = 0;
- var towerPreview = new TowerPreview();
+ towerPreview = new TowerPreview();
game.addChild(towerPreview);
towerPreview.visible = false;
var isDragging = false;
function wouldBlockPath(gridX, gridY) {
@@ -2317,35 +2072,10 @@
for (var i = 0; i < cells.length; i++) {
cells[i].cell.type = cells[i].originalType;
}
grid.pathFind();
- grid.renderDebug();
return blocked;
}
- 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) {
- return waveIndicator && waveIndicator.gameStarted ? Math.floor(totalValue * 0.6) : totalValue;
- }
function placeTower(gridX, gridY, towerType) {
var towerCost = getTowerCost(towerType);
if (gold >= towerCost) {
var tower = new Tower(towerType || 'default');
@@ -2353,35 +2083,89 @@
towerLayer.addChild(tower);
towers.push(tower);
setGold(gold - towerCost);
grid.pathFind();
- grid.renderDebug();
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 upgradeMenuVisible = game.children.some(function (child) {
return child instanceof UpgradeMenu;
});
if (upgradeMenuVisible) {
return;
}
- for (var i = 0; i < sourceTowers.length; i++) {
- var tower = sourceTowers[i];
- if (x >= tower.x - tower.width / 2 && x <= tower.x + tower.width / 2 && y >= tower.y - tower.height / 2 && y <= tower.y + tower.height / 2) {
- towerPreview.visible = true;
- isDragging = true;
- towerPreview.towerType = tower.towerType;
- towerPreview.updateAppearance();
- towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
- break;
+ if (isBuildPanelOpen) {
+ 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)) {
+ towerPreview.visible = true;
+ isDragging = true;
+ towerPreview.towerType = tower.towerType;
+ towerPreview.updateAppearance();
+ towerPreview.snapToGrid(x, y - CELL_SIZE * 1.5);
+ toggleBuildPanel('close');
+ return;
+ }
}
}
+ 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);
@@ -2390,13 +2174,10 @@
game.up = function (x, y, obj) {
var clickedOnTower = false;
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
- var towerLeft = tower.x - tower.width / 2;
- var towerRight = tower.x + tower.width / 2;
- var towerTop = tower.y - tower.height / 2;
- var towerBottom = tower.y + tower.height / 2;
- if (x >= towerLeft && x <= towerRight && y >= towerTop && y <= towerBottom) {
+ var towerBounds = tower.getBounds();
+ if (towerBounds.contains(x - tower.x + tower.width / 2, y - tower.y + tower.height / 2)) {
clickedOnTower = true;
break;
}
}
@@ -2406,31 +2187,24 @@
if (upgradeMenus.length > 0 && !isDragging && !clickedOnTower) {
var clickedOnMenu = false;
for (var i = 0; i < upgradeMenus.length; i++) {
var menu = upgradeMenus[i];
- var menuWidth = 2048;
- var menuHeight = 450;
- var menuLeft = menu.x - menuWidth / 2;
- var menuRight = menu.x + menuWidth / 2;
- var menuTop = menu.y - menuHeight / 2;
- var menuBottom = menu.y + menuHeight / 2;
- if (x >= menuLeft && x <= menuRight && y >= menuTop && y <= menuBottom) {
+ 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++) {
- var menu = upgradeMenus[i];
- hideUpgradeMenu(menu);
+ 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;
- grid.renderDebug();
}
}
if (isDragging) {
isDragging = false;
@@ -2451,131 +2225,105 @@
notification.x = 2048 / 2;
notification.y = grid.height - 50;
}
towerPreview.visible = false;
- if (isDragging) {
- var upgradeMenus = game.children.filter(function (child) {
- return child instanceof UpgradeMenu;
- });
- for (var i = 0; i < upgradeMenus.length; i++) {
- upgradeMenus[i].destroy();
- }
- }
}
};
- var waveIndicator = new WaveIndicator();
- waveIndicator.x = 2048 / 2;
- waveIndicator.y = 2732 - 80;
- game.addChild(waveIndicator);
- var nextWaveButtonContainer = new Container();
- var nextWaveButton = new NextWaveButton();
- nextWaveButton.x = 2048 - 200;
- nextWaveButton.y = 2732 - 100 + 20;
- nextWaveButtonContainer.addChild(nextWaveButton);
- game.addChild(nextWaveButtonContainer);
- var towerTypes = ['default', 'rapid', 'sniper', 'splash', 'slow', 'poison'];
- var sourceTowers = [];
- var towerSpacing = 300;
- var startX = 2048 / 2 - towerTypes.length * towerSpacing / 2 + towerSpacing / 2;
- var towerY = 2732 - CELL_SIZE * 3 - 90;
- for (var i = 0; i < towerTypes.length; i++) {
- var tower = new SourceTower(towerTypes[i]);
- tower.x = startX + i * towerSpacing;
- tower.y = towerY;
- towerLayer.addChild(tower);
- sourceTowers.push(tower);
- }
- sourceTower = null;
- enemiesToSpawn = 10;
}
game.update = function () {
if (currentScreenState === 'gameplay') {
- if (waveInProgress) {
- if (!waveSpawned) {
- waveSpawned = true;
- var waveType = waveIndicator.getWaveType(currentWave);
- var enemyCount = waveIndicator.getEnemyCount(currentWave);
- var isBossWave = currentWave % 10 === 0 && currentWave > 0;
- if (isBossWave && waveType !== 'swarm') {
- enemyCount = 1;
+ // --- 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);
}
- var healthMultiplier = Math.pow(1.12, currentWave);
- enemy.maxHealth = Math.round(enemy.maxHealth * healthMultiplier);
- enemy.health = enemy.maxHealth;
- var gridWidth = 24;
- var midPoint = Math.floor(gridWidth / 2);
- var availableColumns = [];
- for (var col = midPoint - 3; col < midPoint + 3; col++) {
- var columnOccupied = false;
- for (var e = 0; e < enemies.length; e++) {
- if (enemies[e].cellX === col && enemies[e].currentCellY < 4) {
- columnOccupied = true;
- break;
- }
- }
- if (!columnOccupied) {
- availableColumns.push(col);
- }
- }
- var spawnX;
- if (availableColumns.length > 0) {
- spawnX = availableColumns[Math.floor(Math.random() * availableColumns.length)];
- } else {
- spawnX = midPoint - 3 + Math.floor(Math.random() * 6);
- }
- var spawnY = -1 - Math.random() * 5;
- enemy.cellX = spawnX;
- enemy.cellY = 5;
- enemy.currentCellX = spawnX;
- enemy.currentCellY = spawnY;
- enemy.waveNumber = currentWave;
enemies.push(enemy);
}
- }
- 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;
}
}
+ 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);
- // ZMIANA: Zamiast dodawać score, zwiększamy licznik zabitych wrogów
- 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;
}