User prompt
Elimina la aleatoriedad de aparición de capa 6 y haz que se pueda especificar la cantidad de cada variedad como capa 6A y 6B
User prompt
Haz que capa 6 se divida en 4 capa 5 en vez de 1
User prompt
Haz que capa 6 se divida en más enemigos
User prompt
Haz que capa 6 al perder su capa se divida en 4 capa 5 en vez de 1
User prompt
Haz que cada 6 se divida en 4 capa 5 al morir
User prompt
Haz un sistema flexible para mecánicas extra de cada capa
User prompt
El enemigo no se divide en 4
User prompt
Haz que capa 6 al morir se divida en 4 de su capa inferior
User prompt
Elimina el sistema actual para asignar y cambiar tinte de los enemigos y crea otro que permita más variedad y configuración debido al error que no permite que una misma capa tenga variantes de color ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Arregla el error que hace que capa 6 no cambie de color según su variable
User prompt
Agrega 2 enemigo de ssexta capa en la oleada 1
User prompt
Agrega un sistema para hacer que la sexta capa venga aparezca con la variable Anti hielo o anti fuego activa como variable local. Si viene con Anti hielo su color será blanco, si es anti fuego será negro
User prompt
Crea dos variables: Anti hielo y anti fuego boleanas
User prompt
Haz que la nueva capa tenga la misma velocidad de verde
User prompt
Agrega una nueva capa de color blanco
User prompt
Haz que cada capa de enemigo de dinero
User prompt
Please fix the bug: 'ReferenceError: currentWaveIndex is not defined' in or related to this line: 'waveText.setText('Wave: ' + (currentWaveIndex + 1));' Line Number: 1349
User prompt
Elimina toda la lógica de los enemigos
User prompt
La velocidad sigue sin ser la correspondiente a la capa que posee el enemigo cuando pierde 1
User prompt
Empieza en la oleada 15
User prompt
Arregla el error que hace que no se actualice la velocidad del enemigo
User prompt
Arregla el error que hace que azul no se vuelve su capa inferior
User prompt
Mantén el sistema de capas pero mantén la clasificación actual
User prompt
Mantén el sistema de capas pero mantén la clasificación actual
User prompt
Mantén el sistemas de capas ya establecida pero con la nueva clasificación por t xto
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('Bala', {
anchorX: 0.5,
anchorY: 0.5
});
self.target = null;
self.speed = 800; // pixels per second
self.damage = 0;
self.directionX = 0; // Direction components for straight line movement
self.directionY = 0;
self.isAlive = true;
self.hitCount = 0; // Track number of enemies hit by this bullet
self.hitEnemies = []; // Track which specific enemies have been hit to prevent double-hitting
// Calculate lifespan based on range and bullet speed with 20% buffer
var bulletSpeed = 800; // Base bullet speed in pixels per second
// Apply fastGame speed boost to bullet speed for lifespan calculation
if (fastGame) {
bulletSpeed = bulletSpeed * 1.5; // 50% faster when fastGame is true
}
var towerRange = self.towerRef ? self.towerRef.range : 400; // Use tower's range or default to 400
var rangeBasedTravelTime = towerRange / bulletSpeed * 1000; // Convert to milliseconds
var baseDuration = rangeBasedTravelTime * 1.2; // 20% more than range travel time
var duration = baseDuration;
// Apply duration multiplier if tower reference exists and has the multiplier
if (self.towerRef && self.towerRef.bulletDurationMultiplier) {
duration = baseDuration * self.towerRef.bulletDurationMultiplier;
}
tween(self, {}, {
duration: duration,
onFinish: function onFinish() {
if (self.parent) {
self.destroy();
}
}
});
self.update = function () {
if (!self.isAlive) {
return;
}
// Move in straight line using direction
var effectiveSpeed = self.speed;
// Apply fastGame speed boost to bullet movement (50% faster)
if (fastGame) {
effectiveSpeed = self.speed * 1.5;
}
self.x += self.directionX * effectiveSpeed * frameTime;
self.y += self.directionY * effectiveSpeed * frameTime;
// Enemy collision detection - removed
};
return self;
});
// Reusable tower creation function
var Gameplay = Container.expand(function () {
var self = Container.call(this);
var gameplayGraphics = self.attachAsset('gameplayBackground', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var UI = Container.expand(function () {
var self = Container.call(this);
var uiGraphics = self.attachAsset('uiBackground', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Reusable tower creation function
7;
function createTowerBase(params) {
return Container.expand(function () {
var self = Container.call(this);
// Tower parameters
self.damage = params.damage;
self.cadence = params.cadence;
self.range = params.range;
self.rangeSquared = self.range * self.range; // Cache squared range for optimization
self.totalDamage = 0; // Track total damage dealt by this tower
self.cross = 1; // Initialize cross value for this tower
self.targetingPriority = 'first'; // Default targeting priority: 'first', 'last', 'strongest'
var areaGraphics = self.attachAsset('Area', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale the area to match the tower's actual range
var areaScale = self.range * 2 / 100; // Area asset is 100x100, so scale to range diameter
areaGraphics.scaleX = areaScale;
areaGraphics.scaleY = areaScale;
areaGraphics.alpha = 0.3;
areaGraphics.visible = false; // Hide range area by default
var towerGraphics = self.attachAsset(params.asset, {
anchorX: 0.5,
anchorY: 0.5
});
// Method to show range area
self.showRange = function () {
areaGraphics.visible = true;
};
// Method to hide range area
self.hideRange = function () {
areaGraphics.visible = false;
};
// Tower selection state
self.isSelected = false;
// Tower placement state
self.isPlaced = false;
// Shooting properties
self.lastShotTime = 0;
self.bullets = [];
// Current target tracking
self.currentTarget = null;
// Method to find enemies in range - removed (no enemies exist)
self.findEnemiesInRange = function () {
return [];
};
// Method to shoot at target
self.shoot = function (target) {
var currentTime = Date.now();
var effectiveCadence = self.cadence;
// Apply fastGame speed boost to firing rate (50% faster = reduce cadence by 33%)
if (fastGame) {
effectiveCadence = self.cadence / 1.5;
}
if (currentTime - self.lastShotTime >= effectiveCadence) {
// Function to create and fire a bullet
var createBullet = function createBullet(angleOffset) {
var bullet = new Bullet();
// Calculate current direction to target
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Enemy prediction - removed (no enemies exist)
var bulletSpeed = 800 * (self.bulletSpeedMultiplier || 1); // Apply speed multiplier if available
// Apply fastGame speed boost to bullet speed (50% faster)
if (fastGame) {
bulletSpeed = bulletSpeed * 1.5;
}
var predictedX = target.x;
var predictedY = target.y;
// Calculate direction to predicted position with angle offset
var predictedDx = predictedX - self.x;
var predictedDy = predictedY - self.y;
var baseAngle = Math.atan2(predictedDy, predictedDx);
var adjustedAngle = baseAngle + angleOffset;
var offsetDistance = 50; // Distance to spawn bullet ahead of tower
// Spawn bullet slightly ahead in the adjusted direction
bullet.x = self.x + Math.cos(adjustedAngle) * offsetDistance;
bullet.y = self.y + Math.sin(adjustedAngle) * offsetDistance;
// Set bullet direction for straight line movement in adjusted direction
bullet.directionX = Math.cos(adjustedAngle);
bullet.directionY = Math.sin(adjustedAngle);
bullet.target = target;
bullet.damage = self.damage;
bullet.speed = bulletSpeed; // Use calculated speed with multiplier
bullet.towerRef = self; // Store reference to the tower that fired this bullet
// Rotate bullet to face adjusted direction
bullet.rotation = adjustedAngle;
self.bullets.push(bullet);
game.addChild(bullet);
};
createBullet(0);
// Fire side bullets if multishot upgrade is active
if (self.hasMultishot) {
createBullet(-Math.PI / 12); // 15 degrees to the left
createBullet(Math.PI / 12); // 15 degrees to the right
}
self.lastShotTime = currentTime;
// Play bullet shooting sound
LK.getSound('Balababa').play();
// Initialize attack sprites if not already created
if (!self.attackSprite1) {
self.attackSprite1 = self.attachAsset('TorreinicialAttack', {
anchorX: 0.5,
anchorY: 0.5
});
self.attackSprite1.visible = false;
}
if (!self.attackSprite2) {
self.attackSprite2 = self.attachAsset('TorreinicialAttack2', {
anchorX: 0.5,
anchorY: 0.5
});
self.attackSprite2.visible = false;
}
if (!self.attackSprite3) {
self.attackSprite3 = self.attachAsset('TorreinicialAttack3', {
anchorX: 0.5,
anchorY: 0.5
});
self.attackSprite3.visible = false;
}
if (!self.normalSprite) {
self.normalSprite = towerGraphics;
}
// Initialize animation frame counter if not exists
if (!self.animationFrame) {
self.animationFrame = 0;
}
// Cycle through attack sprites
self.animationFrame = (self.animationFrame + 1) % 3;
var currentAttackSprite;
if (self.animationFrame === 0) {
currentAttackSprite = self.attackSprite1;
} else if (self.animationFrame === 1) {
currentAttackSprite = self.attackSprite2;
} else {
currentAttackSprite = self.attackSprite3;
}
// Sync attack sprite properties with current sprite
currentAttackSprite.rotation = towerGraphics.rotation;
currentAttackSprite.scaleY = towerGraphics.scaleY;
currentAttackSprite.x = towerGraphics.x;
currentAttackSprite.y = towerGraphics.y;
// Hide current sprite and show attack sprite
towerGraphics.visible = false;
currentAttackSprite.visible = true;
towerGraphics = currentAttackSprite;
// Animate attack sprite with scaling effect
tween(currentAttackSprite, {
scaleX: 1.2,
scaleY: currentAttackSprite.scaleY > 0 ? 1.2 : -1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(currentAttackSprite, {
scaleX: 1.0,
scaleY: currentAttackSprite.scaleY > 0 ? 1.0 : -1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
// Change back to normal sprite after a short delay using LK.setTimeout
LK.setTimeout(function () {
if (self.parent && currentAttackSprite && self.normalSprite) {
// Sync normal sprite properties with current attack sprite
self.normalSprite.rotation = currentAttackSprite.rotation;
self.normalSprite.scaleY = currentAttackSprite.scaleY;
self.normalSprite.x = currentAttackSprite.x;
self.normalSprite.y = currentAttackSprite.y;
// Hide attack sprite and show normal sprite
currentAttackSprite.visible = false;
self.normalSprite.visible = true;
towerGraphics = self.normalSprite;
}
}, 250);
}
};
// Update method for tower
self.update = function () {
// Clean up destroyed bullets
for (var i = self.bullets.length - 1; i >= 0; i--) {
if (!self.bullets[i].parent) {
self.bullets.splice(i, 1);
}
}
// Enemy targeting removed - towers no longer shoot
if (self.isPlaced) {
// Clear current target
self.currentTarget = null;
// No enemies to target
}
};
// Handle tower selection
self.down = function (x, y, obj) {
// Deselect all other towers first
for (var i = 0; i < placedTowers.length; i++) {
if (placedTowers[i] !== self) {
placedTowers[i].isSelected = false;
placedTowers[i].hideRange();
}
}
// Toggle selection for this tower
self.isSelected = !self.isSelected;
if (self.isSelected) {
self.showRange();
updateTowerUpgrade(self); // Update UI with this tower's upgrade options
} else {
self.hideRange();
updateTowerUpgrade(null); // Clear UI when deselected
}
};
return self;
});
}
var Tower = createTowerBase({
damage: 1,
// Damage dealt per shot
cadence: 1000,
// Time between shots in milliseconds (1 second)
range: 400,
// Range in pixels
asset: 'torreInicial'
});
// Initialize tower-specific properties
Tower.prototype.cross = 1; // Each tower starts with cross value of 1
var draggedTower = null;
var isDragging = false;
var placedTowers = []; // Track all placed towers
// Cache frequently used values
var gameplayBounds = null;
var uiBounds = null;
var frameTime = 1 / 60; // Cache frame time calculation
// Reusable tower creation function that accepts tower constructor
function createTowerButton(color, x, y, TowerClass) {
var buttonBG = game.addChild(LK.getAsset('BGbuttonTower', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
buttonBG.x = x;
buttonBG.y = y;
var button = game.addChild(new TowerClass());
button.x = x;
button.y = y;
button.tint = color;
// Store reference to button background for easy access
button.buttonBG = buttonBG;
button.down = function (x, y, obj) {
isDragging = true;
draggedTower = game.addChild(new TowerClass());
draggedTower.x = button.x;
draggedTower.y = button.y;
draggedTower.alpha = 0.7;
draggedTower.tint = color;
draggedTower.showRange(); // Show range area when dragging
// Initialize last valid position to starting position
draggedTower.lastValidX = button.x;
draggedTower.lastValidY = button.y;
};
return button;
}
// Game down handler to deselect towers when clicking on gameplay area
game.down = function (x, y, obj) {
// Check if click is in gameplay area (not on UI or towers)
var gameplayBounds = getGameplayBounds();
var clickInGameplay = x >= gameplayBounds.left && x <= gameplayBounds.right && y >= gameplayBounds.top && y <= gameplayBounds.bottom;
if (clickInGameplay) {
// Deselect all towers
for (var i = 0; i < placedTowers.length; i++) {
placedTowers[i].isSelected = false;
placedTowers[i].hideRange();
}
updateTowerUpgrade(null); // Clear tower upgrade when no tower is selected
}
};
// Helper function to check if point is inside rotated rectangle
function isPointInRotatedRect(pointX, pointY, rectX, rectY, rectWidth, rectHeight, rotation) {
// Translate point to rectangle's coordinate system
var dx = pointX - rectX;
var dy = pointY - rectY;
// Rotate point by negative rotation to align with rectangle
var cos = Math.cos(-rotation);
var sin = Math.sin(-rotation);
var rotatedX = dx * cos - dy * sin;
var rotatedY = dx * sin + dy * cos;
// Check if rotated point is within rectangle bounds with much larger bounds for better collision
var halfWidth = rectWidth / 2 + 90; // Add 80 pixels buffer for much better collision detection
var halfHeight = rectHeight / 2 + 60; // Add 80 pixels buffer for much better collision detection
return Math.abs(rotatedX) <= halfWidth && Math.abs(rotatedY) <= halfHeight;
}
// Helper functions for bounds calculations
function getGameplayBounds() {
return {
left: gameplay.x - gameplay.width / 2,
right: gameplay.x + gameplay.width / 2,
top: gameplay.y - gameplay.height / 2,
bottom: gameplay.y + gameplay.height / 2,
centerX: gameplay.x,
centerY: gameplay.y
};
}
function getUIBounds() {
return {
left: ui.x - ui.width / 2,
right: ui.x + ui.width / 2,
top: ui.y - ui.height / 2,
bottom: ui.y + ui.height / 2
};
}
function isPointInUI(x, y) {
var bounds = getUIBounds();
return x >= bounds.left && x <= bounds.right && y >= bounds.top && y <= bounds.bottom;
}
function calculateDragOffset(x, y) {
var bounds = getGameplayBounds();
var distanceFromCenterX = Math.abs(x - bounds.centerX);
var distanceFromCenterY = Math.abs(y - bounds.centerY);
var maxDistanceX = gameplay.width / 2;
var maxDistanceY = gameplay.height / 2;
var normalizedDistanceX = distanceFromCenterX / maxDistanceX;
var normalizedDistanceY = distanceFromCenterY / maxDistanceY;
var maxOffset = 200;
var offsetMagnitudeX = maxOffset * normalizedDistanceX;
var offsetMagnitudeY = maxOffset * normalizedDistanceY;
var offsetX = 0;
var offsetY = 0;
if (x >= bounds.centerX && y <= bounds.centerY) {
offsetX = offsetMagnitudeX;
offsetY = -offsetMagnitudeY;
} else if (x <= bounds.centerX && y <= bounds.centerY) {
offsetX = -offsetMagnitudeX;
offsetY = -offsetMagnitudeY;
} else if (x <= bounds.centerX && y >= bounds.centerY) {
offsetX = -offsetMagnitudeX;
offsetY = offsetMagnitudeY;
} else if (x >= bounds.centerX && y >= bounds.centerY) {
offsetX = offsetMagnitudeX;
offsetY = offsetMagnitudeY;
}
return {
offsetX: offsetX,
offsetY: offsetY
};
}
// Layer management - objects are added in z-index order (bottom to top)
// Background layer
var gameplay = game.addChild(new Gameplay());
gameplay.x = 1024;
gameplay.y = 1093;
// Game objects layer (towers will be added here)
// UI layer
var ui = game.addChild(new UI());
ui.x = 1024;
ui.y = 2459;
// Create single tower creation button
var towerButtons = [];
var startX = 400; // Position button on the left side
towerButtons.push(createTowerButton(0xffffff, startX, 2459, Tower)); // White tower (normal)
// Create path objects with transparency
var caminoObjects = [];
// Add several camino objects to create a path
var caminoPositions = [{
x: 959,
y: -99,
rotation: 0,
width: 200,
height: 200
}, {
x: 831,
y: 50,
rotation: 0.9948,
width: 200,
height: 510.2
}, {
x: 574,
y: 224,
rotation: 0.8029,
width: 190.3,
height: 201.6
}, {
x: 508,
y: 313,
rotation: 0.4538,
width: 203.6,
height: 200
}, {
x: 488,
y: 412,
rotation: 0,
width: 220.8,
height: 191.1
}, {
x: 516,
y: 506,
rotation: -0.6981,
width: 214.2,
height: 220
}, {
x: 632,
y: 587,
rotation: 0.3491,
width: 197,
height: 220.9
}, {
x: 883,
y: 609,
rotation: -0.0313,
width: 390.1,
height: 210.3
}, {
x: 1144,
y: 619,
rotation: 0.1745,
width: 200,
height: 225.4
}, {
x: 1318,
y: 675,
rotation: 0.4363,
width: 224.6,
height: 240
}, {
x: 1457,
y: 772,
rotation: -0.733,
width: 267.3,
height: 199.6
}, {
x: 1508,
y: 922,
rotation: 0,
width: 228.8,
height: 351.5
}, {
x: 1459,
y: 1134,
rotation: -0.9250,
width: 232.2,
height: 231.9
}, {
x: 1121,
y: 1309,
rotation: -0.3665,
width: 652.6,
height: 224.8
}, {
x: 754,
y: 1478,
rotation: -0.7156,
width: 227.5,
height: 225.5
}, {
x: 639,
y: 1643,
rotation: 0.4013,
width: 224.5,
height: 257.7
}, {
x: 601,
y: 1863,
rotation: 0.0698,
width: 239.2,
height: 274.2
}, {
x: 612,
y: 2086,
rotation: -0.1396,
width: 236.3,
height: 235
}];
for (var i = 0; i < caminoPositions.length; i++) {
var camino = game.addChild(LK.getAsset('camino', {
anchorX: 0.5,
anchorY: 0.5
}));
camino.x = caminoPositions[i].x;
camino.y = caminoPositions[i].y;
camino.rotation = caminoPositions[i].rotation; // Apply rotation from positions array
// Scale camino to match desired dimensions using width and height from caminoPositions
var caminoWidth = caminoPositions[i].width || 200; // Use width from array or default to 200
var caminoHeight = caminoPositions[i].height || 200; // Use height from array or default to 200
camino.scaleX = caminoWidth / 200; // Asset is 200x200 by default
camino.scaleY = caminoHeight / 200;
camino.alpha = 0.2; // Set transparency to 0.2
caminoObjects.push(camino);
}
// Create end object and place it at the final waypoint
var end = game.addChild(LK.getAsset('End', {
anchorX: 0.5,
anchorY: 0.5
}));
// Position end closer to the penultimate waypoint
var finalPosition = caminoPositions[caminoPositions.length - 1];
var penultimatePosition = caminoPositions[caminoPositions.length - 2];
// Calculate direction from penultimate to final waypoint
var dx = finalPosition.x - penultimatePosition.x;
var dy = finalPosition.y - penultimatePosition.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move end object 60% of the way from final to penultimate position
var moveBackRatio = 0.6;
end.x = finalPosition.x - dx * moveBackRatio;
end.y = finalPosition.y - dy * moveBackRatio;
var directionAngle = Math.atan2(dy, dx);
end.rotation = directionAngle;
end.alpha = 1.0; // Remove transparency
// Wave system variables - enemies removed
// Dynamic wave generation function - removed
// Wave distribution function - removed
// Enemy health layers function - removed
// Wave management variables - removed
// Enemy base class - removed
// Enemy types and classes - removed
// Wave start function - removed
// UI mode management
var UI_MODE_TOWER_CREATION = 'creation';
var UI_MODE_TOWER_UPGRADE = 'upgrade';
var currentUIMode = UI_MODE_TOWER_CREATION;
// UI Upgrade panel for selected tower
var towerUpgradeContainer = game.addChild(new Container());
towerUpgradeContainer.x = 1024;
towerUpgradeContainer.y = 2250;
// Helper function to update range area visually
function updateRangeArea(tower) {
if (tower.children[0]) {
var areaScale = tower.range * 2 / 100;
tower.children[0].scaleX = areaScale;
tower.children[0].scaleY = areaScale;
}
}
// Helper function to increment upgrade counter
function incrementUpgradeCounter(tower, type) {
if (type === 'left') {
tower.leftUpgrades = tower.leftUpgrades || 0;
tower.leftUpgrades++;
} else if (type === 'right') {
tower.rightUpgrades = tower.rightUpgrades || 0;
tower.rightUpgrades++;
}
}
// Reusable upgrade system
var upgradeDefinitions = {
speed: {
title: 'Rapid Fire',
cost: 75,
apply: function apply(tower) {
tower.cadence = Math.max(100, tower.cadence * 0.8);
incrementUpgradeCounter(tower, 'left');
}
},
range: {
title: 'Eagle Eye',
cost: 100,
apply: function apply(tower) {
tower.range = Math.floor(tower.range * 1.25);
tower.rangeSquared = tower.range * tower.range;
updateRangeArea(tower);
incrementUpgradeCounter(tower, 'left');
}
},
multishot: {
title: 'Triple Threat',
cost: 150,
apply: function apply(tower) {
tower.hasMultishot = true;
incrementUpgradeCounter(tower, 'left');
}
},
damage: {
title: 'Power Surge',
cost: 50,
apply: function apply(tower) {
tower.damage += 1;
}
},
left_final: {
title: 'Berserker Mode',
cost: 200,
apply: function apply(tower) {
tower.damage += 1;
tower.cadence = Math.max(50, tower.cadence * 0.25);
incrementUpgradeCounter(tower, 'left');
}
},
right1_damage: {
title: 'Brutal Force',
cost: 50,
apply: function apply(tower) {
tower.damage += 1;
incrementUpgradeCounter(tower, 'right');
}
},
right1_cross: {
title: 'Chain Lightning',
cost: 75,
apply: function apply(tower) {
tower.cross = (tower.cross || 1) + 2;
incrementUpgradeCounter(tower, 'right');
}
},
right1_range: {
title: 'Sniper Scope',
cost: 100,
apply: function apply(tower) {
tower.range = Math.floor(tower.range * 1.3);
tower.rangeSquared = tower.range * tower.range;
updateRangeArea(tower);
incrementUpgradeCounter(tower, 'right');
}
},
right1_cross_final: {
title: 'Storm Walker',
cost: 125,
apply: function apply(tower) {
tower.cross = (tower.cross || 1) + 2;
tower.bulletSpeedMultiplier = 1.3;
tower.bulletDurationMultiplier = 1.5;
incrementUpgradeCounter(tower, 'right');
}
},
right1_ultimate: {
title: 'Apocalypse',
cost: 300,
apply: function apply(tower) {
tower.bulletSpeedMultiplier = (tower.bulletSpeedMultiplier || 1) * 1.6;
tower.cross = (tower.cross || 1) + 6;
tower.damage += 2;
incrementUpgradeCounter(tower, 'right');
}
},
targeting_priority: {
title: 'Hunter Instinct',
cost: 0,
apply: function apply(tower) {
var priorities = ['first', 'last', 'strongest'];
var currentIndex = priorities.indexOf(tower.targetingPriority);
tower.targetingPriority = priorities[(currentIndex + 1) % priorities.length];
}
},
maxed: {
title: 'Legendary',
cost: 999999,
apply: function apply(tower) {
// Do nothing - this upgrade can't be purchased
}
}
};
// Upgrade path configurations
var leftUpgradePath = ['speed', 'range', 'multishot', 'left_final'];
var rightUpgradePath = ['right1_damage', 'right1_range', 'right1_cross_final', 'right1_ultimate'];
// Function to get current left upgrade options for a tower
function getLeftUpgradeOptions(tower) {
tower.leftUpgrades = tower.leftUpgrades || 0;
return leftUpgradePath[tower.leftUpgrades] || 'maxed';
}
// Function to get current right upgrade options for a tower
function getRightUpgradeOptions(tower) {
tower.rightUpgrades = tower.rightUpgrades || 0;
return {
first: rightUpgradePath[tower.rightUpgrades] || 'maxed',
second: null
};
}
// Left upgrade frame - Damage +1
var leftUpgradeFrame = towerUpgradeContainer.addChild(LK.getAsset('UpgradeBG', {
anchorX: 0.5,
anchorY: 0.5
}));
leftUpgradeFrame.x = -700;
leftUpgradeFrame.y = 180;
var leftUpgradeTitle = towerUpgradeContainer.addChild(new Text2('', {
size: 60,
fill: 0xFFFFFF
}));
leftUpgradeTitle.anchor.set(0.5, 0.5);
leftUpgradeTitle.x = -700;
leftUpgradeTitle.y = 0;
// Right upgrade frames and titles (only 2 slots)
var rightUpgradeFrame1 = towerUpgradeContainer.addChild(LK.getAsset('UpgradeBG', {
anchorX: 0.5,
anchorY: 0.5
}));
rightUpgradeFrame1.x = 100;
rightUpgradeFrame1.y = 180;
var rightUpgradeTitle1 = towerUpgradeContainer.addChild(new Text2('', {
size: 60,
fill: 0xFFFFFF
}));
rightUpgradeTitle1.anchor.set(0.5, 0.5);
rightUpgradeTitle1.x = 100;
rightUpgradeTitle1.y = 0;
var rightUpgradeFrame2 = towerUpgradeContainer.addChild(LK.getAsset('UpgradeBG', {
anchorX: 0.5,
anchorY: 0.5
}));
rightUpgradeFrame2.x = 400;
rightUpgradeFrame2.y = 180;
var rightUpgradeTitle2 = towerUpgradeContainer.addChild(new Text2('', {
size: 60,
fill: 0xFFFFFF
}));
rightUpgradeTitle2.anchor.set(0.5, 0.5);
rightUpgradeTitle2.x = 400;
rightUpgradeTitle2.y = 0;
// Priority button frame and title
var priorityUpgradeFrame = towerUpgradeContainer.addChild(LK.getAsset('UpgradeBG', {
anchorX: 0.5,
anchorY: 0.5
}));
priorityUpgradeFrame.x = 700;
priorityUpgradeFrame.y = 180;
var priorityUpgradeTitle = towerUpgradeContainer.addChild(new Text2('', {
size: 60,
fill: 0xFFFFFF
}));
priorityUpgradeTitle.anchor.set(0.5, 0.5);
priorityUpgradeTitle.x = 700;
priorityUpgradeTitle.y = 0;
// Store reference to currently selected tower
var selectedTowerForUpgrade = null;
// Function to switch UI modes
function setUIMode(mode) {
currentUIMode = mode;
if (mode === UI_MODE_TOWER_CREATION) {
// Show tower creation buttons and their backgrounds
for (var i = 0; i < towerButtons.length; i++) {
towerButtons[i].visible = true;
if (towerButtons[i].buttonBG) {
towerButtons[i].buttonBG.visible = true;
}
}
// Hide tower upgrade panel
towerUpgradeContainer.visible = false;
// Show fast mode button when in tower creation mode
if (speedButton && speedButton.parent) {
speedButton.visible = true;
}
// Show auto wave button when in tower creation mode
if (autoWaveButton && autoWaveButton.parent) {
autoWaveButton.visible = true;
}
} else if (mode === UI_MODE_TOWER_UPGRADE) {
// Hide tower creation buttons and their backgrounds
for (var i = 0; i < towerButtons.length; i++) {
towerButtons[i].visible = false;
if (towerButtons[i].buttonBG) {
towerButtons[i].buttonBG.visible = false;
}
}
// Show tower upgrade panel
towerUpgradeContainer.visible = true;
// Hide fast mode button when in tower upgrade mode
if (speedButton && speedButton.parent) {
speedButton.visible = false;
}
// Hide auto wave button when in tower upgrade mode
if (autoWaveButton && autoWaveButton.parent) {
autoWaveButton.visible = false;
}
}
}
// Function to create upgrade button with animation and functionality
function createUpgradeButton(upgradeType, x, y, container) {
var upgradeDef = upgradeDefinitions[upgradeType];
if (!upgradeDef) {
return null;
}
var upgradeButton = container.addChild(LK.getAsset('uiBackground', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.15
}));
upgradeButton.x = x;
upgradeButton.y = y;
var upgradeText = container.addChild(new Text2('BUY', {
size: 50,
fill: 0x000000
}));
upgradeText.anchor.set(0.5, 0.5);
upgradeText.x = x;
upgradeText.y = y;
// Add click handler with animation
upgradeButton.down = function (x, y, obj) {
if (selectedTowerForUpgrade && playerMoney >= upgradeDef.cost && upgradeType !== 'maxed') {
// Apply upgrade
upgradeDef.apply(selectedTowerForUpgrade);
// Deduct cost
playerMoney -= upgradeDef.cost;
// Animate button press effect
tween(upgradeButton, {
scaleX: 0.12,
scaleY: 0.12
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(upgradeButton, {
scaleX: 0.15,
scaleY: 0.15
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
// Flash button to show upgrade
LK.effects.flashObject(upgradeButton, 0xFFFFFF, 300);
// Refresh the upgrade display immediately after purchase
updateTowerUpgrade(selectedTowerForUpgrade);
}
};
return {
button: upgradeButton,
text: upgradeText,
updateDisplay: function updateDisplay() {
if (upgradeType === 'maxed') {
upgradeButton.alpha = 0.5;
upgradeText.alpha = 0.5;
upgradeText.setText('BUY MAX');
} else {
var canAfford = selectedTowerForUpgrade && playerMoney >= upgradeDef.cost;
upgradeButton.alpha = canAfford ? 1.0 : 0.5;
upgradeText.alpha = canAfford ? 1.0 : 0.5;
upgradeText.setText('BUY');
}
}
};
}
// Upgrade button configurations
var upgradeButtonConfigs = [{
type: 'left',
x: -700,
y: 380,
title: leftUpgradeTitle,
frame: leftUpgradeFrame
}, {
type: 'right1',
x: 100,
y: 380,
title: rightUpgradeTitle1,
frame: rightUpgradeFrame1
}, {
type: 'right2',
x: 400,
y: 380,
title: rightUpgradeTitle2,
frame: rightUpgradeFrame2
}, {
type: 'priority',
x: 700,
y: 380,
title: priorityUpgradeTitle,
frame: priorityUpgradeFrame
}];
// Function to update tower upgrade display
function updateTowerUpgrade(tower) {
if (tower) {
// Store reference to selected tower for upgrades
selectedTowerForUpgrade = tower;
// Switch to tower upgrade mode when a tower is selected
setUIMode(UI_MODE_TOWER_UPGRADE);
// Get current upgrade options for this tower
var leftOption = getLeftUpgradeOptions(tower);
var rightOptions = getRightUpgradeOptions(tower);
var upgradeOptions = [leftOption, rightOptions.first, rightOptions.second, 'targeting_priority'];
// Clean up existing upgrade buttons and create new ones
var upgradeButtons = [leftUpgrade, right1Upgrade, right2Upgrade, priorityUpgrade];
for (var i = 0; i < upgradeButtons.length; i++) {
// Clean up existing button
if (upgradeButtons[i] && upgradeButtons[i].button && upgradeButtons[i].button.parent) {
upgradeButtons[i].button.destroy();
upgradeButtons[i].text.destroy();
}
// Create new button
var config = upgradeButtonConfigs[i];
var option = upgradeOptions[i];
upgradeButtons[i] = option ? createUpgradeButton(option, config.x, config.y, towerUpgradeContainer) : null;
// Update frame visibility
if (option && upgradeDefinitions[option]) {
var title = option === 'targeting_priority' ? 'Priority: ' + (tower.targetingPriority === 'first' ? 'First' : tower.targetingPriority === 'last' ? 'Last' : 'Strongest') : upgradeDefinitions[option].title;
config.title.setText(title);
config.frame.visible = true;
config.title.visible = true;
} else {
config.title.setText('');
config.frame.visible = false;
config.title.visible = false;
}
// Update display
if (upgradeButtons[i]) {
upgradeButtons[i].updateDisplay();
}
}
// Update references
leftUpgrade = upgradeButtons[0];
right1Upgrade = upgradeButtons[1];
right2Upgrade = upgradeButtons[2];
priorityUpgrade = upgradeButtons[3];
} else {
// Clear reference to selected tower
selectedTowerForUpgrade = null;
// Hide priority upgrade frame when no tower selected
priorityUpgradeFrame.visible = false;
priorityUpgradeTitle.visible = false;
// Switch back to tower creation mode when no tower is selected
setUIMode(UI_MODE_TOWER_CREATION);
}
}
// Create upgrade buttons using the reusable system
var leftUpgrade = null; // Will be created dynamically
var right1Upgrade = null; // Will be created dynamically
var right2Upgrade = null; // Will be created dynamically
var priorityUpgrade = null; // Will be created dynamically
// Initialize with no tower selected and tower creation mode
updateTowerUpgrade(null);
setUIMode(UI_MODE_TOWER_CREATION);
// Add money, life and wave UI texts in the top-right corner
var moneyText = new Text2('Money: 100', {
size: 80,
fill: 0xFFFF00
});
moneyText.anchor.set(1, 0);
moneyText.x = 1900;
moneyText.y = 150;
game.addChild(moneyText);
var lifeText = new Text2('Life: 20', {
size: 80,
fill: 0xFF0000
});
lifeText.anchor.set(1, 0);
lifeText.x = 1900;
lifeText.y = 250;
game.addChild(lifeText);
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0x00FF00
});
waveText.anchor.set(1, 0);
waveText.x = 1900;
waveText.y = 350;
game.addChild(waveText);
// Add fast mode button to UI towers section
var speedButton = ui.addChild(LK.getAsset('x1Speed', {
anchorX: 0.5,
anchorY: 0.5
}));
speedButton.x = 800;
speedButton.y = -130;
// Add auto wave button below speed button
var autoWaveButton = ui.addChild(LK.getAsset('AutoWaveStop', {
anchorX: 0.5,
anchorY: 0.5
}));
autoWaveButton.x = 800;
autoWaveButton.y = 70;
// Add touch handler to speed button
speedButton.down = function (x, y, obj) {
// Toggle fastGame variable
fastGame = !fastGame;
// Update button asset to reflect current speed
if (fastGame) {
// Remove current button and create new one with FastMode asset
speedButton.destroy();
speedButton = ui.addChild(LK.getAsset('FastMode', {
anchorX: 0.5,
anchorY: 0.5
}));
speedButton.x = 800;
speedButton.y = -130;
// Re-attach the down handler to the new button
speedButton.down = arguments.callee;
} else {
// Remove current button and create new one with x1Speed asset
speedButton.destroy();
speedButton = ui.addChild(LK.getAsset('x1Speed', {
anchorX: 0.5,
anchorY: 0.5
}));
speedButton.x = 800;
speedButton.y = -130;
// Re-attach the down handler to the new button
speedButton.down = arguments.callee;
}
// Enemy speed updates - removed (no enemies exist)
};
// Add touch handler to auto wave button
autoWaveButton.down = function (x, y, obj) {
// Toggle autoStartWaves variable
autoStartWaves = !autoStartWaves;
// Update button asset to reflect current auto wave state
if (autoStartWaves) {
// Add rotation animation when auto wave is true
var _startAutoWaveAnimation = function startAutoWaveAnimation() {
tween(autoWaveButton, {
rotation: autoWaveButton.rotation + Math.PI * 4 // Rotate 2 full turns (4 * PI)
}, {
duration: 5000,
// Animation duration in milliseconds
easing: tween.easeInOut,
// Start slow, speed up, slow down
onFinish: function onFinish() {
// Animation complete, check if autoStartWaves is still true and repeat the animation
if (autoStartWaves && autoWaveButton && autoWaveButton.parent) {
_startAutoWaveAnimation(); // Start the animation again
}
}
});
};
// Remove current button and create new one with Wavestart asset
autoWaveButton.destroy();
autoWaveButton = ui.addChild(LK.getAsset('Wavestart', {
anchorX: 0.5,
anchorY: 0.5
}));
autoWaveButton.x = 800;
autoWaveButton.y = 70;
// Re-attach the down handler to the new button
autoWaveButton.down = arguments.callee;
// Wave start - removed (no waves exist)
_startAutoWaveAnimation(); // Initial call to start the loop
} else {
// Remove current button and create new one with AutoWaveStop asset
autoWaveButton.destroy();
autoWaveButton = ui.addChild(LK.getAsset('AutoWaveStop', {
anchorX: 0.5,
anchorY: 0.5
}));
autoWaveButton.x = 800;
autoWaveButton.y = 70;
// Re-attach the down handler to the new button
autoWaveButton.down = arguments.callee;
// Stop the rotation animation when auto wave is false
tween.stop(autoWaveButton, {
rotation: true
});
}
};
// Initialize game variables
var gameStart = false; // Boolean to control game start state
var playerMoney = 99999;
var playerLife = 20;
var currentWave = 1; // Reset to wave 1 (no wave system)
var PathShow = false; // Boolean to control path visibility
var vida = 20; // Player's life/health
var dinero = 100; // Player's money/currency
var fastGame = false; // Boolean to control 2x speed mode
var autoStartWaves = false; // Boolean to control automatic wave starting
// Camino path dimensions - can be changed while maintaining 200x200 default
var caminoWidth = 200;
var caminoHeight = 200;
// Top overlay layer (pointer on top of everything)
var puntero = game.addChild(LK.getAsset('Puntero', {
anchorX: 0.5,
anchorY: 0.5
}));
puntero.x = 1024;
puntero.y = 1366;
puntero.alpha = 0;
// Game move handler for dragging
game.move = function (x, y, obj) {
puntero.x = x;
puntero.y = y;
if (isDragging && draggedTower) {
var gameplayBounds = getGameplayBounds();
var uiBounds = getUIBounds();
var offset = calculateDragOffset(x, y);
var targetX = x + offset.offsetX;
var targetY = y + offset.offsetY;
// Apply boundary constraints
if (targetY > uiBounds.top) {
targetY = uiBounds.top - 70;
}
if (targetY < gameplayBounds.top) {
targetY = gameplayBounds.top + 70;
}
if (targetX < uiBounds.left) {
targetX = uiBounds.left + 70;
}
if (targetX < gameplayBounds.left + 70) {
targetX = gameplayBounds.left + 70;
}
if (targetX > gameplayBounds.right - 70) {
targetX = gameplayBounds.right - 70;
}
// Check if tower is too close to existing towers
var minDistance = 140; // Standardized minimum distance between towers
var minDistanceSquared = minDistance * minDistance;
var tooCloseToOtherTowers = false;
for (var i = 0; i < placedTowers.length; i++) {
var existingTower = placedTowers[i];
var dx = targetX - existingTower.x;
var dy = targetY - existingTower.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < minDistanceSquared) {
tooCloseToOtherTowers = true;
break;
}
}
// Check if tower would be placed on camino path
var onCamino = false;
for (var i = 0; i < caminoObjects.length; i++) {
var camino = caminoObjects[i];
// Use dynamic dimensions with scaling
var caminoEffectiveWidth = caminoWidth * camino.scaleX;
var caminoEffectiveHeight = caminoHeight * camino.scaleY;
// Check collision with rotated rectangle
if (isPointInRotatedRect(targetX, targetY, camino.x, camino.y, caminoEffectiveWidth, caminoEffectiveHeight, camino.rotation)) {
onCamino = true;
break;
}
}
// Update area tint based on pointer position and tower proximity
var pointerInUI = isPointInUI(puntero.x, puntero.y);
var cannotPlace = pointerInUI || tooCloseToOtherTowers || onCamino;
var finalX, finalY;
if (cannotPlace) {
// Apply red tint to area when cannot place tower
if (draggedTower.children[0]) {
draggedTower.children[0].tint = 0xff0000;
}
// If position is invalid, try to find the closest valid position
// First check if we have a last valid position
if (draggedTower.lastValidX !== undefined && draggedTower.lastValidY !== undefined) {
// Calculate distance to see if we should try to interpolate or just use last valid
var distanceToLastValid = Math.sqrt((targetX - draggedTower.lastValidX) * (targetX - draggedTower.lastValidX) + (targetY - draggedTower.lastValidY) * (targetY - draggedTower.lastValidY));
// If we're reasonably close to last valid position, try to find a valid position between current and last valid
if (distanceToLastValid < 250) {
var validPositionFound = false;
var steps = 20; // More steps for better precision
for (var step = 1; step <= steps; step++) {
var ratio = step / steps;
var testX = draggedTower.lastValidX + (targetX - draggedTower.lastValidX) * ratio;
var testY = draggedTower.lastValidY + (targetY - draggedTower.lastValidY) * ratio;
// Test this interpolated position
var testTooClose = false;
var testMinDistanceSquared = 140 * 140; // Use same standardized distance
for (var i = 0; i < placedTowers.length; i++) {
var existingTower = placedTowers[i];
var dx = testX - existingTower.x;
var dy = testY - existingTower.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < testMinDistanceSquared) {
testTooClose = true;
break;
}
}
var testOnCamino = false;
if (!testTooClose) {
for (var i = 0; i < caminoObjects.length; i++) {
var camino = caminoObjects[i];
// Use dynamic dimensions with scaling
var caminoEffectiveWidth = caminoWidth * camino.scaleX;
var caminoEffectiveHeight = caminoHeight * camino.scaleY;
// Check collision with rotated rectangle
if (isPointInRotatedRect(testX, testY, camino.x, camino.y, caminoEffectiveWidth, caminoEffectiveHeight, camino.rotation)) {
testOnCamino = true;
break;
}
}
}
var testPointerInUI = isPointInUI(testX, testY);
if (!testTooClose && !testOnCamino && !testPointerInUI) {
// Found a valid position
finalX = testX;
finalY = testY;
validPositionFound = true;
// Update last valid position to this new position
draggedTower.lastValidX = testX;
draggedTower.lastValidY = testY;
// Remove red tint since we found a valid position
if (draggedTower.children[0]) {
draggedTower.children[0].tint = 0xFFFFFF;
}
break;
}
}
if (!validPositionFound) {
// Use last valid position
finalX = draggedTower.lastValidX;
finalY = draggedTower.lastValidY;
}
} else {
// Too far from last valid position, just use it
finalX = draggedTower.lastValidX;
finalY = draggedTower.lastValidY;
}
} else {
// No last valid position, use target position (shouldn't happen with proper initialization)
finalX = targetX;
finalY = targetY;
}
} else {
// Remove tint from area when tower can be placed
if (draggedTower.children[0]) {
draggedTower.children[0].tint = 0xFFFFFF;
}
// Store this as the last valid position
draggedTower.lastValidX = targetX;
draggedTower.lastValidY = targetY;
finalX = targetX;
finalY = targetY;
}
// Apply different movement behavior based on validity
if (cannotPlace) {
// In invalid zones, use immediate positioning for quick stops
draggedTower.x = finalX;
draggedTower.y = finalY;
} else {
// In valid zones, use instant positioning for immediate tower appearance
draggedTower.x = finalX;
draggedTower.y = finalY;
}
}
};
// Cross variable to control bullet destruction after hitting enemies - now tower-specific
// var Cross = 1; // Removed global Cross, now each tower has its own cross value
// Variable to control enemy hitbox visibility
var shotHitbox = true; // When true, show enemy hitboxes; when false, hide them
// Game update handler
game.update = function () {
// Update UI texts with current values
moneyText.setText('Money: ' + playerMoney);
lifeText.setText('Life: ' + playerLife);
waveText.setText('Wave: ' + currentWave);
// Update path visibility based on PathShow variable
for (var i = 0; i < caminoObjects.length; i++) {
caminoObjects[i].alpha = PathShow ? 0.2 : 0;
}
// Enemy hitbox visibility - removed (no enemies exist)
// Wave spawning logic - removed (no enemies exist)
};
// Game release handler
game.up = function (x, y, obj) {
if (isDragging && draggedTower) {
var gameplayBounds = getGameplayBounds();
var uiBounds = getUIBounds();
var pointerInUI = isPointInUI(puntero.x, puntero.y);
var towerInUI = draggedTower.x >= uiBounds.left && draggedTower.x <= uiBounds.right && draggedTower.y >= uiBounds.top && draggedTower.y <= uiBounds.bottom;
// Check if tower is too close to existing towers at current position
var minDistance = 140; // Standardized minimum distance between towers
var minDistanceSquared = minDistance * minDistance;
var tooCloseToTowers = false;
for (var i = 0; i < placedTowers.length; i++) {
var existingTower = placedTowers[i];
var dx = draggedTower.x - existingTower.x;
var dy = draggedTower.y - existingTower.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared < minDistanceSquared) {
tooCloseToTowers = true;
break;
}
}
// Check if tower would be placed on camino path at current position
var onCamino = false;
for (var i = 0; i < caminoObjects.length; i++) {
var camino = caminoObjects[i];
// Use dynamic dimensions with scaling
var caminoEffectiveWidth = caminoWidth * camino.scaleX;
var caminoEffectiveHeight = caminoHeight * camino.scaleY;
// Check collision with rotated rectangle
if (isPointInRotatedRect(draggedTower.x, draggedTower.y, camino.x, camino.y, caminoEffectiveWidth, caminoEffectiveHeight, camino.rotation)) {
onCamino = true;
break;
}
}
var canPlaceAtCurrentPosition = !pointerInUI && !towerInUI && !tooCloseToTowers && !onCamino && draggedTower.x >= gameplayBounds.left && draggedTower.x <= gameplayBounds.right && draggedTower.y >= gameplayBounds.top && draggedTower.y <= gameplayBounds.bottom;
if (canPlaceAtCurrentPosition) {
// Can place at current position
draggedTower.alpha = 1.0;
draggedTower.tint = 0xffffff;
draggedTower.hideRange(); // Hide range area when placed
draggedTower.isPlaced = true; // Set placement status
placedTowers.push(draggedTower); // Add to placed towers array
LK.getSound('TorreColocada').play(); // Play tower placement sound
} else {
// Cannot place at current position - destroy tower if it's in UI or invalid position
draggedTower.destroy();
}
isDragging = false;
draggedTower = null;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1315,9 +1315,9 @@
game.update = function () {
// Update UI texts with current values
moneyText.setText('Money: ' + playerMoney);
lifeText.setText('Life: ' + playerLife);
- waveText.setText('Wave: ' + (currentWaveIndex + 1));
+ waveText.setText('Wave: ' + currentWave);
// Update path visibility based on PathShow variable
for (var i = 0; i < caminoObjects.length; i++) {
caminoObjects[i].alpha = PathShow ? 0.2 : 0;
}