User prompt
las habilitats no tenan preu
User prompt
fes visual al gastar una habilitat āŖš” Consider importing and using the following plugins: @upit/tween.v1
User prompt
crea un asset per la torra que reanima las torras
User prompt
crea habilitats per mi
User prompt
fes que els diners emb donguin mes
User prompt
borra que jo pugui perdre
User prompt
fes el joc mes dificil
User prompt
fes que quan la vida baixa de 0 mort la torra o la unit
User prompt
al comprar una unit fes que apareixin 5 pero fes que el preu sigui per 5
User prompt
al comprar una unit fes que apareixin 5
User prompt
crea una torra que torna a la vida a altras torras
User prompt
posa habilitats a els murs hi ha las minas
User prompt
fes que las trampas i els murs es puguin millorar
User prompt
crea trampas i murs per la ai
User prompt
fes que la base tambe dispari
User prompt
la ultima millora dona una habilitat a la torra
User prompt
crea novas milloras per las torras
User prompt
fes un asset per cada torra
User prompt
fes mes classes de torras
User prompt
fes que la ai no contrueixi si hi ha units a prop
User prompt
fes la unit de mele mes lenta pero mes barata
User prompt
fes que las units si tenan rang per atacar es deixin de moura
User prompt
fes que las torras de curacio curin la vida de las torras que estiguin al costat āŖš” Consider importing and using the following plugins: @upit/tween.v1
User prompt
fes que cada unit tingui el seu asset
User prompt
crea units a mele
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AreaTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('areaTowerAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Add explosion indicator
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -50;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -50;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
var explosionIndicator = self.attachAsset('upgradeIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
explosionIndicator.x = 0;
explosionIndicator.y = 0;
explosionIndicator.tint = 0xff0000; // Red explosion symbol
explosionIndicator.scaleX = 1.3;
explosionIndicator.scaleY = 1.3;
self.towerType = 'area';
self.health = 140;
self.maxHealth = 140;
self.range = 180;
self.damage = 25; // Base damage per unit
self.areaRadius = 80; // Area effect radius
self.shootCooldown = 0;
self.target = null;
self.cost = 130;
self.canUpgrade = function () {
return false; // Area towers cannot be upgraded
};
self.getUpgradeCost = function () {
return 0; // Area towers cannot be upgraded
};
self.update = function () {
// Find target (center of enemy group)
if (!self.target || !self.target.parent) {
self.target = null;
var bestTarget = null;
var maxUnitsInArea = 0;
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (distance <= self.range) {
// Count how many units would be hit if we target this unit
var unitsInArea = 0;
for (var j = 0; j < playerUnits.length; j++) {
var otherUnit = playerUnits[j];
var areaDistance = Math.sqrt(Math.pow(otherUnit.x - unit.x, 2) + Math.pow(otherUnit.y - unit.y, 2));
if (areaDistance <= self.areaRadius) {
unitsInArea++;
}
}
if (unitsInArea > maxUnitsInArea) {
maxUnitsInArea = unitsInArea;
bestTarget = unit;
}
}
}
self.target = bestTarget;
}
// Shoot area effect
if (self.target && self.shootCooldown <= 0) {
// Create area explosion at target location
var targetX = self.target.x;
var targetY = self.target.y;
// Damage all units in area
var unitsHit = 0;
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - targetX, 2) + Math.pow(unit.y - targetY, 2));
if (distance <= self.areaRadius) {
unit.takeDamage(self.damage);
LK.effects.flashObject(unit, 0xff6600, 300);
unitsHit++;
}
}
if (unitsHit > 0) {
// Visual explosion effect
tween(explosionIndicator, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0.3
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(explosionIndicator, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
LK.getSound('shoot').play();
}
self.shootCooldown = 150; // 2.5 second cooldown
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var AttackUnit = Container.expand(function () {
var self = Container.call(this);
var unitGraphics = self.attachAsset('basicUnitAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -40;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -40;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
self.health = 100;
self.maxHealth = 100;
self.speed = 2;
self.damage = 25;
self.range = 150;
self.shootCooldown = 0;
self.target = null;
self.lastX = 0;
self.lastY = 0;
self.currentWaypoint = 0;
self.isMovingToWaypoint = false;
// Create path through tower grid
var pathWaypoints = [];
pathWaypoints.push({
x: 400,
y: self.y
});
// Tower grid parameters
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Serpentine path through towers
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
pathWaypoints.push({
x: 1600,
y: 1000
});
self.pathWaypoints = pathWaypoints;
self.followPath = function () {
if (self.isMovingToWaypoint) return;
if (self.currentWaypoint >= self.pathWaypoints.length) {
// Reached end of path, move directly to base
self.x += self.speed;
return;
}
var waypoint = self.pathWaypoints[self.currentWaypoint];
var distance = Math.sqrt(Math.pow(waypoint.x - self.x, 2) + Math.pow(waypoint.y - self.y, 2));
var duration = distance / self.speed * 16.67; // Convert speed to ms (60fps = 16.67ms per frame)
self.isMovingToWaypoint = true;
tween(self, {
x: waypoint.x,
y: waypoint.y
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.currentWaypoint++;
self.isMovingToWaypoint = false;
}
});
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Find target (prioritize base, then towers)
if (!self.target || !self.target.parent) {
self.target = null;
var closestTarget = null;
var closestDistance = Infinity;
// Check distance to enemy base first
if (enemyBase && enemyBase.parent) {
var baseDistance = Math.sqrt(Math.pow(enemyBase.x - self.x, 2) + Math.pow(enemyBase.y - self.y, 2));
if (baseDistance <= self.range) {
closestTarget = enemyBase;
closestDistance = baseDistance;
}
}
// Check towers if no base target or if tower is closer
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.parent) {
var towerDistance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (towerDistance <= self.range && towerDistance < closestDistance) {
closestDistance = towerDistance;
closestTarget = tower;
}
}
}
self.target = closestTarget;
}
// Attack target if in range
if (self.target && self.shootCooldown <= 0) {
var bullet = new UnitBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
unitBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 60; // 1 second cooldown at 60fps
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
// Move towards enemy base using waypoints only if no target in range
if (!self.target) {
self.followPath();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
return true; // Unit is dead
}
return false;
};
return self;
});
var BasicTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('basicTowerAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -50;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -50;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
self.towerType = 'basic';
self.health = 100;
self.maxHealth = 100;
self.range = 150;
self.damage = 20;
self.shootCooldown = 0;
self.target = null;
self.cost = 75;
self.canUpgrade = function () {
return false; // Basic towers cannot be upgraded
};
self.getUpgradeCost = function () {
return 0; // Basic towers cannot be upgraded
};
self.update = function () {
// Find target
if (!self.target || !self.target.parent) {
self.target = null;
var closestUnit = null;
var closestDistance = Infinity;
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (distance <= self.range && distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
self.target = closestUnit;
}
// Shoot at target
if (self.target && self.shootCooldown <= 0) {
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
towerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 90; // 1.5 second cooldown
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var BasicUnit = Container.expand(function () {
var self = Container.call(this);
var unitGraphics = self.attachAsset('basicUnitAsset', {
anchorX: 0.5,
anchorY: 0.5
});
unitGraphics.tint = 0x87CEEB; // Sky blue color for basic unit
unitGraphics.scaleX = 0.9;
unitGraphics.scaleY = 0.9;
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -35;
healthBarBg.scaleX = 0.8;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -35;
healthBar.scaleX = 0.8;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent * 0.8;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
self.unitType = 'basic';
self.health = 80;
self.maxHealth = 80;
self.speed = 2;
self.damage = 20;
self.range = 140;
self.cost = 40;
self.shootCooldown = 0;
self.target = null;
self.lastX = 0;
self.lastY = 0;
self.currentWaypoint = 0;
self.isMovingToWaypoint = false;
// Create path through tower grid
var pathWaypoints = [];
pathWaypoints.push({
x: 400,
y: self.y
});
// Tower grid parameters
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Serpentine path through towers
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
pathWaypoints.push({
x: 1600,
y: 1000
});
self.pathWaypoints = pathWaypoints;
self.followPath = function () {
if (self.isMovingToWaypoint) return;
if (self.currentWaypoint >= self.pathWaypoints.length) {
self.x += self.speed;
return;
}
var waypoint = self.pathWaypoints[self.currentWaypoint];
var distance = Math.sqrt(Math.pow(waypoint.x - self.x, 2) + Math.pow(waypoint.y - self.y, 2));
var duration = distance / self.speed * 16.67;
self.isMovingToWaypoint = true;
tween(self, {
x: waypoint.x,
y: waypoint.y
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.currentWaypoint++;
self.isMovingToWaypoint = false;
}
});
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (!self.target || !self.target.parent) {
self.target = null;
var closestTarget = null;
var closestDistance = Infinity;
if (enemyBase && enemyBase.parent) {
var baseDistance = Math.sqrt(Math.pow(enemyBase.x - self.x, 2) + Math.pow(enemyBase.y - self.y, 2));
if (baseDistance <= self.range) {
closestTarget = enemyBase;
closestDistance = baseDistance;
}
}
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.parent) {
var towerDistance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (towerDistance <= self.range && towerDistance < closestDistance) {
closestDistance = towerDistance;
closestTarget = tower;
}
}
}
self.target = closestTarget;
}
if (self.target && self.shootCooldown <= 0) {
var bullet = new UnitBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
unitBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 75;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (!self.target) {
self.followPath();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var EnemyBase = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('enemyBase', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 500;
self.maxHealth = 500;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
return true; // Base destroyed - player wins!
}
return false;
};
return self;
});
// Game arrays to track entities
var EnemyTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('enemyTower', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -50;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -50;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
// Upgrade indicator (initially hidden)
var upgradeIndicator = self.attachAsset('upgradeIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
upgradeIndicator.x = 30;
upgradeIndicator.y = -30;
upgradeIndicator.visible = false;
self.level = 1;
self.maxLevel = 3;
self.health = 150;
self.maxHealth = 150;
self.baseRange = 200;
self.baseDamage = 30;
self.range = self.baseRange;
self.damage = self.baseDamage;
self.shootCooldown = 0;
self.target = null;
self.updateStats = function () {
var multiplier = 1 + (self.level - 1) * 0.5; // 50% increase per level
self.range = Math.floor(self.baseRange * multiplier);
self.damage = Math.floor(self.baseDamage * multiplier);
self.maxHealth = Math.floor(150 * multiplier);
self.health = Math.min(self.health, self.maxHealth);
// Update visual appearance based on level
if (self.level === 2) {
towerGraphics.tint = 0xc0392b; // Darker red
upgradeIndicator.visible = true;
upgradeIndicator.tint = 0xffd700; // Gold
} else if (self.level === 3) {
towerGraphics.tint = 0x8b0000; // Dark red
upgradeIndicator.visible = true;
upgradeIndicator.tint = 0xff4500; // Orange red
}
};
self.canUpgrade = function () {
return self.level < self.maxLevel;
};
self.getUpgradeCost = function () {
return 75 * self.level; // Cost increases with level
};
self.upgrade = function () {
if (self.canUpgrade()) {
self.level++;
self.updateStats();
LK.effects.flashObject(self, 0xffd700, 500);
return true;
}
return false;
};
self.update = function () {
// Increase range and damage if base is low on health
var baseHealthPercent = enemyBase ? enemyBase.health / enemyBase.maxHealth : 1;
var bonusRange = baseHealthPercent < 0.5 ? 100 : 0;
var bonusDamage = baseHealthPercent < 0.3 ? 20 : 0;
var currentRange = self.range + bonusRange;
var currentDamage = self.damage + bonusDamage;
// Find target
if (!self.target || !self.target.parent) {
self.target = null;
var closestUnit = null;
var closestDistance = Infinity;
// Prioritize units closer to base
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
var distanceToBase = Math.sqrt(Math.pow(unit.x - enemyBase.x, 2) + Math.pow(unit.y - enemyBase.y, 2));
if (distance <= currentRange) {
// Prioritize units closer to base
var priority = distance - distanceToBase * 0.3;
if (priority < closestDistance) {
closestDistance = priority;
closestUnit = unit;
}
}
}
self.target = closestUnit;
}
// Shoot at target
if (self.target && self.shootCooldown <= 0) {
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = currentDamage;
towerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Shoot faster when base is in danger
var shootCooldown = baseHealthPercent < 0.5 ? 60 : 90;
self.shootCooldown = shootCooldown;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var FastTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('fastTowerAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -40;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -40;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
self.towerType = 'fast';
self.health = 80;
self.maxHealth = 80;
self.range = 180;
self.damage = 15;
self.shootCooldown = 0;
self.target = null;
self.cost = 100;
self.canUpgrade = function () {
return false; // Fast towers cannot be upgraded
};
self.getUpgradeCost = function () {
return 0; // Fast towers cannot be upgraded
};
self.update = function () {
// Find target
if (!self.target || !self.target.parent) {
self.target = null;
var closestUnit = null;
var closestDistance = Infinity;
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (distance <= self.range && distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
self.target = closestUnit;
}
// Shoot at target with fast rate
if (self.target && self.shootCooldown <= 0) {
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
towerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 30; // 0.5 second cooldown (very fast)
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var FastUnit = Container.expand(function () {
var self = Container.call(this);
var unitGraphics = self.attachAsset('fastUnitAsset', {
anchorX: 0.5,
anchorY: 0.5
});
unitGraphics.tint = 0x32CD32; // Lime green color for fast unit
unitGraphics.scaleX = 0.8;
unitGraphics.scaleY = 0.8;
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -32;
healthBarBg.scaleX = 0.7;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -32;
healthBar.scaleX = 0.7;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent * 0.7;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
self.unitType = 'fast';
self.health = 60;
self.maxHealth = 60;
self.speed = 4;
self.damage = 15;
self.range = 120;
self.cost = 60;
self.shootCooldown = 0;
self.target = null;
self.lastX = 0;
self.lastY = 0;
self.currentWaypoint = 0;
self.isMovingToWaypoint = false;
// Create path through tower grid
var pathWaypoints = [];
pathWaypoints.push({
x: 400,
y: self.y
});
// Tower grid parameters
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Serpentine path through towers
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
pathWaypoints.push({
x: 1600,
y: 1000
});
self.pathWaypoints = pathWaypoints;
self.followPath = function () {
if (self.isMovingToWaypoint) return;
if (self.currentWaypoint >= self.pathWaypoints.length) {
self.x += self.speed;
return;
}
var waypoint = self.pathWaypoints[self.currentWaypoint];
var distance = Math.sqrt(Math.pow(waypoint.x - self.x, 2) + Math.pow(waypoint.y - self.y, 2));
var duration = distance / self.speed * 16.67;
self.isMovingToWaypoint = true;
tween(self, {
x: waypoint.x,
y: waypoint.y
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.currentWaypoint++;
self.isMovingToWaypoint = false;
}
});
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (!self.target || !self.target.parent) {
self.target = null;
var closestTarget = null;
var closestDistance = Infinity;
if (enemyBase && enemyBase.parent) {
var baseDistance = Math.sqrt(Math.pow(enemyBase.x - self.x, 2) + Math.pow(enemyBase.y - self.y, 2));
if (baseDistance <= self.range) {
closestTarget = enemyBase;
closestDistance = baseDistance;
}
}
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.parent) {
var towerDistance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (towerDistance <= self.range && towerDistance < closestDistance) {
closestDistance = towerDistance;
closestTarget = tower;
}
}
}
self.target = closestTarget;
}
if (self.target && self.shootCooldown <= 0) {
var bullet = new UnitBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
unitBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 45; // Faster shooting
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (!self.target) {
self.followPath();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var HealTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('healTowerAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -50;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -50;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
// Add a cross symbol effect
var crossIndicator = self.attachAsset('upgradeIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
crossIndicator.x = 0;
crossIndicator.y = 0;
crossIndicator.tint = 0xffffff; // White cross
crossIndicator.scaleX = 1.5;
crossIndicator.scaleY = 1.5;
self.towerType = 'heal';
self.health = 120;
self.maxHealth = 120;
self.range = 200; // Healing range
self.healAmount = 15;
self.healCooldown = 0;
self.target = null;
self.cost = 110;
self.canUpgrade = function () {
return false; // Heal towers cannot be upgraded
};
self.getUpgradeCost = function () {
return 0; // Heal towers cannot be upgraded
};
self.update = function () {
// Find damaged towers to heal
if (self.healCooldown <= 0) {
self.target = null;
var bestTarget = null;
var lowestHealthPercent = 1;
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower !== self && tower.parent) {
var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (distance <= self.range) {
var healthPercent = tower.health / tower.maxHealth;
if (healthPercent < 1 && healthPercent < lowestHealthPercent) {
lowestHealthPercent = healthPercent;
bestTarget = tower;
}
}
}
}
self.target = bestTarget;
}
// Heal target
if (self.target && self.healCooldown <= 0) {
var healingAmount = Math.min(self.healAmount, self.target.maxHealth - self.target.health);
if (healingAmount > 0) {
self.target.health += healingAmount;
// Update target's health bar after healing
if (self.target.updateHealthBar) {
self.target.updateHealthBar();
}
LK.effects.flashObject(self.target, 0x00ff00, 400);
// Create healing visual effect
tween(crossIndicator, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(crossIndicator, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
});
self.healCooldown = 120; // 2 second cooldown
}
}
if (self.healCooldown > 0) {
self.healCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var HeavyTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('heavyTowerAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -60;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -60;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
self.towerType = 'heavy';
self.health = 200;
self.maxHealth = 200;
self.range = 160;
self.damage = 50;
self.shootCooldown = 0;
self.target = null;
self.cost = 150;
self.canUpgrade = function () {
return false; // Heavy towers cannot be upgraded
};
self.getUpgradeCost = function () {
return 0; // Heavy towers cannot be upgraded
};
self.update = function () {
// Find target
if (!self.target || !self.target.parent) {
self.target = null;
var closestUnit = null;
var closestDistance = Infinity;
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (distance <= self.range && distance < closestDistance) {
closestDistance = distance;
closestUnit = unit;
}
}
self.target = closestUnit;
}
// Shoot at target with heavy damage
if (self.target && self.shootCooldown <= 0) {
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
towerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 120; // 2 second cooldown (slow)
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var HeavyUnit = Container.expand(function () {
var self = Container.call(this);
var unitGraphics = self.attachAsset('heavyUnitAsset', {
anchorX: 0.5,
anchorY: 0.5
});
unitGraphics.tint = 0x8B4513; // Brown color for heavy unit
unitGraphics.scaleX = 1.2;
unitGraphics.scaleY = 1.2;
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -45;
healthBarBg.scaleX = 1.0;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -45;
healthBar.scaleX = 1.0;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent * 1.0;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
self.unitType = 'heavy';
self.health = 150;
self.maxHealth = 150;
self.speed = 1;
self.damage = 40;
self.range = 160;
self.cost = 90;
self.shootCooldown = 0;
self.target = null;
self.lastX = 0;
self.lastY = 0;
self.currentWaypoint = 0;
self.isMovingToWaypoint = false;
// Create path through tower grid
var pathWaypoints = [];
pathWaypoints.push({
x: 400,
y: self.y
});
// Tower grid parameters
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Serpentine path through towers
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
pathWaypoints.push({
x: 1600,
y: 1000
});
self.pathWaypoints = pathWaypoints;
self.followPath = function () {
if (self.isMovingToWaypoint) return;
if (self.currentWaypoint >= self.pathWaypoints.length) {
self.x += self.speed;
return;
}
var waypoint = self.pathWaypoints[self.currentWaypoint];
var distance = Math.sqrt(Math.pow(waypoint.x - self.x, 2) + Math.pow(waypoint.y - self.y, 2));
var duration = distance / self.speed * 16.67;
self.isMovingToWaypoint = true;
tween(self, {
x: waypoint.x,
y: waypoint.y
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.currentWaypoint++;
self.isMovingToWaypoint = false;
}
});
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (!self.target || !self.target.parent) {
self.target = null;
var closestTarget = null;
var closestDistance = Infinity;
if (enemyBase && enemyBase.parent) {
var baseDistance = Math.sqrt(Math.pow(enemyBase.x - self.x, 2) + Math.pow(enemyBase.y - self.y, 2));
if (baseDistance <= self.range) {
closestTarget = enemyBase;
closestDistance = baseDistance;
}
}
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.parent) {
var towerDistance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (towerDistance <= self.range && towerDistance < closestDistance) {
closestDistance = towerDistance;
closestTarget = tower;
}
}
}
self.target = closestTarget;
}
if (self.target && self.shootCooldown <= 0) {
var bullet = new UnitBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
unitBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 100; // Slower shooting
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (!self.target) {
self.followPath();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var MeleeUnit = Container.expand(function () {
var self = Container.call(this);
var unitGraphics = self.attachAsset('meleeUnitAsset', {
anchorX: 0.5,
anchorY: 0.5
});
unitGraphics.tint = 0xFF6347; // Tomato red color for melee unit
unitGraphics.scaleX = 1.1;
unitGraphics.scaleY = 1.1;
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -40;
healthBarBg.scaleX = 0.9;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -40;
healthBar.scaleX = 0.9;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent * 0.9;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
self.unitType = 'melee';
self.health = 120;
self.maxHealth = 120;
self.speed = 3;
self.damage = 35;
self.range = 50; // Very short range for melee
self.cost = 70;
self.attackCooldown = 0;
self.target = null;
self.lastX = 0;
self.lastY = 0;
self.currentWaypoint = 0;
self.isMovingToWaypoint = false;
// Create path through tower grid
var pathWaypoints = [];
pathWaypoints.push({
x: 400,
y: self.y
});
// Tower grid parameters
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Serpentine path through towers
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
pathWaypoints.push({
x: 1600,
y: 1000
});
self.pathWaypoints = pathWaypoints;
self.followPath = function () {
if (self.isMovingToWaypoint) return;
if (self.currentWaypoint >= self.pathWaypoints.length) {
self.x += self.speed;
return;
}
var waypoint = self.pathWaypoints[self.currentWaypoint];
var distance = Math.sqrt(Math.pow(waypoint.x - self.x, 2) + Math.pow(waypoint.y - self.y, 2));
var duration = distance / self.speed * 16.67;
self.isMovingToWaypoint = true;
tween(self, {
x: waypoint.x,
y: waypoint.y
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.currentWaypoint++;
self.isMovingToWaypoint = false;
}
});
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Find closest target (prioritize base, then towers)
if (!self.target || !self.target.parent) {
self.target = null;
var closestTarget = null;
var closestDistance = Infinity;
// Check distance to enemy base first
if (enemyBase && enemyBase.parent) {
var baseDistance = Math.sqrt(Math.pow(enemyBase.x - self.x, 2) + Math.pow(enemyBase.y - self.y, 2));
if (baseDistance <= self.range) {
closestTarget = enemyBase;
closestDistance = baseDistance;
}
}
// Check towers if no base target or if tower is closer
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.parent) {
var towerDistance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (towerDistance <= self.range && towerDistance < closestDistance) {
closestDistance = towerDistance;
closestTarget = tower;
}
}
}
self.target = closestTarget;
}
// Melee attack - no bullets, direct damage
if (self.target && self.attackCooldown <= 0) {
// Flash effect for melee attack
LK.effects.flashObject(self, 0xFF6347, 200);
LK.effects.flashObject(self.target, 0xFF0000, 200);
// Direct damage to target
self.target.takeDamage(self.damage);
LK.getSound('hit').play();
self.attackCooldown = 90; // 1.5 second cooldown
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Move towards target or follow path
if (self.target) {
// Move directly towards target if one is found
if (!self.isMovingToWaypoint) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.range) {
// Move towards target
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
} else {
// Follow path if no target
self.followPath();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var SniperTower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('sniperTowerAsset', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -55;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -55;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
};
self.towerType = 'sniper';
self.health = 120;
self.maxHealth = 120;
self.range = 300; // Very long range
self.damage = 40;
self.shootCooldown = 0;
self.target = null;
self.cost = 125;
self.canUpgrade = function () {
return false; // Sniper towers cannot be upgraded
};
self.getUpgradeCost = function () {
return 0; // Sniper towers cannot be upgraded
};
self.update = function () {
// Find target (prioritize units furthest away)
if (!self.target || !self.target.parent) {
self.target = null;
var bestUnit = null;
var longestDistance = 0;
for (var i = 0; i < playerUnits.length; i++) {
var unit = playerUnits[i];
var distance = Math.sqrt(Math.pow(unit.x - self.x, 2) + Math.pow(unit.y - self.y, 2));
if (distance <= self.range && distance > longestDistance) {
longestDistance = distance;
bestUnit = unit;
}
}
self.target = bestUnit;
}
// Shoot at target with precision
if (self.target && self.shootCooldown <= 0) {
var bullet = new TowerBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
bullet.speed = 10; // Faster bullet
towerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 150; // 2.5 second cooldown
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
return true; // Tower is destroyed
}
return false;
};
return self;
});
var SniperUnit = Container.expand(function () {
var self = Container.call(this);
var unitGraphics = self.attachAsset('sniperUnitAsset', {
anchorX: 0.5,
anchorY: 0.5
});
unitGraphics.tint = 0x4B0082; // Indigo color for sniper unit
unitGraphics.scaleX = 1.0;
unitGraphics.scaleY = 1.3; // Taller appearance
// Health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -42;
healthBarBg.scaleX = 0.9;
// Health bar foreground
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 0;
healthBar.y = -42;
healthBar.scaleX = 0.9;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBar.scaleX = healthPercent * 0.9;
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00;
} else {
healthBar.tint = 0xff0000;
}
};
self.unitType = 'sniper';
self.health = 70;
self.maxHealth = 70;
self.speed = 1.5;
self.damage = 50;
self.range = 250; // Very long range
self.cost = 80;
self.shootCooldown = 0;
self.target = null;
self.lastX = 0;
self.lastY = 0;
self.currentWaypoint = 0;
self.isMovingToWaypoint = false;
// Create path through tower grid
var pathWaypoints = [];
pathWaypoints.push({
x: 400,
y: self.y
});
// Tower grid parameters
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Serpentine path through towers
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
pathWaypoints.push({
x: 1600,
y: 1000
});
self.pathWaypoints = pathWaypoints;
self.followPath = function () {
if (self.isMovingToWaypoint) return;
if (self.currentWaypoint >= self.pathWaypoints.length) {
self.x += self.speed;
return;
}
var waypoint = self.pathWaypoints[self.currentWaypoint];
var distance = Math.sqrt(Math.pow(waypoint.x - self.x, 2) + Math.pow(waypoint.y - self.y, 2));
var duration = distance / self.speed * 16.67;
self.isMovingToWaypoint = true;
tween(self, {
x: waypoint.x,
y: waypoint.y
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.currentWaypoint++;
self.isMovingToWaypoint = false;
}
});
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (!self.target || !self.target.parent) {
self.target = null;
var closestTarget = null;
var closestDistance = Infinity;
// Prioritize towers over base due to long range
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower && tower.parent) {
var towerDistance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
if (towerDistance <= self.range && towerDistance < closestDistance) {
closestDistance = towerDistance;
closestTarget = tower;
}
}
}
// Check base if no towers in range
if (!closestTarget && enemyBase && enemyBase.parent) {
var baseDistance = Math.sqrt(Math.pow(enemyBase.x - self.x, 2) + Math.pow(enemyBase.y - self.y, 2));
if (baseDistance <= self.range) {
closestTarget = enemyBase;
closestDistance = baseDistance;
}
}
self.target = closestTarget;
}
if (self.target && self.shootCooldown <= 0) {
var bullet = new UnitBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.target = self.target;
bullet.damage = self.damage;
bullet.speed = 12; // Faster bullet
unitBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.shootCooldown = 120; // Slow shooting rate
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (!self.target) {
self.followPath();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
return true;
}
return false;
};
return self;
});
var TowerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('towerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.target = null;
self.damage = 30;
self.update = function () {
if (!self.target || !self.target.parent) {
// Target destroyed, remove bullet
return;
}
// Move towards target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
// Hit target
if (self.target.takeDamage) {
self.target.takeDamage(self.damage);
LK.getSound('hit').play();
}
return; // Bullet will be removed
}
// Normalize and move
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
};
return self;
});
var TowerSlot = Container.expand(function () {
var self = Container.call(this);
var slotGraphics = self.attachAsset('towerSlot', {
anchorX: 0.5,
anchorY: 0.5
});
slotGraphics.alpha = 0.3;
self.occupied = false;
self.tower = null;
self.placeTower = function () {
if (!self.occupied) {
var tower = new EnemyTower();
tower.x = self.x;
tower.y = self.y;
tower.slot = self;
tower.updateStats(); // Initialize stats properly
enemyTowers.push(tower);
game.addChild(tower);
self.occupied = true;
self.tower = tower;
slotGraphics.alpha = 0.1;
return tower;
}
return null;
};
self.removeTower = function () {
if (self.occupied && self.tower) {
self.occupied = false;
self.tower = null;
slotGraphics.alpha = 0.3;
}
};
return self;
});
var UnitBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('unitBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.target = null;
self.damage = 25;
self.update = function () {
if (!self.target || !self.target.parent) {
// Target destroyed, remove bullet
return;
}
// Move towards target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
// Hit target
if (self.target.takeDamage) {
self.target.takeDamage(self.damage);
LK.getSound('hit').play();
}
return; // Bullet will be removed
}
// Normalize and move
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d5016
});
/****
* Game Code
****/
// Game arrays to track entities
// Initialize game assets
var playerUnits = [];
var enemyTowers = [];
var unitBullets = [];
var towerBullets = [];
var towerSlots = [];
var enemyBase;
// Game resources
var coins = 150;
var unitCost = 50;
// UI Elements
var coinsText = new Text2('Coins: ' + coins, {
size: 80,
fill: 0xFFD700
});
coinsText.anchor.set(1, 0);
coinsText.x = -20; // Small margin from right edge
coinsText.y = 20; // Small margin from top
LK.gui.topRight.addChild(coinsText);
var coinIcon = LK.getAsset('coinIcon', {
anchorX: 0.5,
anchorY: 0.5
});
coinIcon.x = -coinsText.width - 60; // Position to left of text
coinIcon.y = 45; // Align with text
LK.gui.topRight.addChild(coinIcon);
var healthText = new Text2('Base Health: 500', {
size: 50,
fill: 0xFFFFFF
});
healthText.anchor.set(0.5, 0);
LK.gui.top.addChild(healthText);
// Unit spawn buttons
var basicButton = new Text2('Basic (40)', {
size: 40,
fill: 0x87CEEB
});
basicButton.anchor.set(0.5, 1);
basicButton.x = -300;
basicButton.interactive = true;
basicButton.down = function () {
if (coins >= 40) {
spawnUnit('basic');
}
};
LK.gui.bottom.addChild(basicButton);
var fastButton = new Text2('Fast (60)', {
size: 40,
fill: 0x32CD32
});
fastButton.anchor.set(0.5, 1);
fastButton.x = -100;
fastButton.interactive = true;
fastButton.down = function () {
if (coins >= 60) {
spawnUnit('fast');
}
};
LK.gui.bottom.addChild(fastButton);
var heavyButton = new Text2('Heavy (90)', {
size: 40,
fill: 0x8B4513
});
heavyButton.anchor.set(0.5, 1);
heavyButton.x = 100;
heavyButton.interactive = true;
heavyButton.down = function () {
if (coins >= 90) {
spawnUnit('heavy');
}
};
LK.gui.bottom.addChild(heavyButton);
var sniperButton = new Text2('Sniper (80)', {
size: 40,
fill: 0x4B0082
});
sniperButton.anchor.set(0.5, 1);
sniperButton.x = 200;
sniperButton.interactive = true;
sniperButton.down = function () {
if (coins >= 80) {
spawnUnit('sniper');
}
};
LK.gui.bottom.addChild(sniperButton);
var meleeButton = new Text2('Melee (70)', {
size: 40,
fill: 0xFF6347
});
meleeButton.anchor.set(0.5, 1);
meleeButton.x = 400;
meleeButton.interactive = true;
meleeButton.down = function () {
if (coins >= 70) {
spawnUnit('melee');
}
};
LK.gui.bottom.addChild(meleeButton);
// Create enemy base
enemyBase = game.addChild(new EnemyBase());
enemyBase.x = 1800;
enemyBase.y = 2732 / 2;
// Create tower slots in a grid
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
var slot = new TowerSlot();
slot.x = gridStartX + col * gridSpacingX;
slot.y = gridStartY + row * gridSpacingY;
towerSlots.push(slot);
game.addChild(slot);
}
}
// Initially place some towers in random slots
var initialTowerCount = 4;
var placedTowers = 0;
while (placedTowers < initialTowerCount && placedTowers < towerSlots.length) {
var randomSlotIndex = Math.floor(Math.random() * towerSlots.length);
var slot = towerSlots[randomSlotIndex];
if (slot.placeTower()) {
// Initialize health bar for the newly placed tower
if (slot.tower && slot.tower.updateHealthBar) {
slot.tower.updateHealthBar();
}
placedTowers++;
}
}
function spawnUnit(unitType) {
if (!unitType) unitType = 'basic';
var unit = null;
var cost = 40;
switch (unitType) {
case 'basic':
unit = new BasicUnit();
cost = 40;
break;
case 'fast':
unit = new FastUnit();
cost = 60;
break;
case 'heavy':
unit = new HeavyUnit();
cost = 90;
break;
case 'sniper':
unit = new SniperUnit();
cost = 80;
break;
case 'melee':
unit = new MeleeUnit();
cost = 70;
break;
default:
unit = new BasicUnit();
cost = 40;
break;
}
if (coins >= cost && unit) {
coins -= cost;
coinsText.setText('Coins: ' + coins);
coinIcon.x = -coinsText.width - 60;
unit.x = 100;
unit.y = 500 + playerUnits.length % 5 * 150;
// Create path that goes through all tower positions
var pathWaypoints = [];
// Start from spawn position
pathWaypoints.push({
x: 400,
y: unit.y
});
// Add waypoints to pass through tower grid
var gridStartX = 800;
var gridStartY = 600;
var gridSpacingX = 200;
var gridSpacingY = 200;
var gridRows = 8;
var gridCols = 4;
// Create serpentine path through tower grid
for (var col = 0; col < gridCols; col++) {
if (col % 2 === 0) {
// Go down for even columns
for (var row = 0; row < gridRows; row++) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
} else {
// Go up for odd columns
for (var row = gridRows - 1; row >= 0; row--) {
pathWaypoints.push({
x: gridStartX + col * gridSpacingX,
y: gridStartY + row * gridSpacingY
});
}
}
}
// Final waypoint towards the base
pathWaypoints.push({
x: 1600,
y: 1366
});
unit.pathWaypoints = pathWaypoints;
playerUnits.push(unit);
game.addChild(unit);
unit.updateHealthBar();
LK.getSound('unitSpawn').play();
}
}
// Coin generation timer
var coinTimer = 0;
// Enemy AI system
var enemyAI = {
coins: 200,
towerCost: 100,
lastTowerPlacement: 0,
placementCooldown: 300,
// 5 seconds at 60fps
update: function update() {
// Generate coins for enemy AI
if (LK.ticks % 180 === 0) {
// Every 3 seconds
this.coins += 50;
}
// Force spending if AI has too many coins
var forceSpend = this.coins >= 1000;
// Check if should place new towers
if (this.coins >= this.towerCost && LK.ticks - this.lastTowerPlacement > this.placementCooldown || forceSpend) {
this.considerTowerPlacement();
}
// Upgrade existing towers (with forced spending)
this.considerTowerUpgrades(forceSpend);
// Repair damaged towers
this.repairTowers();
},
considerTowerPlacement: function considerTowerPlacement() {
// First priority: Check if we need heal towers near damaged towers
var needsHealTower = false;
var healSlot = null;
var damagedTowerNeedingHeal = null;
// Find damaged towers that need healing
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower.health < tower.maxHealth * 0.6) {
// If tower is below 60% health
// Check if there's already a heal tower nearby
var hasHealerNearby = false;
for (var j = 0; j < enemyTowers.length; j++) {
var otherTower = enemyTowers[j];
if (otherTower.towerType === 'heal') {
var distance = Math.sqrt(Math.pow(tower.x - otherTower.x, 2) + Math.pow(tower.y - otherTower.y, 2));
if (distance <= 200) {
// Within healing range
hasHealerNearby = true;
break;
}
}
}
if (!hasHealerNearby) {
damagedTowerNeedingHeal = tower;
needsHealTower = true;
break;
}
}
}
// If we need a heal tower and can afford it, find best slot near damaged tower
if (needsHealTower && damagedTowerNeedingHeal && this.coins >= 110) {
var bestDistance = Infinity;
for (var i = 0; i < towerSlots.length; i++) {
var slot = towerSlots[i];
if (!slot.occupied) {
var distance = Math.sqrt(Math.pow(damagedTowerNeedingHeal.x - slot.x, 2) + Math.pow(damagedTowerNeedingHeal.y - slot.y, 2));
if (distance < bestDistance && distance <= 200) {
// Within heal range
bestDistance = distance;
healSlot = slot;
}
}
}
// Place heal tower if we found a good slot
if (healSlot) {
var tower = new HealTower();
tower.x = healSlot.x;
tower.y = healSlot.y;
tower.slot = healSlot;
enemyTowers.push(tower);
game.addChild(tower);
healSlot.occupied = true;
healSlot.tower = tower;
healSlot.attachAsset('towerSlot', {}).alpha = 0.1;
this.coins -= 110;
this.lastTowerPlacement = LK.ticks;
// Initialize health bar
if (tower.updateHealthBar) {
tower.updateHealthBar();
}
// Visual feedback
LK.effects.flashObject(healSlot, 0x00ff00, 500);
return; // Exit early after placing heal tower
}
}
// Second priority: Find empty slots closest to player units for combat towers
var bestSlot = null;
var minDistance = Infinity;
var forceSpend = this.coins >= 1000;
for (var i = 0; i < towerSlots.length; i++) {
var slot = towerSlots[i];
if (!slot.occupied) {
// Calculate average distance to all player units
var totalDistance = 0;
var unitCount = 0;
for (var j = 0; j < playerUnits.length; j++) {
var unit = playerUnits[j];
var distance = Math.sqrt(Math.pow(unit.x - slot.x, 2) + Math.pow(unit.y - slot.y, 2));
totalDistance += distance;
unitCount++;
}
if (unitCount > 0) {
var avgDistance = totalDistance / unitCount;
// Force placement if we have too many coins, otherwise use distance restriction
if (avgDistance < minDistance && (avgDistance < 400 || forceSpend)) {
minDistance = avgDistance;
bestSlot = slot;
}
} else if (forceSpend && !bestSlot) {
// If forced to spend and no players around, pick any empty slot
bestSlot = slot;
}
}
}
// Place tower at best location
if (bestSlot) {
// Choose random tower type based on available coins (excluding heal since we handle that above)
var towerTypes = [];
if (this.coins >= 75) towerTypes.push('basic');
if (this.coins >= 100) towerTypes.push('fast');
if (this.coins >= 125) towerTypes.push('sniper');
if (this.coins >= 130) towerTypes.push('area');
if (this.coins >= 150) towerTypes.push('heavy');
if (towerTypes.length > 0) {
var randomType = towerTypes[Math.floor(Math.random() * towerTypes.length)];
var tower = null;
var cost = 75;
switch (randomType) {
case 'basic':
tower = new BasicTower();
cost = 75;
break;
case 'fast':
tower = new FastTower();
cost = 100;
break;
case 'sniper':
tower = new SniperTower();
cost = 125;
break;
case 'area':
tower = new AreaTower();
cost = 130;
break;
case 'heavy':
tower = new HeavyTower();
cost = 150;
break;
}
if (tower) {
tower.x = bestSlot.x;
tower.y = bestSlot.y;
tower.slot = bestSlot;
enemyTowers.push(tower);
game.addChild(tower);
bestSlot.occupied = true;
bestSlot.tower = tower;
bestSlot.attachAsset('towerSlot', {}).alpha = 0.1;
this.coins -= cost;
this.lastTowerPlacement = LK.ticks;
// Initialize health bar
if (tower.updateHealthBar) {
tower.updateHealthBar();
}
// Visual feedback
LK.effects.flashObject(bestSlot, 0xff0000, 500);
}
}
}
},
considerTowerUpgrades: function considerTowerUpgrades(forceSpend) {
// Find towers that can be upgraded and are in combat zones
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower.canUpgrade()) {
var upgradeCost = tower.getUpgradeCost();
if (this.coins >= upgradeCost) {
// Check if tower is in an active combat zone (has nearby player units)
var nearbyUnits = 0;
for (var j = 0; j < playerUnits.length; j++) {
var unit = playerUnits[j];
var distance = Math.sqrt(Math.pow(unit.x - tower.x, 2) + Math.pow(unit.y - tower.y, 2));
if (distance <= tower.range + 100) {
nearbyUnits++;
}
}
// Upgrade towers that are actively engaged or if we have excess coins or forced to spend
if (nearbyUnits > 0 || this.coins > upgradeCost * 2 || forceSpend) {
if (tower.upgrade()) {
this.coins -= upgradeCost;
break; // Only upgrade one tower per update
}
}
}
}
}
},
repairTowers: function repairTowers() {
// Find damaged towers and repair them
for (var i = 0; i < enemyTowers.length; i++) {
var tower = enemyTowers[i];
if (tower.health < tower.maxHealth * 0.5 && this.coins >= 25) {
tower.health = Math.min(tower.health + 25, tower.maxHealth);
this.coins -= 25;
LK.effects.flashObject(tower, 0x00ff00, 300);
break; // Only repair one tower per update
}
}
}
};
// Touch controls for spawning units
game.down = function (x, y, obj) {
if (coins >= 40) {
spawnUnit('basic');
}
};
game.update = function () {
// Update enemy AI
enemyAI.update();
// Generate coins over time
coinTimer++;
if (coinTimer >= 120) {
// Every 2 seconds
coins += 25;
coinsText.setText('Coins: ' + coins);
coinIcon.x = -coinsText.width - 60; // Update icon position
coinTimer = 0;
}
// Update unit bullets
for (var i = unitBullets.length - 1; i >= 0; i--) {
var bullet = unitBullets[i];
if (!bullet.target || !bullet.target.parent) {
bullet.destroy();
unitBullets.splice(i, 1);
continue;
}
var dx = bullet.target.x - bullet.x;
var dy = bullet.target.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 15) {
// Hit target
var isDead = bullet.target.takeDamage(bullet.damage);
if (isDead) {
// Remove from appropriate array
if (bullet.target === enemyBase) {
// Player wins!
LK.effects.flashScreen(0x00ff00, 2000);
LK.showYouWin();
return;
} else {
// Remove tower
for (var j = 0; j < enemyTowers.length; j++) {
if (enemyTowers[j] === bullet.target) {
// Calculate money reward based on tower type and level
var moneyReward = 75; // Base reward
if (enemyTowers[j].towerType) {
switch (enemyTowers[j].towerType) {
case 'fast':
moneyReward = 100;
break;
case 'heal':
moneyReward = 110;
break;
case 'sniper':
moneyReward = 125;
break;
case 'area':
moneyReward = 130;
break;
case 'heavy':
moneyReward = 150;
break;
default:
moneyReward = 75;
break;
}
} else if (enemyTowers[j].level) {
// For upgradeable towers, reward based on level
moneyReward = 75 + (enemyTowers[j].level - 1) * 50;
}
// Clean up slot if tower has one
if (enemyTowers[j].slot) {
enemyTowers[j].slot.removeTower();
}
enemyTowers[j].destroy();
enemyTowers.splice(j, 1);
coins += moneyReward; // Money reward for destroying tower
coinsText.setText('Coins: ' + coins);
coinIcon.x = -coinsText.width - 60; // Update icon position
break;
}
}
}
}
bullet.destroy();
unitBullets.splice(i, 1);
}
}
// Update tower bullets
for (var i = towerBullets.length - 1; i >= 0; i--) {
var bullet = towerBullets[i];
if (!bullet.target || !bullet.target.parent) {
bullet.destroy();
towerBullets.splice(i, 1);
continue;
}
var dx = bullet.target.x - bullet.x;
var dy = bullet.target.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 15) {
// Hit target
var isDead = bullet.target.takeDamage(bullet.damage);
if (isDead) {
// Remove unit
for (var j = 0; j < playerUnits.length; j++) {
if (playerUnits[j] === bullet.target) {
playerUnits[j].destroy();
playerUnits.splice(j, 1);
break;
}
}
}
bullet.destroy();
towerBullets.splice(i, 1);
}
}
// Check if player has no units and insufficient coins (lose condition)
if (playerUnits.length === 0 && coins < unitCost) {
// Check if there are still towers or base with health
if (enemyTowers.length > 0 || enemyBase && enemyBase.health > 0) {
LK.effects.flashScreen(0xff0000, 2000);
LK.showGameOver();
return;
}
}
// Update base health display
if (enemyBase) {
healthText.setText('Base Health: ' + enemyBase.health);
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1045,8 +1045,12 @@
if (self.target && self.healCooldown <= 0) {
var healingAmount = Math.min(self.healAmount, self.target.maxHealth - self.target.health);
if (healingAmount > 0) {
self.target.health += healingAmount;
+ // Update target's health bar after healing
+ if (self.target.updateHealthBar) {
+ self.target.updateHealthBar();
+ }
LK.effects.flashObject(self.target, 0x00ff00, 400);
// Create healing visual effect
tween(crossIndicator, {
scaleX: 2.0,
coinIcon. In-Game asset. 2d. High contrast. No shadows
enemyBase. In-Game asset. 2d. High contrast. No shadows
enemyTower. In-Game asset. 2d. High contrast. No shadows
towerBullet. In-Game asset. 2d. High contrast. No shadows
towerSlot. In-Game asset. 2d. High contrast. No shadows
upgradeIndicator. In-Game asset. 2d. High contrast. No shadows
heavyTowerAsset. In-Game asset. 2d. High contrast. No shadows
fastTowerAsset. In-Game asset. 2d. High contrast. No shadows
healTowerAsset. In-Game asset. 2d. High contrast. No shadows
sniperTowerAsset. In-Game asset. 2d. High contrast. No shadows
areaTowerAsset. In-Game asset. 2d. High contrast. No shadows
meleeUnitAsset. In-Game asset. 2d. High contrast. No shadows
laserTowerAsset. In-Game asset. 2d. High contrast. No shadows
poisonTowerAsset. In-Game asset. 2d. High contrast. No shadows
slowTowerAsset. In-Game asset. 2d. High contrast. No shadows
resurrectionTowerAsset. In-Game asset. 2d. High contrast. No shadows