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
User prompt
Haz que todos los enemigos tengan 1 de vida y que al morir es cuando se vuelve la inferior con este jerarquía: Rosa -> amarillo -> verde -> azul -> rojo
User prompt
Elimina esa clasificación de "healthlayers == 5" y haz utilizando una variable texto para determinar el color y velocidad según el enemigo específico y no por su capa de via
User prompt
Haz que cada enemigo esté por separado del otro y no los clasifiquen según su vida, esto no permite agregar dos enemigos con la mismas cantidad de capas
User prompt
Haz que los enemigos no se determinen por sus capas, esto genera errores
User prompt
Arraiga los colores de los enemigos a su nombre clave, básico 1 = rojo, básico 2 = azul, etc
User prompt
Haz que Anti hielo y anti fuego tengan una capa
User prompt
Establece la oleada inicial en 1
User prompt
Agrega un anti hielo y fuego en la oleada 1
User prompt
Crea dos enemigos nuevos Anti hielo (color blanco) y anti fuego (color negro) y haz que al morir suelten 4 enemigos de capa rosa
User prompt
Arregla el error de que enemigo negro salga como color blanco, esto no permite determinar si es anti hielo o anti fuego
User prompt
Mueve los enemigos anti hielo y anti fuego externos al código de creación de enemigos. Pero mantén las mismas funciones
User prompt
Haz que Anti hielo y anti fuego sea casos especiales de enemigos externos a los principales pero con funciones similares
User prompt
Arregla el error que no permite tener los anit hielos blancos y a la vez los Anti fuegos negros
/**** * 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; // Check collision with all enemies, not just the original target for (var e = 0; e < enemies.length; e++) { var enemy = enemies[e]; if (enemy && enemy.parent) { // Skip enemies that have already been hit by this bullet if (self.hitEnemies && self.hitEnemies.indexOf(enemy) !== -1) { continue; } // Check collision with enemy's hitbox instead of enemy center var hitbox = null; // Find the hitbox child in the enemy for (var i = 0; i < enemy.children.length; i++) { var child = enemy.children[i]; // Check by texture URL first if (child.texture && child.texture.baseTexture && child.texture.baseTexture.resource && child.texture.baseTexture.resource.url && child.texture.baseTexture.resource.url.includes('hitbox')) { hitbox = child; break; } // Check by alpha value (hitbox has alpha 0.2 when visible, 0 when invisible) if (child.alpha === 0.2 || child.alpha === 0) { // Additional check: hitbox should have width and height of 120 if (child.width === 120 && child.height === 120) { hitbox = child; break; } } } if (hitbox) { // Calculate distance to hitbox position (relative to enemy) var hitboxWorldX = enemy.x + hitbox.x; var hitboxWorldY = enemy.y + hitbox.y; var dx = hitboxWorldX - self.x; var dy = hitboxWorldY - self.y; var distanceSquared = dx * dx + dy * dy; // Use appropriate hitbox size for collision detection (hitbox is 120x120) var hitboxRadius = 60; // Standard collision radius matching visual hitbox if (distanceSquared < hitboxRadius * hitboxRadius) { // Initialize hit enemies array if it doesn't exist if (!self.hitEnemies) { self.hitEnemies = []; } // Add this enemy to the hit list self.hitEnemies.push(enemy); // Apply damage to enemy using its takeDamage method if (enemy.takeDamage) { enemy.takeDamage(self.damage); } // Add damage to tower's total damage counter if (self.towerRef && self.towerRef.parent) { self.towerRef.totalDamage += self.damage; } // Increment hit count and check if bullet should be destroyed self.hitCount++; var towerCross = self.towerRef && self.towerRef.cross ? self.towerRef.cross : 1; if (self.hitCount >= towerCross) { // Bullet has hit the required number of enemies, destroy it self.isAlive = false; if (self.parent) { self.destroy(); } return; } // Continue to check other enemies break; } } else { // Fallback to enemy center if hitbox not found var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distanceSquared = dx * dx + dy * dy; // If close enough to target, hit it (using squared distance to avoid sqrt) if (distanceSquared < 1600) { // 40 * 40 = 1600 - reasonable collision radius for visual accuracy // Initialize hit enemies array if it doesn't exist if (!self.hitEnemies) { self.hitEnemies = []; } // Add this enemy to the hit list self.hitEnemies.push(enemy); // Apply damage to enemy using its takeDamage method if (enemy.takeDamage) { enemy.takeDamage(self.damage); } // Add damage to tower's total damage counter if (self.towerRef && self.towerRef.parent) { self.towerRef.totalDamage += self.damage; } // Increment hit count and check if bullet should be destroyed self.hitCount++; var towerCross = self.towerRef && self.towerRef.cross ? self.towerRef.cross : 1; if (self.hitCount >= towerCross) { // Bullet has hit the required number of enemies, destroy it self.isAlive = false; if (self.parent) { self.destroy(); } return; } // Continue to check other enemies break; } } } } }; 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 self.findEnemiesInRange = function () { var enemiesInRange = []; // Check all enemies in the enemies array for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (enemy && enemy.parent) { var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distanceSquared = dx * dx + dy * dy; if (distanceSquared <= self.rangeSquared) { // Analyze total incoming damage from all towers targeting this enemy var totalIncomingDamage = 0; var isBeingTargeted = false; // Check all towers and their bullets targeting this enemy for (var j = 0; j < placedTowers.length; j++) { var otherTower = placedTowers[j]; if (otherTower !== self) { // Check if this tower is targeting the enemy if (otherTower.currentTarget === enemy) { isBeingTargeted = true; } // Count all bullets from this tower that are targeting this enemy for (var k = 0; k < otherTower.bullets.length; k++) { var bullet = otherTower.bullets[k]; if (bullet && bullet.target === enemy && bullet.isAlive) { // Check if bullet hasn't already hit this enemy if (!bullet.hitEnemies || bullet.hitEnemies.indexOf(enemy) === -1) { totalIncomingDamage += bullet.damage; } } } } } // Add enemy to list if: // 1. Not being targeted at all, OR // 2. Being targeted but total incoming damage won't kill it var canTarget = !isBeingTargeted || totalIncomingDamage < enemy.currentHealth; if (canTarget) { enemiesInRange.push(enemy); } } } } // Sort enemies based on targeting priority enemiesInRange.sort(function (a, b) { if (self.targetingPriority === 'first') { // Calculate progress for enemy a var progressA = a.currentWaypointIndex; if (a.currentWaypointIndex < caminoPositions.length - 1) { var currentWaypointA = caminoPositions[a.currentWaypointIndex]; var nextWaypointA = caminoPositions[a.currentWaypointIndex + 1]; var totalDistanceA = Math.sqrt((nextWaypointA.x - currentWaypointA.x) * (nextWaypointA.x - currentWaypointA.x) + (nextWaypointA.y - currentWaypointA.y) * (nextWaypointA.y - currentWaypointA.y)); var coveredDistanceA = Math.sqrt((a.x - currentWaypointA.x) * (a.x - currentWaypointA.x) + (a.y - currentWaypointA.y) * (a.y - currentWaypointA.y)); progressA += totalDistanceA > 0 ? coveredDistanceA / totalDistanceA : 0; } // Calculate progress for enemy b var progressB = b.currentWaypointIndex; if (b.currentWaypointIndex < caminoPositions.length - 1) { var currentWaypointB = caminoPositions[b.currentWaypointIndex]; var nextWaypointB = caminoPositions[b.currentWaypointIndex + 1]; var totalDistanceB = Math.sqrt((nextWaypointB.x - currentWaypointB.x) * (nextWaypointB.x - currentWaypointB.x) + (nextWaypointB.y - currentWaypointB.y) * (nextWaypointB.y - currentWaypointB.y)); var coveredDistanceB = Math.sqrt((b.x - currentWaypointB.x) * (b.x - currentWaypointB.x) + (b.y - currentWaypointB.y) * (b.y - currentWaypointB.y)); progressB += totalDistanceB > 0 ? coveredDistanceB / totalDistanceB : 0; } // Sort in descending order (highest progress first = closest to end) return progressB - progressA; } else if (self.targetingPriority === 'last') { // Calculate progress for enemy a var progressA = a.currentWaypointIndex; if (a.currentWaypointIndex < caminoPositions.length - 1) { var currentWaypointA = caminoPositions[a.currentWaypointIndex]; var nextWaypointA = caminoPositions[a.currentWaypointIndex + 1]; var totalDistanceA = Math.sqrt((nextWaypointA.x - currentWaypointA.x) * (nextWaypointA.x - currentWaypointA.x) + (nextWaypointA.y - currentWaypointA.y) * (nextWaypointA.y - currentWaypointA.y)); var coveredDistanceA = Math.sqrt((a.x - currentWaypointA.x) * (a.x - currentWaypointA.x) + (a.y - currentWaypointA.y) * (a.y - currentWaypointA.y)); progressA += totalDistanceA > 0 ? coveredDistanceA / totalDistanceA : 0; } // Calculate progress for enemy b var progressB = b.currentWaypointIndex; if (b.currentWaypointIndex < caminoPositions.length - 1) { var currentWaypointB = caminoPositions[b.currentWaypointIndex]; var nextWaypointB = caminoPositions[b.currentWaypointIndex + 1]; var totalDistanceB = Math.sqrt((nextWaypointB.x - currentWaypointB.x) * (nextWaypointB.x - currentWaypointB.x) + (nextWaypointB.y - currentWaypointB.y) * (nextWaypointB.y - currentWaypointB.y)); var coveredDistanceB = Math.sqrt((b.x - currentWaypointB.x) * (b.x - currentWaypointB.x) + (b.y - currentWaypointB.y) * (b.y - currentWaypointB.y)); progressB += totalDistanceB > 0 ? coveredDistanceB / totalDistanceB : 0; } // Sort in ascending order (lowest progress first = farthest from end) return progressA - progressB; } else if (self.targetingPriority === 'strongest') { // Sort by health (highest health first = strongest) return b.currentHealth - a.currentHealth; } return 0; }); return enemiesInRange; }; // 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); // Predict enemy position based on distance 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 timeToReach = distance / bulletSpeed; // time in seconds for bullet to reach current target position // Calculate enemy movement prediction - farther enemies get more prediction (reduced) var baseEnemySpeed = 260; // Base enemy speed in pixels per second var enemySpeed = getEnemySpeed(target); // Adjust prediction factor based on fastGame mode for better accuracy var predictionFactor = fastGame ? 0.8 : 0.6; // More aggressive prediction in fast mode var predictionDistance = enemySpeed * timeToReach * predictionFactor; // Get enemy's current movement direction var enemyDx = 0; var enemyDy = 0; if (target.currentWaypointIndex < caminoPositions.length - 1) { var nextWaypoint = caminoPositions[target.currentWaypointIndex + 1]; enemyDx = nextWaypoint.x - target.x; enemyDy = nextWaypoint.y - target.y; var enemyMoveDistance = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy); if (enemyMoveDistance > 0) { // Normalize enemy direction enemyDx = enemyDx / enemyMoveDistance; enemyDy = enemyDy / enemyMoveDistance; } } // Calculate predicted target position var predictedX = target.x + enemyDx * predictionDistance; var predictedY = target.y + enemyDy * predictionDistance; // 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); } } // Only shoot if tower is placed (check cached status) if (self.isPlaced) { // Clear current target if it's no longer valid if (self.currentTarget && (!self.currentTarget.parent || self.currentTarget.currentHealth <= 0)) { self.currentTarget = null; } // Find and shoot at enemies var enemies = self.findEnemiesInRange(); if (enemies.length > 0) { var target = enemies[0]; // Set current target self.currentTarget = target; // Calculate predicted target position for tower rotation var distance = Math.sqrt((target.x - self.x) * (target.x - self.x) + (target.y - self.y) * (target.y - self.y)); var bulletSpeed = 800; // pixels per second // Apply fastGame speed boost to bullet speed for prediction calculations if (fastGame) { bulletSpeed = bulletSpeed * 1.5; } var timeToReach = distance / bulletSpeed; var enemySpeed = getEnemySpeed(target); // Adjust prediction factor based on fastGame mode for better accuracy var predictionFactor = fastGame ? 0.8 : 0.6; // More aggressive prediction in fast mode var predictionDistance = enemySpeed * timeToReach * predictionFactor; // Get enemy's current movement direction var enemyDx = 0; var enemyDy = 0; if (target.currentWaypointIndex < caminoPositions.length - 1) { var nextWaypoint = caminoPositions[target.currentWaypointIndex + 1]; enemyDx = nextWaypoint.x - target.x; enemyDy = nextWaypoint.y - target.y; var enemyMoveDistance = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy); if (enemyMoveDistance > 0) { // Normalize enemy direction enemyDx = enemyDx / enemyMoveDistance; enemyDy = enemyDy / enemyMoveDistance; } } // Calculate predicted target position var predictedX = target.x + enemyDx * predictionDistance; var predictedY = target.y + enemyDy * predictionDistance; // Calculate angle to predicted target position var dx = predictedX - self.x; var dy = predictedY - self.y; var targetAngle = Math.atan2(dy, dx) + Math.PI / 2; // Add 90° rotation offset // Smooth rotation using tween animation var angleDiff = targetAngle - towerGraphics.rotation; // Normalize angle difference to shortest path while (angleDiff > Math.PI) { angleDiff -= 2 * Math.PI; } while (angleDiff < -Math.PI) { angleDiff += 2 * Math.PI; } // Only rotate if angle difference is significant (> 0.1 radians) if (Math.abs(angleDiff) > 0.1) { // Stop any existing rotation tween tween.stop(towerGraphics, { rotation: true }); // Animate rotation smoothly tween(towerGraphics, { rotation: targetAngle }, { duration: 200, easing: tween.easeOut }); } // Keep tower orientation consistent - no flipping based on target position towerGraphics.scaleY = -1; // Always maintain normal orientation // Shoot at the first enemy found self.shoot(target); } else { // No enemies in range, clear current target self.currentTarget = null; } } }; // 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 var enemies = []; // Dynamic wave generation function function generateWaveData() { var waves = []; var baseEnemyCount = 10; var baseSpawnDelay = 800; for (var i = 0; i < 15; i++) { waves.push({ enemyCount: baseEnemyCount + i * 5, spawnDelay: Math.max(220, baseSpawnDelay - i * 40), // Dynamic enemy distribution based on wave number distribution: getWaveDistribution(i) }); } return waves; } // Simplified enemy distribution logic function getWaveDistribution(waveIndex) { var distributions = [[10, 0, 0, 0, 0, 0], // Wave 1: 10x1-layer [15, 5, 0, 0, 0, 0], // Wave 2: 15x1-layer, 5x2-layer [15, 5, 5, 0, 0, 0], // Wave 3: 15x1, 5x2, 5x3-layer [15, 10, 5, 0, 0, 0], // Wave 4: 15x1, 10x2, 5x3-layer [15, 10, 10, 0, 0, 0], // Wave 5: 15x1, 10x2, 10x3-layer [15, 15, 10, 0, 0, 0], // Wave 6: 15x1, 15x2, 10x3-layer [15, 15, 15, 0, 0, 0], // Wave 7: 15x1, 15x2, 15x3-layer [15, 20, 15, 0, 0, 0], // Wave 8: 15x1, 20x2, 15x3-layer [15, 20, 20, 0, 0, 0], // Wave 9: 15x1, 20x2, 20x3-layer [15, 25, 20, 0, 0, 0], // Wave 10: 15x1, 25x2, 20x3-layer [15, 25, 20, 5, 0, 0], // Wave 11: 15x1, 25x2, 20x3, 5x4-layer [15, 25, 20, 10, 0, 0], // Wave 12: 15x1, 25x2, 20x3, 10x4-layer [15, 20, 20, 15, 5, 0], // Wave 13: 15x1, 20x2, 20x3, 15x4, 5x5-layer [15, 20, 20, 15, 10, 0], // Wave 14: 15x1, 20x2, 20x3, 15x4, 10x5-layer [15, 20, 20, 15, 15, 5] // Wave 15: 15x1, 20x2, 20x3, 15x4, 15x5-layer, 5x6-layer ]; return distributions[waveIndex] || [10, 0, 0, 0, 0, 0]; } // Optimized function to determine enemy health layers function getEnemyHealthLayers(waveIndex, enemyIndex) { var distribution = getWaveDistribution(waveIndex); var cumulative = 0; for (var layer = 0; layer < distribution.length; layer++) { cumulative += distribution[layer]; if (enemyIndex < cumulative) { return layer + 1; } } return 1; // Default to 1 layer } var waveData = generateWaveData(); var currentWaveIndex = 0; var enemiesSpawned = 0; var waveInProgress = false; var nextSpawnTime = 0; // Base enemy class with common functionality function createEnemyBase(healthLayers, speedMultiplier, color) { return Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('Enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); // Add hitbox to enemy var hitboxGraphics = self.attachAsset('hitbox', { anchorX: 0.5, anchorY: 0.5 }); hitboxGraphics.alpha = shotHitbox ? 0.2 : 0; // Set starting position to first camino waypoint self.x = caminoPositions[0].x; self.y = caminoPositions[0].y; // Path following properties self.currentWaypointIndex = 0; self.isMoving = false; // Health system for enemy self.maxHealth = healthLayers; self.currentHealth = self.maxHealth; self.healthLayers = []; self.canBeDestroyed = false; self.speedMultiplier = speedMultiplier; // Create health layers based on healthLayers parameter for (var i = 0; i < healthLayers; i++) { var colors = [0xff0000, 0x0000ff, 0x00ff00, 0xffff00, 0xff00ff, 0xFFFFFF]; // Red, Blue, Green, Yellow, Pink, White self.healthLayers.push({ min: i + 1, max: i + 1, color: colors[i % colors.length] }); } // Method to update enemy color based on health self.updateHealthColor = function () { for (var i = 0; i < this.healthLayers.length; i++) { var layer = this.healthLayers[i]; if (this.currentHealth >= layer.min && this.currentHealth <= layer.max) { // Animate color transition using tween tween(this, { tint: layer.color }, { duration: 200, easing: tween.easeOut }); break; } } }; // Method to take damage self.takeDamage = function (damage) { var oldHealth = this.currentHealth; this.currentHealth = Math.max(0, this.currentHealth - damage); // Check if we crossed a layer boundary var oldLayer = -1; var newLayer = -1; for (var i = 0; i < this.healthLayers.length; i++) { var layer = this.healthLayers[i]; if (oldHealth >= layer.min && oldHealth <= layer.max) { oldLayer = i; } if (this.currentHealth >= layer.min && this.currentHealth <= layer.max) { newLayer = i; } } // Update color if we changed layers or if this is the first damage if (oldLayer !== newLayer || oldHealth === this.maxHealth) { this.updateHealthColor(); } // Update speed multiplier and movement speed based on new current health var newSpeed = getEnemySpeed(this); this.speedMultiplier = newSpeed / 260; // Calculate multiplier from speed // Immediately update movement speed if enemy is currently moving if (this.isMoving && this.moveSpeed) { // Apply fastGame speed boost if (fastGame) { newSpeed = newSpeed * 1.5; // 50% faster when fastGame is true } this.moveSpeed = newSpeed / 60; // Convert to pixels per frame (60 FPS) } // Check if enemy is dead if (this.currentHealth <= 0) { // Play random enemy death sound (1 of 3) var deathSounds = ['EnemyDerrivado', 'EnemigoDerrivado2', 'EnemigoDerrivado3']; var randomSoundIndex = Math.floor(Math.random() * deathSounds.length); LK.getSound(deathSounds[randomSoundIndex]).play(); // Stop any running animations if enemy is in end animation if (this.canBeDestroyed) { tween.stop(this, { scaleX: true, scaleY: true, alpha: true }); } // Remove from enemies array for (var j = 0; j < enemies.length; j++) { if (enemies[j] === this) { enemies.splice(j, 1); break; } } // Enemy is destroyed, remove it from the game this.destroy(); } }; // Method to move to next waypoint self.moveToNextWaypoint = function () { if (this.isMoving) { return; } // Don't start new movement if already moving // Check if we've reached near the end of the path (start animation much earlier) if (this.currentWaypointIndex >= caminoPositions.length - 2) { // Start shrinking and fading animation much earlier (5 waypoints before the end) this.canBeDestroyed = true; // Mark enemy as able to be destroyed during animation this.isEndAnimation = true; this.endAnimationTimer = 3000; // 3 seconds for end animation this.endAnimationStartScale = { x: this.scaleX, y: this.scaleY }; this.endAnimationStartAlpha = this.alpha; return; } this.currentWaypointIndex = (this.currentWaypointIndex + 1) % caminoPositions.length; var nextWaypoint = caminoPositions[this.currentWaypointIndex]; // Calculate movement properties for frame-by-frame movement var dx = nextWaypoint.x - this.x; var dy = nextWaypoint.y - this.y; var distance = Math.sqrt(dx * dx + dy * dy); var speed = getEnemySpeed(this); // Apply fastGame speed boost if (fastGame) { speed = speed * 1.5; // 50% faster when fastGame is true } // Store movement properties this.targetX = nextWaypoint.x; this.targetY = nextWaypoint.y; this.moveDirectionX = dx / distance; // Normalized direction this.moveDirectionY = dy / distance; this.moveSpeed = speed / 60; // Convert to pixels per frame (60 FPS) this.isMoving = true; // Calculate rotation to face the next waypoint var angle = Math.atan2(dy, dx); this.targetRotation = angle; // Calculate rotation difference for smooth rotation var angleDiff = angle - this.rotation; // Normalize angle difference to shortest path while (angleDiff > Math.PI) { angleDiff -= 2 * Math.PI; } while (angleDiff < -Math.PI) { angleDiff += 2 * Math.PI; } // Only rotate if angle difference is significant enough if (Math.abs(angleDiff) > 0.05) { // Stop any existing rotation tween tween.stop(this, { rotation: true }); // Calculate rotation duration based on enemy speed for more responsive turning var baseDuration = 400; // Base duration in milliseconds var speedFactor = this.speedMultiplier || 1; var rotationDuration = Math.max(150, baseDuration / speedFactor); // Faster enemies turn quicker // Adjust duration based on how much we need to turn var angleMagnitude = Math.abs(angleDiff); var angleFactor = angleMagnitude / Math.PI; // 0 to 1 based on how much turn is needed rotationDuration = rotationDuration * (0.3 + 0.7 * angleFactor); // Scale duration with turn amount // Use tween for smooth, velocity-adjusted rotation tween(this, { rotation: angle }, { duration: rotationDuration, easing: tween.easeOut }); } }; // Frame-by-frame update method for movement self.update = function () { // Handle end animation if (this.isEndAnimation) { var animationSpeedMultiplier = fastGame ? 1.5 : 1.0; // 50% faster animation when fastGame is true this.endAnimationTimer -= frameTime * 1000 * animationSpeedMultiplier; // Convert frame time to milliseconds and apply speed multiplier var progress = 1 - this.endAnimationTimer / 3000; // Progress from 0 to 1 // Animate scale and alpha this.scaleX = this.endAnimationStartScale.x * (1 - progress * 0.9); // Scale down to 10% this.scaleY = this.endAnimationStartScale.y * (1 - progress * 0.9); this.alpha = this.endAnimationStartAlpha * (1 - progress); // Fade to 0 if (this.endAnimationTimer <= 0) { // Animation complete if (!this.parent) { return; // Enemy was already destroyed } // Enemy reached the end - reduce player life based on remaining health layers playerLife -= this.currentHealth; // Update life display lifeText.setText('Life: ' + playerLife); // Check if player is defeated if (playerLife <= 0) { LK.showGameOver(); return; } // Remove from enemies array for (var j = 0; j < enemies.length; j++) { if (enemies[j] === this) { enemies.splice(j, 1); break; } } // Destroy the enemy this.destroy(); } return; } // Rotation is now handled by tween system in moveToNextWaypoint method // Handle movement if (this.isMoving) { // Move towards target this.x += this.moveDirectionX * this.moveSpeed; this.y += this.moveDirectionY * this.moveSpeed; // Check if we've reached the target waypoint var dx = this.targetX - this.x; var dy = this.targetY - this.y; var distanceToTarget = Math.sqrt(dx * dx + dy * dy); if (distanceToTarget <= this.moveSpeed) { // Snap to target position this.x = this.targetX; this.y = this.targetY; this.isMoving = false; // Move to next waypoint immediately this.moveToNextWaypoint(); } } }; // Initialize enemy color self.updateHealthColor(); // Start movement after a short delay LK.setTimeout(function () { self.moveToNextWaypoint(); }, 500); return self; }); } // Enemy Layer 1 (Red, base speed) var EnemyCapa1 = createEnemyBase(1, 1.0, 0xff0000); // Enemy Layer 2 (Blue, 5% faster) var EnemyCapa2 = createEnemyBase(2, 1.05, 0x0000ff); // Enemy Layer 3 (Green, 10% faster) var EnemyCapa3 = createEnemyBase(3, 1.1, 0x00ff00); // Enemy Layer 4 (Yellow, 75% faster) var EnemyCapa4 = createEnemyBase(4, 1.75, 0xffff00); // Enemy Layer 5 (Pink, 150% faster) var EnemyCapa5 = createEnemyBase(5, 2.5, 0xff00ff); // Enemy Layer 6 (White, 10% faster - same as green) var EnemyCapa6 = createEnemyBase(6, 1.1, 0xFFFFFF); // Centralized enemy speed calculation function function getEnemySpeed(enemy) { var baseEnemySpeed = 260; // Base enemy speed in pixels per second var enemySpeedMultiplier = 1.0; if (enemy.currentHealth === 2) { enemySpeedMultiplier = 1.05; // 5% faster for 2 layers } else if (enemy.currentHealth === 3) { enemySpeedMultiplier = 1.1; // 10% faster for 3 layers } else if (enemy.currentHealth === 4) { enemySpeedMultiplier = 1.75; // 75% faster for 4 layers (yellow) } else if (enemy.currentHealth === 5) { enemySpeedMultiplier = 2.5; // 150% faster for 5 layers (pink) } else if (enemy.currentHealth === 6) { enemySpeedMultiplier = 1.1; // 10% faster for 6 layers (white) - same as green } return baseEnemySpeed * enemySpeedMultiplier; } // Function to update all enemy speeds (useful for fastGame toggle) function updateAllEnemySpeeds() { for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (enemy && enemy.parent && enemy.isMoving && enemy.moveSpeed) { var newSpeed = getEnemySpeed(enemy); // Apply fastGame speed boost if (fastGame) { newSpeed = newSpeed * 1.5; // 50% faster when fastGame is true } enemy.moveSpeed = newSpeed / 60; // Convert to pixels per frame (60 FPS) } } } // Function to create enemy with specified health layers (for compatibility) function createEnemy(healthLayers) { var enemy; switch (healthLayers) { case 1: enemy = game.addChild(new EnemyCapa1()); break; case 2: enemy = game.addChild(new EnemyCapa2()); break; case 3: enemy = game.addChild(new EnemyCapa3()); break; case 4: enemy = game.addChild(new EnemyCapa4()); break; case 5: enemy = game.addChild(new EnemyCapa5()); break; case 6: enemy = game.addChild(new EnemyCapa6()); break; default: enemy = game.addChild(new EnemyCapa1()); break; } enemies.push(enemy); return enemy; } // Function to start a wave function startWave(waveIndex) { if (waveIndex >= waveData.length) { // All waves completed LK.showYouWin(); return; } currentWaveIndex = waveIndex; enemiesSpawned = 0; waveInProgress = true; nextSpawnTime = Date.now() + 2000; // Start spawning after 2 seconds currentWave = waveIndex + 1; } // Start first wave only if autoStartWaves is true if (autoStartWaves) { startWave(0); } // Enemy is now stationary - no movement code needed // 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; } // Immediately update all existing enemies' speeds updateAllEnemySpeeds(); // Immediately update next spawn time to prevent delayed spawning if (waveInProgress && nextSpawnTime > Date.now()) { var currentWaveData = waveData[currentWaveIndex]; var baseSpawnDelay = currentWaveData.spawnDelay; var adjustedSpawnDelay = fastGame ? baseSpawnDelay / 1.5 : baseSpawnDelay; var timeRemaining = nextSpawnTime - Date.now(); var newTimeRemaining = fastGame ? timeRemaining / 1.5 : timeRemaining * 1.5; nextSpawnTime = Date.now() + newTimeRemaining; } }; // 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; // Start the first wave if no wave is in progress if (!waveInProgress && currentWaveIndex < waveData.length) { startWave(currentWaveIndex); } _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; 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: ' + (currentWaveIndex + 1)); // Update path visibility based on PathShow variable for (var i = 0; i < caminoObjects.length; i++) { caminoObjects[i].alpha = PathShow ? 0.2 : 0; } // Update enemy hitbox visibility based on shotHitbox variable for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (enemy && enemy.parent) { // Find the hitbox child in the enemy for (var j = 0; j < enemy.children.length; j++) { var child = enemy.children[j]; // Check if this is a hitbox (either by texture URL or by alpha value) var isHitbox = false; if (child.texture && child.texture.baseTexture && child.texture.baseTexture.resource && child.texture.baseTexture.resource.url && child.texture.baseTexture.resource.url.includes('hitbox')) { isHitbox = true; } else if (child.alpha === 0.2 || child.alpha === 0) { // This might be a hitbox based on alpha value isHitbox = true; } if (isHitbox) { child.alpha = shotHitbox ? 0.2 : 0; break; } } } } // Wave spawning logic if (waveInProgress && currentWaveIndex < waveData.length) { var currentWaveData = waveData[currentWaveIndex]; var currentTime = Date.now(); if (currentTime >= nextSpawnTime && enemiesSpawned < currentWaveData.enemyCount) { // Determine health layers for this enemy using optimized function var healthLayers = getEnemyHealthLayers(currentWaveIndex, enemiesSpawned); // Spawn enemy createEnemy(healthLayers); enemiesSpawned++; var spawnDelay = currentWaveData.spawnDelay; // Apply fastGame spawn rate boost (50% faster = divide by 1.5) if (fastGame) { spawnDelay = spawnDelay / 1.5; } nextSpawnTime = currentTime + spawnDelay; } // Check if wave is complete if (enemiesSpawned >= currentWaveData.enemyCount && enemies.length === 0) { waveInProgress = false; // Start next wave after a delay only if autoStartWaves is true if (autoStartWaves) { var waveDelay = 500; // 0.5 second delay between waves (much faster) // Apply fastGame wave interval boost (50% faster = divide by 1.5) if (fastGame) { waveDelay = waveDelay / 1.5; } LK.setTimeout(function () { startWave(currentWaveIndex + 1); }, waveDelay); } } } }; // 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
@@ -1209,10 +1209,10 @@
// Enemy Layer 4 (Yellow, 75% faster)
var EnemyCapa4 = createEnemyBase(4, 1.75, 0xffff00);
// Enemy Layer 5 (Pink, 150% faster)
var EnemyCapa5 = createEnemyBase(5, 2.5, 0xff00ff);
-// Enemy Layer 6 (White, 300% faster)
-var EnemyCapa6 = createEnemyBase(6, 4.0, 0xFFFFFF);
+// Enemy Layer 6 (White, 10% faster - same as green)
+var EnemyCapa6 = createEnemyBase(6, 1.1, 0xFFFFFF);
// Centralized enemy speed calculation function
function getEnemySpeed(enemy) {
var baseEnemySpeed = 260; // Base enemy speed in pixels per second
var enemySpeedMultiplier = 1.0;
@@ -1224,9 +1224,9 @@
enemySpeedMultiplier = 1.75; // 75% faster for 4 layers (yellow)
} else if (enemy.currentHealth === 5) {
enemySpeedMultiplier = 2.5; // 150% faster for 5 layers (pink)
} else if (enemy.currentHealth === 6) {
- enemySpeedMultiplier = 4.0; // 300% faster for 6 layers (white)
+ enemySpeedMultiplier = 1.1; // 10% faster for 6 layers (white) - same as green
}
return baseEnemySpeed * enemySpeedMultiplier;
}
// Function to update all enemy speeds (useful for fastGame toggle)