/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bird = Container.expand(function () { var self = Container.call(this); var birdGraphics = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); self.health = 250; self.maxHealth = 250; self.speed = 3.0 + Math.random() * 1.0; // Faster than other enemies self.pathIndex = 0; self.reward = 35; // Medium reward // Create health bar components var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBarBg.x = 0; healthBarBg.y = -55; var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5 }); healthBarFill.x = -35; healthBarFill.y = -55; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.update = function () { if (self.pathIndex < gamePath.length) { var target = gamePath[self.pathIndex]; var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { self.pathIndex++; if (self.pathIndex >= gamePath.length) { // Bird reached the end - damage packet (8% of current health) packetHealth -= Math.floor(packetHealth * 0.08); updatePacketDisplay(); LK.getSound('enemySteal').play(); if (packetHealth <= 0) { LK.showGameOver(); } self.destroy(); birds.splice(birds.indexOf(self), 1); return; } } else { // Flip scaleX based on movement direction if (dx > 0) { birdGraphics.scaleX = 1; // Face right } else if (dx < 0) { birdGraphics.scaleX = -1; // Face left } self.x += dx / distance * self.speed * gameSpeedMultiplier; self.y += dy / distance * self.speed * gameSpeedMultiplier; } } }; self.takeDamage = function (damage) { self.health -= damage; self.updateHealthBar(); if (self.health <= 0) { // Bird defeated - give reward gameGold += self.reward; updateGoldDisplay(); LK.getSound('mouseHit').play(); self.destroy(); birds.splice(birds.indexOf(self), 1); } }; return self; }); var Dog = Container.expand(function () { var self = Container.call(this); var dogGraphics = self.attachAsset('dog', { anchorX: 0.5, anchorY: 0.5 }); self.health = 400; self.maxHealth = 400; self.speed = 1.2 + Math.random() * 0.8; // Slower than most enemies self.pathIndex = 0; self.reward = 50; // High reward // Create health bar components var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBarBg.x = 0; healthBarBg.y = -70; var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5 }); healthBarFill.x = -35; healthBarFill.y = -70; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.update = function () { if (self.pathIndex < gamePath.length) { var target = gamePath[self.pathIndex]; var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { self.pathIndex++; if (self.pathIndex >= gamePath.length) { // Dog reached the end - damage packet (20% of current health) packetHealth -= Math.floor(packetHealth * 0.20); updatePacketDisplay(); LK.getSound('enemySteal').play(); if (packetHealth <= 0) { LK.showGameOver(); } self.destroy(); dogs.splice(dogs.indexOf(self), 1); return; } } else { // Flip scaleX based on movement direction if (dx > 0) { dogGraphics.scaleX = 1; // Face right } else if (dx < 0) { dogGraphics.scaleX = -1; // Face left } self.x += dx / distance * self.speed * gameSpeedMultiplier; self.y += dy / distance * self.speed * gameSpeedMultiplier; } } }; self.takeDamage = function (damage) { self.health -= damage; self.updateHealthBar(); if (self.health <= 0) { // Dog defeated - give reward gameGold += self.reward; updateGoldDisplay(); LK.getSound('mouseHit').play(); self.destroy(); dogs.splice(dogs.indexOf(self), 1); } }; return self; }); var Hare = Container.expand(function () { var self = Container.call(this); var hareGraphics = self.attachAsset('hare', { anchorX: 0.5, anchorY: 0.5 }); self.health = 300; self.maxHealth = 300; self.speed = 2.0 + Math.random() * 1.0; // Faster than rats self.pathIndex = 0; self.reward = 40; // Higher reward than rats // Create health bar components var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBarBg.x = 0; healthBarBg.y = -65; var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5 }); healthBarFill.x = -35; healthBarFill.y = -65; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.update = function () { if (self.pathIndex < gamePath.length) { var target = gamePath[self.pathIndex]; var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { self.pathIndex++; if (self.pathIndex >= gamePath.length) { // Hare reached the end - damage packet (15% of original damage) packetHealth -= Math.floor(packetHealth * 0.15); // 15% of current packet health updatePacketDisplay(); LK.getSound('enemySteal').play(); if (packetHealth <= 0) { LK.showGameOver(); } self.destroy(); hares.splice(hares.indexOf(self), 1); return; } } else { // Flip scaleX based on movement direction like cats if (dx > 0) { hareGraphics.scaleX = 1; // Face right } else if (dx < 0) { hareGraphics.scaleX = -1; // Face left } self.x += dx / distance * self.speed * gameSpeedMultiplier; self.y += dy / distance * self.speed * gameSpeedMultiplier; } } }; self.takeDamage = function (damage) { self.health -= damage; self.updateHealthBar(); if (self.health <= 0) { // Hare defeated - give reward gameGold += self.reward; updateGoldDisplay(); LK.getSound('mouseHit').play(); self.destroy(); hares.splice(hares.indexOf(self), 1); } }; return self; }); var Mouse = Container.expand(function () { var self = Container.call(this); var mouseGraphics = self.attachAsset('mouse', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.maxHealth = 100; self.speed = 1.5 + Math.random() * 1.5; // Random speed between 1.5 and 3 self.pathIndex = 0; self.reward = 10; // Create health bar components var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBarBg.x = 0; healthBarBg.y = -50; var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5 }); healthBarFill.x = -35; healthBarFill.y = -50; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.update = function () { if (self.pathIndex < gamePath.length) { var target = gamePath[self.pathIndex]; // Add random wandering to target position for more chaotic movement var randomOffsetX = (Math.random() - 0.5) * 80; var randomOffsetY = (Math.random() - 0.5) * 80; var dx = target.x + randomOffsetX - self.x; var dy = target.y + randomOffsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 15 + Math.random() * 10) { self.pathIndex++; if (self.pathIndex >= gamePath.length) { // Mouse reached the end - damage packet (5% of original damage) packetHealth -= 5; // Changed to 5 damage (5% of original 100) updatePacketDisplay(); LK.getSound('enemySteal').play(); if (packetHealth <= 0) { LK.showGameOver(); } self.destroy(); mice.splice(mice.indexOf(self), 1); return; } } else { // Flip scaleX based on movement direction like cats if (dx > 0) { mouseGraphics.scaleX = 1; // Face right } else if (dx < 0) { mouseGraphics.scaleX = -1; // Face left } // Add slight random jitter to movement for more chaotic behavior var jitterX = (Math.random() - 0.5) * 2; var jitterY = (Math.random() - 0.5) * 2; self.x += dx / distance * self.speed * gameSpeedMultiplier + jitterX; self.y += dy / distance * self.speed * gameSpeedMultiplier + jitterY; } } }; self.takeDamage = function (damage) { self.health -= damage; self.updateHealthBar(); if (self.health <= 0) { // Mouse defeated - give reward gameGold += self.reward; updateGoldDisplay(); LK.getSound('mouseHit').play(); self.destroy(); mice.splice(mice.indexOf(self), 1); } }; return self; }); var Rat = Container.expand(function () { var self = Container.call(this); var ratGraphics = self.attachAsset('rat', { anchorX: 0.5, anchorY: 0.5 }); self.health = 200; self.maxHealth = 200; self.speed = 1.0 + Math.random() * 1.0; // Slower than before, similar to mice speed self.pathIndex = 0; self.reward = 25; // Higher reward // Create health bar components var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); healthBarBg.x = 0; healthBarBg.y = -60; var healthBarFill = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5 }); healthBarFill.x = -35; healthBarFill.y = -60; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; healthBarFill.scaleX = healthPercent; // Change color based on health if (healthPercent > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } }; self.update = function () { if (self.pathIndex < gamePath.length) { var target = gamePath[self.pathIndex]; // Add random wandering behavior for more unpredictable movement var randomOffsetX = (Math.random() - 0.5) * 100; var randomOffsetY = (Math.random() - 0.5) * 100; var dx = target.x + randomOffsetX - self.x; var dy = target.y + randomOffsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 20 + Math.random() * 15) { self.pathIndex++; if (self.pathIndex >= gamePath.length) { // Rat reached the end - damage packet (10% of original damage) packetHealth -= 10; // Changed to 10 damage (10% of original 100) updatePacketDisplay(); LK.getSound('enemySteal').play(); if (packetHealth <= 0) { LK.showGameOver(); } self.destroy(); rats.splice(rats.indexOf(self), 1); return; } } else { // Flip scaleX based on movement direction like cats if (dx > 0) { ratGraphics.scaleX = 1; // Face right } else if (dx < 0) { ratGraphics.scaleX = -1; // Face left } // Add random movement variation for more chaotic behavior var jitterX = (Math.random() - 0.5) * 3; var jitterY = (Math.random() - 0.5) * 3; self.x += dx / distance * self.speed * gameSpeedMultiplier + jitterX; self.y += dy / distance * self.speed * gameSpeedMultiplier + jitterY; } } }; self.takeDamage = function (damage) { self.health -= damage; self.updateHealthBar(); if (self.health <= 0) { // Rat defeated - give reward gameGold += self.reward; updateGoldDisplay(); LK.getSound('mouseHit').play(); self.destroy(); rats.splice(rats.indexOf(self), 1); } }; return self; }); var Scratch = Container.expand(function (x, y) { var self = Container.call(this); self.attachAsset('scratch', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.rotation = Math.random() * Math.PI * 2; self.alpha = 1; var startScale = Math.random() * 0.5 + 0.8; self.scale.set(startScale); tween(self, { alpha: 0, scaleX: self.scale.x * 1.5, scaleY: self.scale.y * 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { if (self.parent) { self.destroy(); } } }); return self; }); var Tower = Container.expand(function (type) { var self = Container.call(this); var towerGraphics; self.type = type || 'tired'; self.range = 450; // Increased base range for farther attacks self.damage = 18; // Reduced from 25 self.fireRate = 30; // frames between shots (0.5 seconds at 60fps) self.lastShot = 0; if (self.type === 'tired') { towerGraphics = self.attachAsset('tiredCat', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 20; // Increased from 19 to make game winnable self.cost = 30; self.fireRate = 60; // Slower attack rate for tired cats self.range = 450; // Increased range for farther attacks } else if (self.type === 'normal') { towerGraphics = self.attachAsset('normalCat', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 55; // Increased from 45 to make normal cats even stronger self.range = 500; // Increased range for farther attacks self.cost = 150; self.fireRate = 20; // Reduced from 30 to make normal cats faster } else if (self.type === 'strong') { towerGraphics = self.attachAsset('strongCat', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 35; // Reduced from 50 self.range = 550; // Increased range for farther attacks self.cost = 150; self.fireRate = 30; } else if (self.type === 'strongest') { towerGraphics = self.attachAsset('strongestCat', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 70; // Reduced from 100 self.range = 600; // Increased range for farther attacks self.fireRate = 30; self.cost = 250; } else if (self.type === 'wild') { towerGraphics = self.attachAsset('wildCat', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 50; self.range = 580; // Increased range for farther attacks self.fireRate = 20; // Faster than other cats self.cost = 350; } else if (self.type === 'tiger') { towerGraphics = self.attachAsset('tiger', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 80; self.range = 650; // Increased range for farther attacks self.fireRate = 15; // Very fast attack rate self.cost = 500; } self.update = function () { // Don't allow towers being dragged to attack (prevents cheating) if (isDragging && self === draggedTower) { return; } self.lastShot += gameSpeedMultiplier; var target = self.findTarget(); if (target) { var currentFireRate = self.fireRate; // Normal cat attacks rats extremely fast but mice slowly if (self.type === 'normal') { if (target.constructor.name === 'Rat') { currentFireRate = 2; // Extremely fast against rats for superior effectiveness } else { currentFireRate = 60; // Slow attack rate against mice and other enemies } } // Wild cat attacks hares and birds extremely fast but other enemies slowly if (self.type === 'wild') { if (target.constructor.name === 'Hare' || target.constructor.name === 'Bird') { currentFireRate = 1; // Ultra fast against hares and birds for superior effectiveness } else { currentFireRate = 60; // Slow attack rate against mice and other enemies } } // Tiger attacks dogs much faster than other enemies if (self.type === 'tiger') { if (target.constructor.name === 'Dog') { currentFireRate = 5; // Much faster against dogs } else { currentFireRate = 20; // Normal fast rate against other enemies } } if (self.lastShot >= currentFireRate) { self.shoot(target); self.lastShot = 0; } } }; self.findTarget = function () { var closestEnemy = null; var closestDistance = self.range; // Prioritize targets based on tower type // Wild cats prioritize birds and hares if (self.type === 'wild') { // Check birds first for (var i = 0; i < birds.length; i++) { var bird = birds[i]; var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = bird; closestDistance = distance; } } // Check hares second for (var i = 0; i < hares.length; i++) { var hare = hares[i]; var distance = Math.sqrt(Math.pow(hare.x - self.x, 2) + Math.pow(hare.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = hare; closestDistance = distance; } } } else if (self.type === 'tiger') { // Tigers prioritize dogs for (var i = 0; i < dogs.length; i++) { var dog = dogs[i]; var distance = Math.sqrt(Math.pow(dog.x - self.x, 2) + Math.pow(dog.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = dog; closestDistance = distance; } } } // Check all enemy types for remaining targeting // Check mice for (var i = 0; i < mice.length; i++) { var mouse = mice[i]; var distance = Math.sqrt(Math.pow(mouse.x - self.x, 2) + Math.pow(mouse.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = mouse; closestDistance = distance; } } // Check rats for (var i = 0; i < rats.length; i++) { var rat = rats[i]; var distance = Math.sqrt(Math.pow(rat.x - self.x, 2) + Math.pow(rat.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = rat; closestDistance = distance; } } // Check hares for (var i = 0; i < hares.length; i++) { var hare = hares[i]; var distance = Math.sqrt(Math.pow(hare.x - self.x, 2) + Math.pow(hare.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = hare; closestDistance = distance; } } // Check birds for (var i = 0; i < birds.length; i++) { var bird = birds[i]; var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = bird; closestDistance = distance; } } // Check dogs for (var i = 0; i < dogs.length; i++) { var dog = dogs[i]; var distance = Math.sqrt(Math.pow(dog.x - self.x, 2) + Math.pow(dog.y - self.y, 2)); if (distance < closestDistance) { closestEnemy = dog; closestDistance = distance; } } return closestEnemy; }; self.shoot = function (target) { // Flip scaleX based on enemy position when shooting var dx = target.x - self.x; var dy = target.y - self.y; // Flip horizontally based on enemy position (face the enemy directly) var originalScaleX = 1; if (target.x > self.x) { originalScaleX = 1; // Face right toward enemy towerGraphics.scaleX = 1; } else if (target.x < self.x) { originalScaleX = -1; // Face left toward enemy towerGraphics.scaleX = -1; } // Calculate damage multiplier var damageMultiplier = 1; // Wild cats are excellent against birds and hares if (self.type === 'wild' && (target.constructor.name === 'Hare' || target.constructor.name === 'Bird')) { damageMultiplier = 2.0; // 100% bonus damage // Predict target's next position for better accuracy var predictedX = target.x + (dx > 0 ? target.speed * 3 : -target.speed * 3); var predictedY = target.y + (dy > 0 ? target.speed * 3 : -target.speed * 3); // Apply damage with slight delay for better visual effect LK.setTimeout(function () { if (target && target.parent) { target.takeDamage(self.damage * damageMultiplier); } }, 50); } else if (self.type === 'tiger' && target.constructor.name === 'Dog') { // Tigers are extremely effective against dogs damageMultiplier = 2.5; // 150% bonus damage target.takeDamage(self.damage * damageMultiplier); } else if (self.type === 'tiger') { // Tigers attack other enemies well but not as good as dogs damageMultiplier = 1.3; // 30% bonus damage for all other enemies target.takeDamage(self.damage * damageMultiplier); } else { // Normal damage for other combinations target.takeDamage(self.damage); } LK.getSound('shoot').play(); LK.getSound('hit').play(); // Create multiple scratches for visual effect for (var i = 0; i < 3; i++) { var scratchEffect = new Scratch(target.x + (Math.random() - 0.5) * 50, target.y + (Math.random() - 0.5) * 50); game.addChild(scratchEffect); } // Smooth recoil animation - reduced intensity for tigers to prevent trembling var recoilIntensity = self.type === 'tiger' ? 0.95 : 0.8; var recoilDuration = self.type === 'tiger' ? 150 : 100; tween(towerGraphics, { scaleX: originalScaleX * recoilIntensity, scaleY: recoilIntensity }, { duration: recoilDuration, easing: tween.easeOut, onFinish: function onFinish() { tween(towerGraphics, { scaleX: originalScaleX, scaleY: 1 }, { duration: recoilDuration, easing: tween.easeInOut }); } }); }; self.getSellPrice = function () { return Math.floor(self.cost * 0.7); // 70% of original cost }; self.down = function (x, y, obj) { if (!gameStarted && !isDragging) { // Allow repositioning before game starts if (selectedTower) { selectedTower.tint = 0xffffff; // Reset previous selection tint } selectedTower = self; self.tint = 0x00ffff; // Cyan tint to show selection isDragging = true; draggedTower = self; // Play pickup sound for repositioning LK.getSound('pickupDefender').play(); // No need to free placement spots since we're using free positioning } else if (!isDragging) { showSellUI(self); } }; return self; }); /**** * Initialize Game ****/ // Game state variables var game = new LK.Game({ backgroundColor: 0x228B22 }); /**** * Game Code ****/ // Add background image var background = game.addChild(LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 })); background.x = 1024; // Center horizontally (2048/2) background.y = 1366; // Center vertically (2732/2) // Game assets // Import tween plugin for animations // Game state variables var mice = []; var rats = []; var hares = []; var birds = []; var dogs = []; var towers = []; var gameGold = 120; var packetHealth = 100; var waveNumber = 1; var miceSpawned = 0; var ratsSpawned = 0; var haresSpawned = 0; var birdsSpawned = 0; var dogsSpawned = 0; var maxMicePerWave = 15; var maxRatsPerWave = 0; var maxHaresPerWave = 0; var maxBirdsPerWave = 0; var maxDogsPerWave = 0; var spawnTimer = 0; var ratSpawnTimer = 0; var hareSpawnTimer = 0; var birdSpawnTimer = 0; var dogSpawnTimer = 0; var spawnRate = 90; // frames between spawns (much faster spawning for harder waves) var ratSpawnRate = 100; // frames between rat spawns (faster) var hareSpawnRate = 120; // frames between hare spawns var birdSpawnRate = 80; // frames between bird spawns (faster due to speed) var dogSpawnRate = 140; // frames between dog spawns (slower) var gameStarted = false; var gameStartTimer = 0; var isPaused = false; var pauseTimer = 0; var pauseText = null; var gameSpeedMultiplier = 1; // Normal speed = 1, Fast speed = 2 // Create path for mice - random zigzag movement with more randomization var gamePath = [{ x: 1024 + (Math.random() - 0.5) * 200, y: 50 + Math.random() * 100 }, { x: 600 + (Math.random() - 0.5) * 400, y: 300 + (Math.random() - 0.5) * 200 }, { x: 1400 + (Math.random() - 0.5) * 400, y: 600 + (Math.random() - 0.5) * 200 }, { x: 400 + (Math.random() - 0.5) * 300, y: 900 + (Math.random() - 0.5) * 200 }, { x: 1600 + (Math.random() - 0.5) * 300, y: 1200 + (Math.random() - 0.5) * 200 }, { x: 800 + (Math.random() - 0.5) * 400, y: 1500 + (Math.random() - 0.5) * 200 }, { x: 1200 + (Math.random() - 0.5) * 400, y: 1800 + (Math.random() - 0.5) * 200 }, { x: 500 + (Math.random() - 0.5) * 300, y: 2100 + (Math.random() - 0.5) * 200 }, { x: 1500 + (Math.random() - 0.5) * 300, y: 2400 + (Math.random() - 0.5) * 200 }, { x: 1024 + (Math.random() - 0.5) * 200, y: 2700 + Math.random() * 100 }]; // Draw path for (var i = 0; i < gamePath.length; i++) { var pathSegment = game.addChild(LK.getAsset('path', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })); pathSegment.x = gamePath[i].x; pathSegment.y = gamePath[i].y; } // Create packet of treats at the end var packet = game.addChild(LK.getAsset('packetTreats', { anchorX: 0.5, anchorY: 0.5 })); packet.x = gamePath[gamePath.length - 1].x; packet.y = gamePath[gamePath.length - 1].y - 200; // Create placement system - cats can be placed anywhere near the path var placementSpots = []; // Keep for compatibility but will be used differently var maxDistanceFromPath = 300; // Maximum distance cats can be placed from path // Helper function to check if a position is valid for tower placement function isValidPlacementPosition(x, y) { // Check if position is within game bounds if (x < 100 || x > 1948 || y < 100 || y > 2632) { return false; } // Check if position is too close to existing towers for (var i = 0; i < towers.length; i++) { var tower = towers[i]; var dx = tower.x - x; var dy = tower.y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { // Minimum distance between towers return false; } } return true; } // UI Elements var goldText = new Text2(' Gold: ' + gameGold, { size: 60, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); goldText.anchor.set(0, 0); goldText.x = 50; goldText.y = 50; LK.gui.topLeft.addChild(goldText); var healthText = new Text2('Packet Health: ' + packetHealth, { size: 60, fill: 0xFF0000, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); healthText.anchor.set(0.5, 0); healthText.x = 0; healthText.y = 50; LK.gui.top.addChild(healthText); var waveText = new Text2('Wave: ' + waveNumber, { size: 60, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); waveText.anchor.set(1, 0); waveText.x = 0; waveText.y = 50; LK.gui.topRight.addChild(waveText); // Create start button square var startButton = LK.getAsset('startButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3, alpha: 0 }); startButton.x = 0; startButton.y = 0; startButton.interactive = false; LK.gui.center.addChild(startButton); // Add tutorial images in front of start button var tutorialCat = LK.getAsset('tiredCat', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, alpha: 0 }); tutorialCat.x = -120; tutorialCat.y = -20; LK.gui.center.addChild(tutorialCat); // Add arrow image pointing from cat to mouse var tutorialArrow = new Text2('→', { size: 180, fill: 0xFFFF00, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); tutorialArrow.anchor.set(0.5, 0.5); tutorialArrow.x = 0; tutorialArrow.y = -20; tutorialArrow.alpha = 0; LK.gui.center.addChild(tutorialArrow); // Add mouse image var tutorialMouse = LK.getAsset('mouse', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, alpha: 0 }); tutorialMouse.x = 120; tutorialMouse.y = -20; LK.gui.center.addChild(tutorialMouse); // Add wave 5 waiting state var waitingForWave5Start = false; // Add click handler to start button startButton.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; // Play start sound LK.getSound('start').play(); // Smoothly fade out start button and tutorial elements together tween(startButton, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); startButton.interactive = false; // Smoothly fade out tutorial images at the same time tween(tutorialCat, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); tween(tutorialArrow, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); tween(tutorialMouse, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); } else if (waitingForWave5Start) { // Wave 5 start button clicked waitingForWave5Start = false; isPaused = false; pauseTimer = 0; // Play start sound LK.getSound('start').play(); // Smoothly fade out start button and tutorial elements together tween(startButton, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); startButton.interactive = false; // Smoothly fade out tutorial images at the same time tween(tutorialCat, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); tween(tutorialArrow, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); tween(tutorialMouse, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); } }; // Show start button after 10 seconds LK.setTimeout(function () { if (!gameStarted) { tween(startButton, { alpha: 1 }, { duration: 500 }); // Show tutorial images tween(tutorialCat, { alpha: 1 }, { duration: 500 }); tween(tutorialArrow, { alpha: 1 }, { duration: 500, onFinish: function onFinish() { // Add pulsing effect to make arrow more visible tween(tutorialArrow, { alpha: 0.3 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(tutorialArrow, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); } }); } }); tween(tutorialMouse, { alpha: 1 }, { duration: 500 }); startButton.interactive = true; } }, 10000); // Tower selection UI var selectedTowerType = 'normal'; // Create bottom menu background var menuBackground = LK.getAsset('placementGrid', { anchorX: 0.5, anchorY: 1, scaleX: 20, scaleY: 2, alpha: 0.8 }); menuBackground.x = 0; menuBackground.y = 0; LK.gui.bottom.addChild(menuBackground); // Create tired cat button with asset var tiredCatButton = LK.getAsset('tiredCat', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); tiredCatButton.x = -200; tiredCatButton.y = -80; LK.gui.bottom.addChild(tiredCatButton); // Create price text for tired cat var tiredCatPrice = new Text2('30g', { size: 40, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); tiredCatPrice.anchor.set(0.5, 0); tiredCatPrice.x = -200; tiredCatPrice.y = -40; LK.gui.bottom.addChild(tiredCatPrice); // Create normal cat button with asset var normalCatButton = LK.getAsset('normalCat', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); normalCatButton.x = 200; normalCatButton.y = -80; LK.gui.bottom.addChild(normalCatButton); // Create price text for normal cat var normalCatPrice = new Text2('150g', { size: 40, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); normalCatPrice.anchor.set(0.5, 0); normalCatPrice.x = 200; normalCatPrice.y = -40; LK.gui.bottom.addChild(normalCatPrice); // Create wild cat button with asset var wildCatButton = LK.getAsset('wildCat', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7 }); wildCatButton.x = 400; wildCatButton.y = -80; LK.gui.bottom.addChild(wildCatButton); // Create price text for wild cat var wildCatPrice = new Text2('350g', { size: 40, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); wildCatPrice.anchor.set(0.5, 0); wildCatPrice.x = 400; wildCatPrice.y = -40; LK.gui.bottom.addChild(wildCatPrice); // Create tiger button with asset var tigerButton = LK.getAsset('tiger', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); tigerButton.x = 600; tigerButton.y = -80; LK.gui.bottom.addChild(tigerButton); // Create price text for tiger var tigerPrice = new Text2('500g', { size: 40, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); tigerPrice.anchor.set(0.5, 0); tigerPrice.x = 600; tigerPrice.y = -40; LK.gui.bottom.addChild(tigerPrice); // Create speed control buttons var fastForwardButton = new Text2('⏩', { size: 80, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); fastForwardButton.anchor.set(1, 0); fastForwardButton.x = -20; fastForwardButton.y = 120; LK.gui.topRight.addChild(fastForwardButton); var normalSpeedButton = new Text2('▶️', { size: 80, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); normalSpeedButton.anchor.set(1, 0); normalSpeedButton.x = -20; normalSpeedButton.y = 220; fastForwardButton.alpha = 1; // Start opaque since fast speed is not selected normalSpeedButton.alpha = 0.5; // Start transparent since normal speed is selected LK.gui.topRight.addChild(normalSpeedButton); // Initialize button transparency updateTiredCatButtonAlpha(); updateNormalCatButtonAlpha(); updateWildCatButtonAlpha(); updateTigerButtonAlpha(); // Speed control button handlers fastForwardButton.down = function (x, y, obj) { gameSpeedMultiplier = 2; // Make fast button transparent and normal button opaque (clicked option is transparent) tween(fastForwardButton, { alpha: 0.5 }, { duration: 200 }); tween(normalSpeedButton, { alpha: 1 }, { duration: 200 }); }; normalSpeedButton.down = function (x, y, obj) { gameSpeedMultiplier = 1; // Make normal button transparent and fast button opaque (clicked option is transparent) tween(fastForwardButton, { alpha: 1 }, { duration: 200 }); tween(normalSpeedButton, { alpha: 0.5 }, { duration: 200 }); }; // Dragging variables var isDragging = false; var draggedTower = null; var dragOffset = { x: 0, y: 0 }; // Sell UI variables var sellUI = null; var sellUITower = null; // Tower selection for repositioning var selectedTower = null; function updateGoldDisplay() { goldText.setText(' Gold: ' + gameGold); updateTiredCatButtonAlpha(); updateNormalCatButtonAlpha(); updateWildCatButtonAlpha(); updateTigerButtonAlpha(); } function updatePacketDisplay() { healthText.setText('Packet Health: ' + packetHealth); } function updateWaveDisplay() { waveText.setText('Wave: ' + waveNumber); } function showSellUI(tower) { // Remove existing sell UI if (sellUI) { sellUI.destroy(); sellUI = null; } sellUITower = tower; sellUI = new Container(); game.addChild(sellUI); // Position sell UI above tower sellUI.x = tower.x; sellUI.y = tower.y - 100; // Create sell button var sellButton = sellUI.attachAsset('sellButton', { anchorX: 0.5, anchorY: 0.5 }); // Create sell price text var sellPrice = tower.getSellPrice(); var sellText = new Text2('SELL\n' + sellPrice + 'g', { size: 24, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", fontWeight: 'bold' }); sellText.anchor.set(0.5, 0.5); sellText.x = 0; sellText.y = 0; sellUI.addChild(sellText); // Sell button click handler sellButton.down = function (x, y, obj) { sellTower(sellUITower); }; // Auto-hide sell UI after 3 seconds LK.setTimeout(function () { if (sellUI) { sellUI.destroy(); sellUI = null; sellUITower = null; } }, 3000); } function sellTower(tower) { // Give back gold (70% of original cost) var sellPrice = tower.getSellPrice(); gameGold += sellPrice; updateGoldDisplay(); LK.getSound('mouseHit').play(); // No need to free placement spots since we're using free positioning // Remove tower from towers array var towerIndex = towers.indexOf(tower); if (towerIndex > -1) { towers.splice(towerIndex, 1); } // Destroy tower tower.destroy(); // Hide sell UI if (sellUI) { sellUI.destroy(); sellUI = null; sellUITower = null; } } // Tired cat button drag functionality tiredCatButton.down = function (x, y, obj) { if (gameGold >= 30) { // Hide sell UI when starting to drag if (sellUI) { sellUI.destroy(); sellUI = null; sellUITower = null; } isDragging = true; selectedTowerType = 'tired'; // Create dragged tower preview draggedTower = new Tower('tired'); draggedTower.alpha = 0.8; draggedTower.scaleX = 1.2; draggedTower.scaleY = 1.2; game.addChild(draggedTower); // Convert button position to game coordinates var buttonPos = game.toLocal(tiredCatButton.parent.toGlobal(tiredCatButton.position)); draggedTower.x = buttonPos.x; draggedTower.y = buttonPos.y; dragOffset.x = x; dragOffset.y = y; // Play pickup sound LK.getSound('pickupDefender').play(); // Button feedback tween(tiredCatButton, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(tiredCatButton, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); } }); } }; function updateTiredCatButtonAlpha() { if (gameGold >= 30) { tiredCatButton.alpha = 1; tiredCatPrice.alpha = 1; } else { tiredCatButton.alpha = 0.5; tiredCatPrice.alpha = 0.5; } } // Add move handler to tired cat button for drag support tiredCatButton.move = function (x, y, obj) { if (isDragging && draggedTower && selectedTowerType === 'tired') { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Apply the offset from button position var buttonPos = game.toLocal(tiredCatButton.parent.toGlobal(tiredCatButton.position)); draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x); draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y); // Check if current position is valid for placement var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); // Tint tower based on placement validity if (isValidPosition) { draggedTower.tint = 0x00ff00; // Green tint for valid placement } else { draggedTower.tint = 0xff0000; // Red tint for invalid placement } } }; // Normal cat button drag functionality normalCatButton.down = function (x, y, obj) { if (gameGold >= 150) { // Hide sell UI when starting to drag if (sellUI) { sellUI.destroy(); sellUI = null; sellUITower = null; } isDragging = true; selectedTowerType = 'normal'; // Create dragged tower preview draggedTower = new Tower('normal'); draggedTower.alpha = 0.8; draggedTower.scaleX = 1.2; draggedTower.scaleY = 1.2; game.addChild(draggedTower); // Convert button position to game coordinates var buttonPos = game.toLocal(normalCatButton.parent.toGlobal(normalCatButton.position)); draggedTower.x = buttonPos.x; draggedTower.y = buttonPos.y; dragOffset.x = x; dragOffset.y = y; // Play pickup sound LK.getSound('pickupDefender').play(); // Button feedback tween(normalCatButton, { scaleX: 0.7, scaleY: 0.7 }, { duration: 100, onFinish: function onFinish() { tween(normalCatButton, { scaleX: 0.6, scaleY: 0.6 }, { duration: 100 }); } }); } }; function updateNormalCatButtonAlpha() { if (gameGold >= 150) { normalCatButton.alpha = 1; normalCatPrice.alpha = 1; } else { normalCatButton.alpha = 0.5; normalCatPrice.alpha = 0.5; } } // Add move handler to normal cat button for drag support normalCatButton.move = function (x, y, obj) { if (isDragging && draggedTower && selectedTowerType === 'normal') { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Apply the offset from button position var buttonPos = game.toLocal(normalCatButton.parent.toGlobal(normalCatButton.position)); draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x); draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y); // Check if current position is valid for placement var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); // Tint tower based on placement validity if (isValidPosition) { draggedTower.tint = 0x00ff00; // Green tint for valid placement } else { draggedTower.tint = 0xff0000; // Red tint for invalid placement } } }; // Wild cat button drag functionality wildCatButton.down = function (x, y, obj) { if (gameGold >= 350) { // Hide sell UI when starting to drag if (sellUI) { sellUI.destroy(); sellUI = null; sellUITower = null; } isDragging = true; selectedTowerType = 'wild'; // Create dragged tower preview draggedTower = new Tower('wild'); draggedTower.alpha = 0.8; draggedTower.scaleX = 1.2; draggedTower.scaleY = 1.2; game.addChild(draggedTower); // Convert button position to game coordinates var buttonPos = game.toLocal(wildCatButton.parent.toGlobal(wildCatButton.position)); draggedTower.x = buttonPos.x; draggedTower.y = buttonPos.y; dragOffset.x = x; dragOffset.y = y; // Play pickup sound LK.getSound('pickupDefender').play(); // Button feedback tween(wildCatButton, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100, onFinish: function onFinish() { tween(wildCatButton, { scaleX: 0.7, scaleY: 0.7 }, { duration: 100 }); } }); } }; function updateWildCatButtonAlpha() { if (gameGold >= 350) { wildCatButton.alpha = 1; wildCatPrice.alpha = 1; } else { wildCatButton.alpha = 0.5; wildCatPrice.alpha = 0.5; } } // Add move handler to wild cat button for drag support wildCatButton.move = function (x, y, obj) { if (isDragging && draggedTower && selectedTowerType === 'wild') { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Apply the offset from button position var buttonPos = game.toLocal(wildCatButton.parent.toGlobal(wildCatButton.position)); draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x); draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y); // Check if current position is valid for placement var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); // Tint tower based on placement validity if (isValidPosition) { draggedTower.tint = 0x00ff00; // Green tint for valid placement } else { draggedTower.tint = 0xff0000; // Red tint for invalid placement } } }; // Tiger button drag functionality tigerButton.down = function (x, y, obj) { if (gameGold >= 500) { // Hide sell UI when starting to drag if (sellUI) { sellUI.destroy(); sellUI = null; sellUITower = null; } isDragging = true; selectedTowerType = 'tiger'; // Create dragged tower preview draggedTower = new Tower('tiger'); draggedTower.alpha = 0.8; draggedTower.scaleX = 1.2; draggedTower.scaleY = 1.2; game.addChild(draggedTower); // Convert button position to game coordinates var buttonPos = game.toLocal(tigerButton.parent.toGlobal(tigerButton.position)); draggedTower.x = buttonPos.x; draggedTower.y = buttonPos.y; dragOffset.x = x; dragOffset.y = y; // Play pickup sound LK.getSound('pickupDefender').play(); // Button feedback tween(tigerButton, { scaleX: 0.6, scaleY: 0.6 }, { duration: 100, onFinish: function onFinish() { tween(tigerButton, { scaleX: 0.5, scaleY: 0.5 }, { duration: 100 }); } }); } }; function updateTigerButtonAlpha() { if (gameGold >= 500) { tigerButton.alpha = 1; tigerPrice.alpha = 1; } else { tigerButton.alpha = 0.5; tigerPrice.alpha = 0.5; } } // Add move handler to tiger button for drag support tigerButton.move = function (x, y, obj) { if (isDragging && draggedTower && selectedTowerType === 'tiger') { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Apply the offset from button position var buttonPos = game.toLocal(tigerButton.parent.toGlobal(tigerButton.position)); draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x); draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y); // Check if current position is valid for placement var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); // Tint tower based on placement validity if (isValidPosition) { draggedTower.tint = 0x00ff00; // Green tint for valid placement } else { draggedTower.tint = 0xff0000; // Red tint for invalid placement } } }; // Add up handlers to all tower buttons tiredCatButton.up = function (x, y, obj) { if (isDragging && draggedTower) { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Check if current position is valid for placement using dragged tower's position var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); var towerCost = draggedTower.cost; if (isValidPosition && gameGold >= towerCost) { // Place tower at dragged position (tower already positioned correctly) gameGold -= towerCost; updateGoldDisplay(); towers.push(draggedTower); draggedTower.alpha = 1; draggedTower.tint = 0xffffff; // Reset tint LK.getSound('placeDefender').play(); } else { // Remove dragged tower if placement failed draggedTower.destroy(); } // Reset dragging state isDragging = false; draggedTower = null; } }; normalCatButton.up = function (x, y, obj) { if (isDragging && draggedTower) { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Check if current position is valid for placement using dragged tower's position var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); var towerCost = draggedTower.cost; if (isValidPosition && gameGold >= towerCost) { // Place tower at dragged position (tower already positioned correctly) gameGold -= towerCost; updateGoldDisplay(); towers.push(draggedTower); draggedTower.alpha = 1; draggedTower.tint = 0xffffff; // Reset tint LK.getSound('placeDefender').play(); } else { // Remove dragged tower if placement failed draggedTower.destroy(); } // Reset dragging state isDragging = false; draggedTower = null; } }; wildCatButton.up = function (x, y, obj) { if (isDragging && draggedTower) { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Check if current position is valid for placement using dragged tower's position var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); var towerCost = draggedTower.cost; if (isValidPosition && gameGold >= towerCost) { // Place tower at dragged position (tower already positioned correctly) gameGold -= towerCost; updateGoldDisplay(); towers.push(draggedTower); draggedTower.alpha = 1; draggedTower.tint = 0xffffff; // Reset tint LK.getSound('placeDefender').play(); } else { // Remove dragged tower if placement failed draggedTower.destroy(); } // Reset dragging state isDragging = false; draggedTower = null; } }; tigerButton.up = function (x, y, obj) { if (isDragging && draggedTower) { var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({ x: x, y: y })) : { x: x, y: y }; // Check if current position is valid for placement using dragged tower's position var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y); var towerCost = draggedTower.cost; if (isValidPosition && gameGold >= towerCost) { // Place tower at dragged position (tower already positioned correctly) gameGold -= towerCost; updateGoldDisplay(); towers.push(draggedTower); draggedTower.alpha = 1; draggedTower.tint = 0xffffff; // Reset tint LK.getSound('placeDefender').play(); } else { // Remove dragged tower if placement failed draggedTower.destroy(); } // Reset dragging state isDragging = false; draggedTower = null; } }; // Game move handler for dragging game.move = function (x, y, obj) { if (isDragging && draggedTower) { draggedTower.x = x; draggedTower.y = y; // Check if current position is valid for placement var isValidPosition = isValidPlacementPosition(x, y); // Tint tower based on placement validity if (isValidPosition) { draggedTower.tint = 0x00ff00; // Green tint for valid placement } else if (selectedTower === draggedTower) { draggedTower.tint = 0x00ffff; // Keep cyan tint for selected tower being repositioned } else { draggedTower.tint = 0xff0000; // Red tint for invalid placement } } }; // Game up handler for tower placement game.up = function (x, y, obj) { if (isDragging && draggedTower) { // Check if current position is valid for placement var isValidPosition = isValidPlacementPosition(x, y); // Check if this is a repositioning of an existing tower var isRepositioning = selectedTower === draggedTower; var towerCost = isRepositioning ? 0 : draggedTower.cost; if (isValidPosition && gameGold >= towerCost) { // Place or reposition tower at current position if (!isRepositioning) { gameGold -= towerCost; updateGoldDisplay(); towers.push(draggedTower); } // Keep tower at current dragged position draggedTower.alpha = 1; draggedTower.tint = 0xffffff; // Reset tint if (!isRepositioning) { LK.getSound('placeDefender').play(); } } else if (isRepositioning) { // If repositioning failed, keep tower at its current position but remove selection draggedTower.tint = 0xffffff; } else { // Remove dragged tower if placement failed draggedTower.destroy(); } // Reset dragging and selection state isDragging = false; draggedTower = null; if (selectedTower) { selectedTower = null; } } }; // Start background music LK.playMusic('bgMusic'); game.update = function () { // Don't spawn mice until game starts (start button clicked) if (!gameStarted) { return; // Don't spawn mice until game starts } // Handle pause after wave 4 (changed from wave 3) or waiting for wave 5 start if (isPaused || waitingForWave5Start) { if (isPaused) { pauseTimer += gameSpeedMultiplier; if (pauseTimer >= 600) { // 10 seconds at 60fps isPaused = false; // Remove pause text if (pauseText) { pauseText.destroy(); pauseText = null; } // Show start button with normal cat, arrow, rat after wave 4 if (waveNumber === 5) { // Wave number increments before pause check // Set waiting state for wave 5 waitingForWave5Start = true; // Show start button startButton.alpha = 1; startButton.interactive = true; // Change tutorial images for wave 4 completion tutorialCat.destroy(); tutorialCat = LK.getAsset('normalCat', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, alpha: 1 }); tutorialCat.x = -120; tutorialCat.y = -20; LK.gui.center.addChild(tutorialCat); tutorialArrow.alpha = 1; // Change mouse to rat tutorialMouse.destroy(); tutorialMouse = LK.getAsset('rat', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, alpha: 1 }); tutorialMouse.x = 120; tutorialMouse.y = -20; LK.gui.center.addChild(tutorialMouse); } } } return; // Don't spawn enemies during pause or while waiting for wave 5 start } // Spawn mice with much more random timing variation spawnTimer += gameSpeedMultiplier; var randomSpawnDelay = Math.random() * 60 + Math.random() * 30; // Much more random delay if (spawnTimer >= spawnRate + randomSpawnDelay && miceSpawned < maxMicePerWave) { var mouse = new Mouse(); // Much more random spawn positions with larger variation mouse.x = gamePath[0].x + (Math.random() - 0.5) * 600 + Math.random() * 200; mouse.y = gamePath[0].y + (Math.random() - 0.5) * 400 + Math.random() * 150; // More random health variation (±40%) var baseHealth = 180 + waveNumber * 50; mouse.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.8; mouse.maxHealth = mouse.health; // Much more random speed variation (±50%) mouse.speed = mouse.speed * (0.5 + Math.random() * 1.0); mouse.updateHealthBar(); mice.push(mouse); game.addChild(mouse); miceSpawned++; spawnTimer = Math.random() * 20; // Random reset for more chaos } // Spawn rats (only after wave 5) with random variations if (waveNumber >= 5) { ratSpawnTimer += gameSpeedMultiplier; var randomRatDelay = Math.random() * 40; if (ratSpawnTimer >= ratSpawnRate + randomRatDelay && ratsSpawned < maxRatsPerWave) { var rat = new Rat(); rat.x = gamePath[0].x + (Math.random() - 0.5) * 500; rat.y = gamePath[0].y + (Math.random() - 0.5) * 250; // Random health variation (±25%) var baseHealth = 500 + waveNumber * 120; rat.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.5; rat.maxHealth = rat.health; // Random speed variation (±40%) rat.speed = rat.speed * (0.6 + Math.random() * 0.8); rat.updateHealthBar(); rats.push(rat); game.addChild(rat); ratsSpawned++; ratSpawnTimer = 0; } } // Spawn hares (only after wave 10) with random variations if (waveNumber >= 10) { hareSpawnTimer += gameSpeedMultiplier; var randomHareDelay = Math.random() * 50; if (hareSpawnTimer >= hareSpawnRate + randomHareDelay && haresSpawned < maxHaresPerWave) { var hare = new Hare(); hare.x = gamePath[0].x + (Math.random() - 0.5) * 600; hare.y = gamePath[0].y + (Math.random() - 0.5) * 300; // Random health variation (±30%) var baseHealth = 700 + waveNumber * 150; hare.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.6; hare.maxHealth = hare.health; // Random speed variation (±35%) hare.speed = hare.speed * (0.65 + Math.random() * 0.7); hare.updateHealthBar(); hares.push(hare); game.addChild(hare); haresSpawned++; hareSpawnTimer = 0; } } // Spawn birds (only after wave 15) with random variations if (waveNumber >= 15) { birdSpawnTimer += gameSpeedMultiplier; var randomBirdDelay = Math.random() * 35; if (birdSpawnTimer >= birdSpawnRate + randomBirdDelay && birdsSpawned < maxBirdsPerWave) { var bird = new Bird(); bird.x = gamePath[0].x + (Math.random() - 0.5) * 450; bird.y = gamePath[0].y + (Math.random() - 0.5) * 200; // Random health variation (±25%) var baseHealth = 400 + waveNumber * 100; bird.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.5; bird.maxHealth = bird.health; // Random speed variation (±30%) bird.speed = bird.speed * (0.7 + Math.random() * 0.6); bird.updateHealthBar(); birds.push(bird); game.addChild(bird); birdsSpawned++; birdSpawnTimer = 0; } } // Spawn dogs (only after wave 20) with random variations if (waveNumber >= 20) { dogSpawnTimer += gameSpeedMultiplier; var randomDogDelay = Math.random() * 60; if (dogSpawnTimer >= dogSpawnRate + randomDogDelay && dogsSpawned < maxDogsPerWave) { var dog = new Dog(); dog.x = gamePath[0].x + (Math.random() - 0.5) * 400; dog.y = gamePath[0].y + (Math.random() - 0.5) * 200; // Random health variation (±35%) var baseHealth = 800 + waveNumber * 200; dog.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.7; dog.maxHealth = dog.health; // Random speed variation (±25%) dog.speed = dog.speed * (0.75 + Math.random() * 0.5); dog.updateHealthBar(); dogs.push(dog); game.addChild(dog); dogsSpawned++; dogSpawnTimer = 0; } } // Check if wave is complete if (miceSpawned >= maxMicePerWave && ratsSpawned >= maxRatsPerWave && haresSpawned >= maxHaresPerWave && birdsSpawned >= maxBirdsPerWave && dogsSpawned >= maxDogsPerWave && mice.length === 0 && rats.length === 0 && hares.length === 0 && birds.length === 0 && dogs.length === 0) { // Check if wave 4, 14, or 19 just completed if (waveNumber === 4 || waveNumber === 14 || waveNumber === 19) { isPaused = true; pauseTimer = 0; } waveNumber++; miceSpawned = 0; ratsSpawned = 0; haresSpawned = 0; birdsSpawned = 0; dogsSpawned = 0; // Random variation in mice count per wave (±30%) var baseMiceIncrease = waveNumber <= 3 ? 2 : 1; maxMicePerWave += Math.floor(baseMiceIncrease * (0.7 + Math.random() * 0.6)); // Start spawning rats after wave 5 with random counts if (waveNumber >= 5) { var baseRats = Math.max(1, waveNumber - 4); maxRatsPerWave = Math.floor(baseRats * (0.8 + Math.random() * 0.4)); } // Start spawning birds after wave 15 with random counts if (waveNumber >= 15) { var baseBirds = Math.max(1, waveNumber - 14); maxBirdsPerWave = Math.floor(baseBirds * (0.7 + Math.random() * 0.6)); } // Start spawning hares after wave 10 with random counts if (waveNumber >= 10) { var baseHares = Math.max(1, waveNumber - 9); maxHaresPerWave = Math.floor(baseHares * (0.8 + Math.random() * 0.4)); } // Start spawning dogs after wave 20 with random counts if (waveNumber >= 20) { var baseDogs = Math.max(1, waveNumber - 19); maxDogsPerWave = Math.floor(baseDogs * (0.6 + Math.random() * 0.8)); } // Random spawn rate variations var baseSpawnDecrease = waveNumber <= 3 ? 8 : 12; spawnRate = Math.max(40, spawnRate - Math.floor(baseSpawnDecrease * (0.8 + Math.random() * 0.4))); ratSpawnRate = Math.max(90, ratSpawnRate - Math.floor(15 * (0.7 + Math.random() * 0.6))); hareSpawnRate = Math.max(100, hareSpawnRate - Math.floor(10 * (0.8 + Math.random() * 0.4))); birdSpawnRate = Math.max(70, birdSpawnRate - Math.floor(10 * (0.9 + Math.random() * 0.2))); dogSpawnRate = Math.max(120, dogSpawnRate - Math.floor(10 * (0.7 + Math.random() * 0.6))); updateWaveDisplay(); } // Update all game objects for (var i = mice.length - 1; i >= 0; i--) { if (mice[i].parent) { mice[i].update(); } } for (var i = rats.length - 1; i >= 0; i--) { if (rats[i].parent) { rats[i].update(); } } for (var i = hares.length - 1; i >= 0; i--) { if (hares[i].parent) { hares[i].update(); } } for (var i = birds.length - 1; i >= 0; i--) { if (birds[i].parent) { birds[i].update(); } } for (var i = dogs.length - 1; i >= 0; i--) { if (dogs[i].parent) { dogs[i].update(); } } for (var i = towers.length - 1; i >= 0; i--) { if (towers[i].parent) { towers[i].update(); // Check if tower is touching menu area (bottom 200px of screen) var isTouchingMenu = towers[i].y > 2532; // Menu area starts around y=2532 if (isTouchingMenu && !isDragging) { // Check if tower is very close to the path (excluding treatpacket position) var minDistanceFromPath = Infinity; for (var p = 0; p < gamePath.length - 1; p++) { var dx = gamePath[p].x - towers[i].x; var dy = gamePath[p].y - towers[i].y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistanceFromPath) { minDistanceFromPath = distance; } } // If not very close to path (more than 120px away), turn red if (minDistanceFromPath > 120) { towers[i].tint = 0xff0000; // Red tint } else { towers[i].tint = 0xffffff; // Reset to normal } } else if (!isDragging && towers[i] !== selectedTower) { // Reset tint if not touching menu and not being dragged/selected towers[i].tint = 0xffffff; } } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 250;
self.maxHealth = 250;
self.speed = 3.0 + Math.random() * 1.0; // Faster than other enemies
self.pathIndex = 0;
self.reward = 35; // Medium reward
// Create health bar components
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -55;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5
});
healthBarFill.x = -35;
healthBarFill.y = -55;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
if (self.pathIndex < gamePath.length) {
var target = gamePath[self.pathIndex];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
// Bird reached the end - damage packet (8% of current health)
packetHealth -= Math.floor(packetHealth * 0.08);
updatePacketDisplay();
LK.getSound('enemySteal').play();
if (packetHealth <= 0) {
LK.showGameOver();
}
self.destroy();
birds.splice(birds.indexOf(self), 1);
return;
}
} else {
// Flip scaleX based on movement direction
if (dx > 0) {
birdGraphics.scaleX = 1; // Face right
} else if (dx < 0) {
birdGraphics.scaleX = -1; // Face left
}
self.x += dx / distance * self.speed * gameSpeedMultiplier;
self.y += dy / distance * self.speed * gameSpeedMultiplier;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
// Bird defeated - give reward
gameGold += self.reward;
updateGoldDisplay();
LK.getSound('mouseHit').play();
self.destroy();
birds.splice(birds.indexOf(self), 1);
}
};
return self;
});
var Dog = Container.expand(function () {
var self = Container.call(this);
var dogGraphics = self.attachAsset('dog', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 400;
self.maxHealth = 400;
self.speed = 1.2 + Math.random() * 0.8; // Slower than most enemies
self.pathIndex = 0;
self.reward = 50; // High reward
// Create health bar components
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -70;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5
});
healthBarFill.x = -35;
healthBarFill.y = -70;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
if (self.pathIndex < gamePath.length) {
var target = gamePath[self.pathIndex];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
// Dog reached the end - damage packet (20% of current health)
packetHealth -= Math.floor(packetHealth * 0.20);
updatePacketDisplay();
LK.getSound('enemySteal').play();
if (packetHealth <= 0) {
LK.showGameOver();
}
self.destroy();
dogs.splice(dogs.indexOf(self), 1);
return;
}
} else {
// Flip scaleX based on movement direction
if (dx > 0) {
dogGraphics.scaleX = 1; // Face right
} else if (dx < 0) {
dogGraphics.scaleX = -1; // Face left
}
self.x += dx / distance * self.speed * gameSpeedMultiplier;
self.y += dy / distance * self.speed * gameSpeedMultiplier;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
// Dog defeated - give reward
gameGold += self.reward;
updateGoldDisplay();
LK.getSound('mouseHit').play();
self.destroy();
dogs.splice(dogs.indexOf(self), 1);
}
};
return self;
});
var Hare = Container.expand(function () {
var self = Container.call(this);
var hareGraphics = self.attachAsset('hare', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 300;
self.maxHealth = 300;
self.speed = 2.0 + Math.random() * 1.0; // Faster than rats
self.pathIndex = 0;
self.reward = 40; // Higher reward than rats
// Create health bar components
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -65;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5
});
healthBarFill.x = -35;
healthBarFill.y = -65;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
if (self.pathIndex < gamePath.length) {
var target = gamePath[self.pathIndex];
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
// Hare reached the end - damage packet (15% of original damage)
packetHealth -= Math.floor(packetHealth * 0.15); // 15% of current packet health
updatePacketDisplay();
LK.getSound('enemySteal').play();
if (packetHealth <= 0) {
LK.showGameOver();
}
self.destroy();
hares.splice(hares.indexOf(self), 1);
return;
}
} else {
// Flip scaleX based on movement direction like cats
if (dx > 0) {
hareGraphics.scaleX = 1; // Face right
} else if (dx < 0) {
hareGraphics.scaleX = -1; // Face left
}
self.x += dx / distance * self.speed * gameSpeedMultiplier;
self.y += dy / distance * self.speed * gameSpeedMultiplier;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
// Hare defeated - give reward
gameGold += self.reward;
updateGoldDisplay();
LK.getSound('mouseHit').play();
self.destroy();
hares.splice(hares.indexOf(self), 1);
}
};
return self;
});
var Mouse = Container.expand(function () {
var self = Container.call(this);
var mouseGraphics = self.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.speed = 1.5 + Math.random() * 1.5; // Random speed between 1.5 and 3
self.pathIndex = 0;
self.reward = 10;
// Create health bar components
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -50;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5
});
healthBarFill.x = -35;
healthBarFill.y = -50;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
if (self.pathIndex < gamePath.length) {
var target = gamePath[self.pathIndex];
// Add random wandering to target position for more chaotic movement
var randomOffsetX = (Math.random() - 0.5) * 80;
var randomOffsetY = (Math.random() - 0.5) * 80;
var dx = target.x + randomOffsetX - self.x;
var dy = target.y + randomOffsetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 15 + Math.random() * 10) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
// Mouse reached the end - damage packet (5% of original damage)
packetHealth -= 5; // Changed to 5 damage (5% of original 100)
updatePacketDisplay();
LK.getSound('enemySteal').play();
if (packetHealth <= 0) {
LK.showGameOver();
}
self.destroy();
mice.splice(mice.indexOf(self), 1);
return;
}
} else {
// Flip scaleX based on movement direction like cats
if (dx > 0) {
mouseGraphics.scaleX = 1; // Face right
} else if (dx < 0) {
mouseGraphics.scaleX = -1; // Face left
}
// Add slight random jitter to movement for more chaotic behavior
var jitterX = (Math.random() - 0.5) * 2;
var jitterY = (Math.random() - 0.5) * 2;
self.x += dx / distance * self.speed * gameSpeedMultiplier + jitterX;
self.y += dy / distance * self.speed * gameSpeedMultiplier + jitterY;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
// Mouse defeated - give reward
gameGold += self.reward;
updateGoldDisplay();
LK.getSound('mouseHit').play();
self.destroy();
mice.splice(mice.indexOf(self), 1);
}
};
return self;
});
var Rat = Container.expand(function () {
var self = Container.call(this);
var ratGraphics = self.attachAsset('rat', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 200;
self.maxHealth = 200;
self.speed = 1.0 + Math.random() * 1.0; // Slower than before, similar to mice speed
self.pathIndex = 0;
self.reward = 25; // Higher reward
// Create health bar components
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.x = 0;
healthBarBg.y = -60;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5
});
healthBarFill.x = -35;
healthBarFill.y = -60;
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
self.update = function () {
if (self.pathIndex < gamePath.length) {
var target = gamePath[self.pathIndex];
// Add random wandering behavior for more unpredictable movement
var randomOffsetX = (Math.random() - 0.5) * 100;
var randomOffsetY = (Math.random() - 0.5) * 100;
var dx = target.x + randomOffsetX - self.x;
var dy = target.y + randomOffsetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20 + Math.random() * 15) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length) {
// Rat reached the end - damage packet (10% of original damage)
packetHealth -= 10; // Changed to 10 damage (10% of original 100)
updatePacketDisplay();
LK.getSound('enemySteal').play();
if (packetHealth <= 0) {
LK.showGameOver();
}
self.destroy();
rats.splice(rats.indexOf(self), 1);
return;
}
} else {
// Flip scaleX based on movement direction like cats
if (dx > 0) {
ratGraphics.scaleX = 1; // Face right
} else if (dx < 0) {
ratGraphics.scaleX = -1; // Face left
}
// Add random movement variation for more chaotic behavior
var jitterX = (Math.random() - 0.5) * 3;
var jitterY = (Math.random() - 0.5) * 3;
self.x += dx / distance * self.speed * gameSpeedMultiplier + jitterX;
self.y += dy / distance * self.speed * gameSpeedMultiplier + jitterY;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
// Rat defeated - give reward
gameGold += self.reward;
updateGoldDisplay();
LK.getSound('mouseHit').play();
self.destroy();
rats.splice(rats.indexOf(self), 1);
}
};
return self;
});
var Scratch = Container.expand(function (x, y) {
var self = Container.call(this);
self.attachAsset('scratch', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.rotation = Math.random() * Math.PI * 2;
self.alpha = 1;
var startScale = Math.random() * 0.5 + 0.8;
self.scale.set(startScale);
tween(self, {
alpha: 0,
scaleX: self.scale.x * 1.5,
scaleY: self.scale.y * 1.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self.parent) {
self.destroy();
}
}
});
return self;
});
var Tower = Container.expand(function (type) {
var self = Container.call(this);
var towerGraphics;
self.type = type || 'tired';
self.range = 450; // Increased base range for farther attacks
self.damage = 18; // Reduced from 25
self.fireRate = 30; // frames between shots (0.5 seconds at 60fps)
self.lastShot = 0;
if (self.type === 'tired') {
towerGraphics = self.attachAsset('tiredCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 20; // Increased from 19 to make game winnable
self.cost = 30;
self.fireRate = 60; // Slower attack rate for tired cats
self.range = 450; // Increased range for farther attacks
} else if (self.type === 'normal') {
towerGraphics = self.attachAsset('normalCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 55; // Increased from 45 to make normal cats even stronger
self.range = 500; // Increased range for farther attacks
self.cost = 150;
self.fireRate = 20; // Reduced from 30 to make normal cats faster
} else if (self.type === 'strong') {
towerGraphics = self.attachAsset('strongCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 35; // Reduced from 50
self.range = 550; // Increased range for farther attacks
self.cost = 150;
self.fireRate = 30;
} else if (self.type === 'strongest') {
towerGraphics = self.attachAsset('strongestCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 70; // Reduced from 100
self.range = 600; // Increased range for farther attacks
self.fireRate = 30;
self.cost = 250;
} else if (self.type === 'wild') {
towerGraphics = self.attachAsset('wildCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 50;
self.range = 580; // Increased range for farther attacks
self.fireRate = 20; // Faster than other cats
self.cost = 350;
} else if (self.type === 'tiger') {
towerGraphics = self.attachAsset('tiger', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 80;
self.range = 650; // Increased range for farther attacks
self.fireRate = 15; // Very fast attack rate
self.cost = 500;
}
self.update = function () {
// Don't allow towers being dragged to attack (prevents cheating)
if (isDragging && self === draggedTower) {
return;
}
self.lastShot += gameSpeedMultiplier;
var target = self.findTarget();
if (target) {
var currentFireRate = self.fireRate;
// Normal cat attacks rats extremely fast but mice slowly
if (self.type === 'normal') {
if (target.constructor.name === 'Rat') {
currentFireRate = 2; // Extremely fast against rats for superior effectiveness
} else {
currentFireRate = 60; // Slow attack rate against mice and other enemies
}
}
// Wild cat attacks hares and birds extremely fast but other enemies slowly
if (self.type === 'wild') {
if (target.constructor.name === 'Hare' || target.constructor.name === 'Bird') {
currentFireRate = 1; // Ultra fast against hares and birds for superior effectiveness
} else {
currentFireRate = 60; // Slow attack rate against mice and other enemies
}
}
// Tiger attacks dogs much faster than other enemies
if (self.type === 'tiger') {
if (target.constructor.name === 'Dog') {
currentFireRate = 5; // Much faster against dogs
} else {
currentFireRate = 20; // Normal fast rate against other enemies
}
}
if (self.lastShot >= currentFireRate) {
self.shoot(target);
self.lastShot = 0;
}
}
};
self.findTarget = function () {
var closestEnemy = null;
var closestDistance = self.range;
// Prioritize targets based on tower type
// Wild cats prioritize birds and hares
if (self.type === 'wild') {
// Check birds first
for (var i = 0; i < birds.length; i++) {
var bird = birds[i];
var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = bird;
closestDistance = distance;
}
}
// Check hares second
for (var i = 0; i < hares.length; i++) {
var hare = hares[i];
var distance = Math.sqrt(Math.pow(hare.x - self.x, 2) + Math.pow(hare.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = hare;
closestDistance = distance;
}
}
} else if (self.type === 'tiger') {
// Tigers prioritize dogs
for (var i = 0; i < dogs.length; i++) {
var dog = dogs[i];
var distance = Math.sqrt(Math.pow(dog.x - self.x, 2) + Math.pow(dog.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = dog;
closestDistance = distance;
}
}
}
// Check all enemy types for remaining targeting
// Check mice
for (var i = 0; i < mice.length; i++) {
var mouse = mice[i];
var distance = Math.sqrt(Math.pow(mouse.x - self.x, 2) + Math.pow(mouse.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = mouse;
closestDistance = distance;
}
}
// Check rats
for (var i = 0; i < rats.length; i++) {
var rat = rats[i];
var distance = Math.sqrt(Math.pow(rat.x - self.x, 2) + Math.pow(rat.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = rat;
closestDistance = distance;
}
}
// Check hares
for (var i = 0; i < hares.length; i++) {
var hare = hares[i];
var distance = Math.sqrt(Math.pow(hare.x - self.x, 2) + Math.pow(hare.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = hare;
closestDistance = distance;
}
}
// Check birds
for (var i = 0; i < birds.length; i++) {
var bird = birds[i];
var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = bird;
closestDistance = distance;
}
}
// Check dogs
for (var i = 0; i < dogs.length; i++) {
var dog = dogs[i];
var distance = Math.sqrt(Math.pow(dog.x - self.x, 2) + Math.pow(dog.y - self.y, 2));
if (distance < closestDistance) {
closestEnemy = dog;
closestDistance = distance;
}
}
return closestEnemy;
};
self.shoot = function (target) {
// Flip scaleX based on enemy position when shooting
var dx = target.x - self.x;
var dy = target.y - self.y;
// Flip horizontally based on enemy position (face the enemy directly)
var originalScaleX = 1;
if (target.x > self.x) {
originalScaleX = 1; // Face right toward enemy
towerGraphics.scaleX = 1;
} else if (target.x < self.x) {
originalScaleX = -1; // Face left toward enemy
towerGraphics.scaleX = -1;
}
// Calculate damage multiplier
var damageMultiplier = 1;
// Wild cats are excellent against birds and hares
if (self.type === 'wild' && (target.constructor.name === 'Hare' || target.constructor.name === 'Bird')) {
damageMultiplier = 2.0; // 100% bonus damage
// Predict target's next position for better accuracy
var predictedX = target.x + (dx > 0 ? target.speed * 3 : -target.speed * 3);
var predictedY = target.y + (dy > 0 ? target.speed * 3 : -target.speed * 3);
// Apply damage with slight delay for better visual effect
LK.setTimeout(function () {
if (target && target.parent) {
target.takeDamage(self.damage * damageMultiplier);
}
}, 50);
} else if (self.type === 'tiger' && target.constructor.name === 'Dog') {
// Tigers are extremely effective against dogs
damageMultiplier = 2.5; // 150% bonus damage
target.takeDamage(self.damage * damageMultiplier);
} else if (self.type === 'tiger') {
// Tigers attack other enemies well but not as good as dogs
damageMultiplier = 1.3; // 30% bonus damage for all other enemies
target.takeDamage(self.damage * damageMultiplier);
} else {
// Normal damage for other combinations
target.takeDamage(self.damage);
}
LK.getSound('shoot').play();
LK.getSound('hit').play();
// Create multiple scratches for visual effect
for (var i = 0; i < 3; i++) {
var scratchEffect = new Scratch(target.x + (Math.random() - 0.5) * 50, target.y + (Math.random() - 0.5) * 50);
game.addChild(scratchEffect);
}
// Smooth recoil animation - reduced intensity for tigers to prevent trembling
var recoilIntensity = self.type === 'tiger' ? 0.95 : 0.8;
var recoilDuration = self.type === 'tiger' ? 150 : 100;
tween(towerGraphics, {
scaleX: originalScaleX * recoilIntensity,
scaleY: recoilIntensity
}, {
duration: recoilDuration,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(towerGraphics, {
scaleX: originalScaleX,
scaleY: 1
}, {
duration: recoilDuration,
easing: tween.easeInOut
});
}
});
};
self.getSellPrice = function () {
return Math.floor(self.cost * 0.7); // 70% of original cost
};
self.down = function (x, y, obj) {
if (!gameStarted && !isDragging) {
// Allow repositioning before game starts
if (selectedTower) {
selectedTower.tint = 0xffffff; // Reset previous selection tint
}
selectedTower = self;
self.tint = 0x00ffff; // Cyan tint to show selection
isDragging = true;
draggedTower = self;
// Play pickup sound for repositioning
LK.getSound('pickupDefender').play();
// No need to free placement spots since we're using free positioning
} else if (!isDragging) {
showSellUI(self);
}
};
return self;
});
/****
* Initialize Game
****/
// Game state variables
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Add background image
var background = game.addChild(LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
}));
background.x = 1024; // Center horizontally (2048/2)
background.y = 1366; // Center vertically (2732/2)
// Game assets
// Import tween plugin for animations
// Game state variables
var mice = [];
var rats = [];
var hares = [];
var birds = [];
var dogs = [];
var towers = [];
var gameGold = 120;
var packetHealth = 100;
var waveNumber = 1;
var miceSpawned = 0;
var ratsSpawned = 0;
var haresSpawned = 0;
var birdsSpawned = 0;
var dogsSpawned = 0;
var maxMicePerWave = 15;
var maxRatsPerWave = 0;
var maxHaresPerWave = 0;
var maxBirdsPerWave = 0;
var maxDogsPerWave = 0;
var spawnTimer = 0;
var ratSpawnTimer = 0;
var hareSpawnTimer = 0;
var birdSpawnTimer = 0;
var dogSpawnTimer = 0;
var spawnRate = 90; // frames between spawns (much faster spawning for harder waves)
var ratSpawnRate = 100; // frames between rat spawns (faster)
var hareSpawnRate = 120; // frames between hare spawns
var birdSpawnRate = 80; // frames between bird spawns (faster due to speed)
var dogSpawnRate = 140; // frames between dog spawns (slower)
var gameStarted = false;
var gameStartTimer = 0;
var isPaused = false;
var pauseTimer = 0;
var pauseText = null;
var gameSpeedMultiplier = 1; // Normal speed = 1, Fast speed = 2
// Create path for mice - random zigzag movement with more randomization
var gamePath = [{
x: 1024 + (Math.random() - 0.5) * 200,
y: 50 + Math.random() * 100
}, {
x: 600 + (Math.random() - 0.5) * 400,
y: 300 + (Math.random() - 0.5) * 200
}, {
x: 1400 + (Math.random() - 0.5) * 400,
y: 600 + (Math.random() - 0.5) * 200
}, {
x: 400 + (Math.random() - 0.5) * 300,
y: 900 + (Math.random() - 0.5) * 200
}, {
x: 1600 + (Math.random() - 0.5) * 300,
y: 1200 + (Math.random() - 0.5) * 200
}, {
x: 800 + (Math.random() - 0.5) * 400,
y: 1500 + (Math.random() - 0.5) * 200
}, {
x: 1200 + (Math.random() - 0.5) * 400,
y: 1800 + (Math.random() - 0.5) * 200
}, {
x: 500 + (Math.random() - 0.5) * 300,
y: 2100 + (Math.random() - 0.5) * 200
}, {
x: 1500 + (Math.random() - 0.5) * 300,
y: 2400 + (Math.random() - 0.5) * 200
}, {
x: 1024 + (Math.random() - 0.5) * 200,
y: 2700 + Math.random() * 100
}];
// Draw path
for (var i = 0; i < gamePath.length; i++) {
var pathSegment = game.addChild(LK.getAsset('path', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
}));
pathSegment.x = gamePath[i].x;
pathSegment.y = gamePath[i].y;
}
// Create packet of treats at the end
var packet = game.addChild(LK.getAsset('packetTreats', {
anchorX: 0.5,
anchorY: 0.5
}));
packet.x = gamePath[gamePath.length - 1].x;
packet.y = gamePath[gamePath.length - 1].y - 200;
// Create placement system - cats can be placed anywhere near the path
var placementSpots = []; // Keep for compatibility but will be used differently
var maxDistanceFromPath = 300; // Maximum distance cats can be placed from path
// Helper function to check if a position is valid for tower placement
function isValidPlacementPosition(x, y) {
// Check if position is within game bounds
if (x < 100 || x > 1948 || y < 100 || y > 2632) {
return false;
}
// Check if position is too close to existing towers
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
var dx = tower.x - x;
var dy = tower.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 120) {
// Minimum distance between towers
return false;
}
}
return true;
}
// UI Elements
var goldText = new Text2(' Gold: ' + gameGold, {
size: 60,
fill: 0xFFD700,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
goldText.anchor.set(0, 0);
goldText.x = 50;
goldText.y = 50;
LK.gui.topLeft.addChild(goldText);
var healthText = new Text2('Packet Health: ' + packetHealth, {
size: 60,
fill: 0xFF0000,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
healthText.anchor.set(0.5, 0);
healthText.x = 0;
healthText.y = 50;
LK.gui.top.addChild(healthText);
var waveText = new Text2('Wave: ' + waveNumber, {
size: 60,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
waveText.anchor.set(1, 0);
waveText.x = 0;
waveText.y = 50;
LK.gui.topRight.addChild(waveText);
// Create start button square
var startButton = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.3,
scaleY: 1.3,
alpha: 0
});
startButton.x = 0;
startButton.y = 0;
startButton.interactive = false;
LK.gui.center.addChild(startButton);
// Add tutorial images in front of start button
var tutorialCat = LK.getAsset('tiredCat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
alpha: 0
});
tutorialCat.x = -120;
tutorialCat.y = -20;
LK.gui.center.addChild(tutorialCat);
// Add arrow image pointing from cat to mouse
var tutorialArrow = new Text2('→', {
size: 180,
fill: 0xFFFF00,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
tutorialArrow.anchor.set(0.5, 0.5);
tutorialArrow.x = 0;
tutorialArrow.y = -20;
tutorialArrow.alpha = 0;
LK.gui.center.addChild(tutorialArrow);
// Add mouse image
var tutorialMouse = LK.getAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0
});
tutorialMouse.x = 120;
tutorialMouse.y = -20;
LK.gui.center.addChild(tutorialMouse);
// Add wave 5 waiting state
var waitingForWave5Start = false;
// Add click handler to start button
startButton.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
// Play start sound
LK.getSound('start').play();
// Smoothly fade out start button and tutorial elements together
tween(startButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
startButton.interactive = false;
// Smoothly fade out tutorial images at the same time
tween(tutorialCat, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
tween(tutorialArrow, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
tween(tutorialMouse, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
} else if (waitingForWave5Start) {
// Wave 5 start button clicked
waitingForWave5Start = false;
isPaused = false;
pauseTimer = 0;
// Play start sound
LK.getSound('start').play();
// Smoothly fade out start button and tutorial elements together
tween(startButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
startButton.interactive = false;
// Smoothly fade out tutorial images at the same time
tween(tutorialCat, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
tween(tutorialArrow, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
tween(tutorialMouse, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
};
// Show start button after 10 seconds
LK.setTimeout(function () {
if (!gameStarted) {
tween(startButton, {
alpha: 1
}, {
duration: 500
});
// Show tutorial images
tween(tutorialCat, {
alpha: 1
}, {
duration: 500
});
tween(tutorialArrow, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
// Add pulsing effect to make arrow more visible
tween(tutorialArrow, {
alpha: 0.3
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(tutorialArrow, {
alpha: 1
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
});
tween(tutorialMouse, {
alpha: 1
}, {
duration: 500
});
startButton.interactive = true;
}
}, 10000);
// Tower selection UI
var selectedTowerType = 'normal';
// Create bottom menu background
var menuBackground = LK.getAsset('placementGrid', {
anchorX: 0.5,
anchorY: 1,
scaleX: 20,
scaleY: 2,
alpha: 0.8
});
menuBackground.x = 0;
menuBackground.y = 0;
LK.gui.bottom.addChild(menuBackground);
// Create tired cat button with asset
var tiredCatButton = LK.getAsset('tiredCat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tiredCatButton.x = -200;
tiredCatButton.y = -80;
LK.gui.bottom.addChild(tiredCatButton);
// Create price text for tired cat
var tiredCatPrice = new Text2('30g', {
size: 40,
fill: 0xFFD700,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
tiredCatPrice.anchor.set(0.5, 0);
tiredCatPrice.x = -200;
tiredCatPrice.y = -40;
LK.gui.bottom.addChild(tiredCatPrice);
// Create normal cat button with asset
var normalCatButton = LK.getAsset('normalCat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
normalCatButton.x = 200;
normalCatButton.y = -80;
LK.gui.bottom.addChild(normalCatButton);
// Create price text for normal cat
var normalCatPrice = new Text2('150g', {
size: 40,
fill: 0xFFD700,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
normalCatPrice.anchor.set(0.5, 0);
normalCatPrice.x = 200;
normalCatPrice.y = -40;
LK.gui.bottom.addChild(normalCatPrice);
// Create wild cat button with asset
var wildCatButton = LK.getAsset('wildCat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
wildCatButton.x = 400;
wildCatButton.y = -80;
LK.gui.bottom.addChild(wildCatButton);
// Create price text for wild cat
var wildCatPrice = new Text2('350g', {
size: 40,
fill: 0xFFD700,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
wildCatPrice.anchor.set(0.5, 0);
wildCatPrice.x = 400;
wildCatPrice.y = -40;
LK.gui.bottom.addChild(wildCatPrice);
// Create tiger button with asset
var tigerButton = LK.getAsset('tiger', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
tigerButton.x = 600;
tigerButton.y = -80;
LK.gui.bottom.addChild(tigerButton);
// Create price text for tiger
var tigerPrice = new Text2('500g', {
size: 40,
fill: 0xFFD700,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
tigerPrice.anchor.set(0.5, 0);
tigerPrice.x = 600;
tigerPrice.y = -40;
LK.gui.bottom.addChild(tigerPrice);
// Create speed control buttons
var fastForwardButton = new Text2('⏩', {
size: 80,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
fastForwardButton.anchor.set(1, 0);
fastForwardButton.x = -20;
fastForwardButton.y = 120;
LK.gui.topRight.addChild(fastForwardButton);
var normalSpeedButton = new Text2('▶️', {
size: 80,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
normalSpeedButton.anchor.set(1, 0);
normalSpeedButton.x = -20;
normalSpeedButton.y = 220;
fastForwardButton.alpha = 1; // Start opaque since fast speed is not selected
normalSpeedButton.alpha = 0.5; // Start transparent since normal speed is selected
LK.gui.topRight.addChild(normalSpeedButton);
// Initialize button transparency
updateTiredCatButtonAlpha();
updateNormalCatButtonAlpha();
updateWildCatButtonAlpha();
updateTigerButtonAlpha();
// Speed control button handlers
fastForwardButton.down = function (x, y, obj) {
gameSpeedMultiplier = 2;
// Make fast button transparent and normal button opaque (clicked option is transparent)
tween(fastForwardButton, {
alpha: 0.5
}, {
duration: 200
});
tween(normalSpeedButton, {
alpha: 1
}, {
duration: 200
});
};
normalSpeedButton.down = function (x, y, obj) {
gameSpeedMultiplier = 1;
// Make normal button transparent and fast button opaque (clicked option is transparent)
tween(fastForwardButton, {
alpha: 1
}, {
duration: 200
});
tween(normalSpeedButton, {
alpha: 0.5
}, {
duration: 200
});
};
// Dragging variables
var isDragging = false;
var draggedTower = null;
var dragOffset = {
x: 0,
y: 0
};
// Sell UI variables
var sellUI = null;
var sellUITower = null;
// Tower selection for repositioning
var selectedTower = null;
function updateGoldDisplay() {
goldText.setText(' Gold: ' + gameGold);
updateTiredCatButtonAlpha();
updateNormalCatButtonAlpha();
updateWildCatButtonAlpha();
updateTigerButtonAlpha();
}
function updatePacketDisplay() {
healthText.setText('Packet Health: ' + packetHealth);
}
function updateWaveDisplay() {
waveText.setText('Wave: ' + waveNumber);
}
function showSellUI(tower) {
// Remove existing sell UI
if (sellUI) {
sellUI.destroy();
sellUI = null;
}
sellUITower = tower;
sellUI = new Container();
game.addChild(sellUI);
// Position sell UI above tower
sellUI.x = tower.x;
sellUI.y = tower.y - 100;
// Create sell button
var sellButton = sellUI.attachAsset('sellButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Create sell price text
var sellPrice = tower.getSellPrice();
var sellText = new Text2('SELL\n' + sellPrice + 'g', {
size: 24,
fill: 0xFFFFFF,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma",
fontWeight: 'bold'
});
sellText.anchor.set(0.5, 0.5);
sellText.x = 0;
sellText.y = 0;
sellUI.addChild(sellText);
// Sell button click handler
sellButton.down = function (x, y, obj) {
sellTower(sellUITower);
};
// Auto-hide sell UI after 3 seconds
LK.setTimeout(function () {
if (sellUI) {
sellUI.destroy();
sellUI = null;
sellUITower = null;
}
}, 3000);
}
function sellTower(tower) {
// Give back gold (70% of original cost)
var sellPrice = tower.getSellPrice();
gameGold += sellPrice;
updateGoldDisplay();
LK.getSound('mouseHit').play();
// No need to free placement spots since we're using free positioning
// Remove tower from towers array
var towerIndex = towers.indexOf(tower);
if (towerIndex > -1) {
towers.splice(towerIndex, 1);
}
// Destroy tower
tower.destroy();
// Hide sell UI
if (sellUI) {
sellUI.destroy();
sellUI = null;
sellUITower = null;
}
}
// Tired cat button drag functionality
tiredCatButton.down = function (x, y, obj) {
if (gameGold >= 30) {
// Hide sell UI when starting to drag
if (sellUI) {
sellUI.destroy();
sellUI = null;
sellUITower = null;
}
isDragging = true;
selectedTowerType = 'tired';
// Create dragged tower preview
draggedTower = new Tower('tired');
draggedTower.alpha = 0.8;
draggedTower.scaleX = 1.2;
draggedTower.scaleY = 1.2;
game.addChild(draggedTower);
// Convert button position to game coordinates
var buttonPos = game.toLocal(tiredCatButton.parent.toGlobal(tiredCatButton.position));
draggedTower.x = buttonPos.x;
draggedTower.y = buttonPos.y;
dragOffset.x = x;
dragOffset.y = y;
// Play pickup sound
LK.getSound('pickupDefender').play();
// Button feedback
tween(tiredCatButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(tiredCatButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
}
});
}
};
function updateTiredCatButtonAlpha() {
if (gameGold >= 30) {
tiredCatButton.alpha = 1;
tiredCatPrice.alpha = 1;
} else {
tiredCatButton.alpha = 0.5;
tiredCatPrice.alpha = 0.5;
}
}
// Add move handler to tired cat button for drag support
tiredCatButton.move = function (x, y, obj) {
if (isDragging && draggedTower && selectedTowerType === 'tired') {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Apply the offset from button position
var buttonPos = game.toLocal(tiredCatButton.parent.toGlobal(tiredCatButton.position));
draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x);
draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y);
// Check if current position is valid for placement
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
// Tint tower based on placement validity
if (isValidPosition) {
draggedTower.tint = 0x00ff00; // Green tint for valid placement
} else {
draggedTower.tint = 0xff0000; // Red tint for invalid placement
}
}
};
// Normal cat button drag functionality
normalCatButton.down = function (x, y, obj) {
if (gameGold >= 150) {
// Hide sell UI when starting to drag
if (sellUI) {
sellUI.destroy();
sellUI = null;
sellUITower = null;
}
isDragging = true;
selectedTowerType = 'normal';
// Create dragged tower preview
draggedTower = new Tower('normal');
draggedTower.alpha = 0.8;
draggedTower.scaleX = 1.2;
draggedTower.scaleY = 1.2;
game.addChild(draggedTower);
// Convert button position to game coordinates
var buttonPos = game.toLocal(normalCatButton.parent.toGlobal(normalCatButton.position));
draggedTower.x = buttonPos.x;
draggedTower.y = buttonPos.y;
dragOffset.x = x;
dragOffset.y = y;
// Play pickup sound
LK.getSound('pickupDefender').play();
// Button feedback
tween(normalCatButton, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 100,
onFinish: function onFinish() {
tween(normalCatButton, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 100
});
}
});
}
};
function updateNormalCatButtonAlpha() {
if (gameGold >= 150) {
normalCatButton.alpha = 1;
normalCatPrice.alpha = 1;
} else {
normalCatButton.alpha = 0.5;
normalCatPrice.alpha = 0.5;
}
}
// Add move handler to normal cat button for drag support
normalCatButton.move = function (x, y, obj) {
if (isDragging && draggedTower && selectedTowerType === 'normal') {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Apply the offset from button position
var buttonPos = game.toLocal(normalCatButton.parent.toGlobal(normalCatButton.position));
draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x);
draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y);
// Check if current position is valid for placement
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
// Tint tower based on placement validity
if (isValidPosition) {
draggedTower.tint = 0x00ff00; // Green tint for valid placement
} else {
draggedTower.tint = 0xff0000; // Red tint for invalid placement
}
}
};
// Wild cat button drag functionality
wildCatButton.down = function (x, y, obj) {
if (gameGold >= 350) {
// Hide sell UI when starting to drag
if (sellUI) {
sellUI.destroy();
sellUI = null;
sellUITower = null;
}
isDragging = true;
selectedTowerType = 'wild';
// Create dragged tower preview
draggedTower = new Tower('wild');
draggedTower.alpha = 0.8;
draggedTower.scaleX = 1.2;
draggedTower.scaleY = 1.2;
game.addChild(draggedTower);
// Convert button position to game coordinates
var buttonPos = game.toLocal(wildCatButton.parent.toGlobal(wildCatButton.position));
draggedTower.x = buttonPos.x;
draggedTower.y = buttonPos.y;
dragOffset.x = x;
dragOffset.y = y;
// Play pickup sound
LK.getSound('pickupDefender').play();
// Button feedback
tween(wildCatButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(wildCatButton, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 100
});
}
});
}
};
function updateWildCatButtonAlpha() {
if (gameGold >= 350) {
wildCatButton.alpha = 1;
wildCatPrice.alpha = 1;
} else {
wildCatButton.alpha = 0.5;
wildCatPrice.alpha = 0.5;
}
}
// Add move handler to wild cat button for drag support
wildCatButton.move = function (x, y, obj) {
if (isDragging && draggedTower && selectedTowerType === 'wild') {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Apply the offset from button position
var buttonPos = game.toLocal(wildCatButton.parent.toGlobal(wildCatButton.position));
draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x);
draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y);
// Check if current position is valid for placement
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
// Tint tower based on placement validity
if (isValidPosition) {
draggedTower.tint = 0x00ff00; // Green tint for valid placement
} else {
draggedTower.tint = 0xff0000; // Red tint for invalid placement
}
}
};
// Tiger button drag functionality
tigerButton.down = function (x, y, obj) {
if (gameGold >= 500) {
// Hide sell UI when starting to drag
if (sellUI) {
sellUI.destroy();
sellUI = null;
sellUITower = null;
}
isDragging = true;
selectedTowerType = 'tiger';
// Create dragged tower preview
draggedTower = new Tower('tiger');
draggedTower.alpha = 0.8;
draggedTower.scaleX = 1.2;
draggedTower.scaleY = 1.2;
game.addChild(draggedTower);
// Convert button position to game coordinates
var buttonPos = game.toLocal(tigerButton.parent.toGlobal(tigerButton.position));
draggedTower.x = buttonPos.x;
draggedTower.y = buttonPos.y;
dragOffset.x = x;
dragOffset.y = y;
// Play pickup sound
LK.getSound('pickupDefender').play();
// Button feedback
tween(tigerButton, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 100,
onFinish: function onFinish() {
tween(tigerButton, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 100
});
}
});
}
};
function updateTigerButtonAlpha() {
if (gameGold >= 500) {
tigerButton.alpha = 1;
tigerPrice.alpha = 1;
} else {
tigerButton.alpha = 0.5;
tigerPrice.alpha = 0.5;
}
}
// Add move handler to tiger button for drag support
tigerButton.move = function (x, y, obj) {
if (isDragging && draggedTower && selectedTowerType === 'tiger') {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Apply the offset from button position
var buttonPos = game.toLocal(tigerButton.parent.toGlobal(tigerButton.position));
draggedTower.x = gamePos.x + (buttonPos.x - dragOffset.x);
draggedTower.y = gamePos.y + (buttonPos.y - dragOffset.y);
// Check if current position is valid for placement
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
// Tint tower based on placement validity
if (isValidPosition) {
draggedTower.tint = 0x00ff00; // Green tint for valid placement
} else {
draggedTower.tint = 0xff0000; // Red tint for invalid placement
}
}
};
// Add up handlers to all tower buttons
tiredCatButton.up = function (x, y, obj) {
if (isDragging && draggedTower) {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Check if current position is valid for placement using dragged tower's position
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
var towerCost = draggedTower.cost;
if (isValidPosition && gameGold >= towerCost) {
// Place tower at dragged position (tower already positioned correctly)
gameGold -= towerCost;
updateGoldDisplay();
towers.push(draggedTower);
draggedTower.alpha = 1;
draggedTower.tint = 0xffffff; // Reset tint
LK.getSound('placeDefender').play();
} else {
// Remove dragged tower if placement failed
draggedTower.destroy();
}
// Reset dragging state
isDragging = false;
draggedTower = null;
}
};
normalCatButton.up = function (x, y, obj) {
if (isDragging && draggedTower) {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Check if current position is valid for placement using dragged tower's position
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
var towerCost = draggedTower.cost;
if (isValidPosition && gameGold >= towerCost) {
// Place tower at dragged position (tower already positioned correctly)
gameGold -= towerCost;
updateGoldDisplay();
towers.push(draggedTower);
draggedTower.alpha = 1;
draggedTower.tint = 0xffffff; // Reset tint
LK.getSound('placeDefender').play();
} else {
// Remove dragged tower if placement failed
draggedTower.destroy();
}
// Reset dragging state
isDragging = false;
draggedTower = null;
}
};
wildCatButton.up = function (x, y, obj) {
if (isDragging && draggedTower) {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Check if current position is valid for placement using dragged tower's position
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
var towerCost = draggedTower.cost;
if (isValidPosition && gameGold >= towerCost) {
// Place tower at dragged position (tower already positioned correctly)
gameGold -= towerCost;
updateGoldDisplay();
towers.push(draggedTower);
draggedTower.alpha = 1;
draggedTower.tint = 0xffffff; // Reset tint
LK.getSound('placeDefender').play();
} else {
// Remove dragged tower if placement failed
draggedTower.destroy();
}
// Reset dragging state
isDragging = false;
draggedTower = null;
}
};
tigerButton.up = function (x, y, obj) {
if (isDragging && draggedTower) {
var gamePos = obj.parent ? game.toLocal(obj.parent.toGlobal({
x: x,
y: y
})) : {
x: x,
y: y
};
// Check if current position is valid for placement using dragged tower's position
var isValidPosition = isValidPlacementPosition(draggedTower.x, draggedTower.y);
var towerCost = draggedTower.cost;
if (isValidPosition && gameGold >= towerCost) {
// Place tower at dragged position (tower already positioned correctly)
gameGold -= towerCost;
updateGoldDisplay();
towers.push(draggedTower);
draggedTower.alpha = 1;
draggedTower.tint = 0xffffff; // Reset tint
LK.getSound('placeDefender').play();
} else {
// Remove dragged tower if placement failed
draggedTower.destroy();
}
// Reset dragging state
isDragging = false;
draggedTower = null;
}
};
// Game move handler for dragging
game.move = function (x, y, obj) {
if (isDragging && draggedTower) {
draggedTower.x = x;
draggedTower.y = y;
// Check if current position is valid for placement
var isValidPosition = isValidPlacementPosition(x, y);
// Tint tower based on placement validity
if (isValidPosition) {
draggedTower.tint = 0x00ff00; // Green tint for valid placement
} else if (selectedTower === draggedTower) {
draggedTower.tint = 0x00ffff; // Keep cyan tint for selected tower being repositioned
} else {
draggedTower.tint = 0xff0000; // Red tint for invalid placement
}
}
};
// Game up handler for tower placement
game.up = function (x, y, obj) {
if (isDragging && draggedTower) {
// Check if current position is valid for placement
var isValidPosition = isValidPlacementPosition(x, y);
// Check if this is a repositioning of an existing tower
var isRepositioning = selectedTower === draggedTower;
var towerCost = isRepositioning ? 0 : draggedTower.cost;
if (isValidPosition && gameGold >= towerCost) {
// Place or reposition tower at current position
if (!isRepositioning) {
gameGold -= towerCost;
updateGoldDisplay();
towers.push(draggedTower);
}
// Keep tower at current dragged position
draggedTower.alpha = 1;
draggedTower.tint = 0xffffff; // Reset tint
if (!isRepositioning) {
LK.getSound('placeDefender').play();
}
} else if (isRepositioning) {
// If repositioning failed, keep tower at its current position but remove selection
draggedTower.tint = 0xffffff;
} else {
// Remove dragged tower if placement failed
draggedTower.destroy();
}
// Reset dragging and selection state
isDragging = false;
draggedTower = null;
if (selectedTower) {
selectedTower = null;
}
}
};
// Start background music
LK.playMusic('bgMusic');
game.update = function () {
// Don't spawn mice until game starts (start button clicked)
if (!gameStarted) {
return; // Don't spawn mice until game starts
}
// Handle pause after wave 4 (changed from wave 3) or waiting for wave 5 start
if (isPaused || waitingForWave5Start) {
if (isPaused) {
pauseTimer += gameSpeedMultiplier;
if (pauseTimer >= 600) {
// 10 seconds at 60fps
isPaused = false;
// Remove pause text
if (pauseText) {
pauseText.destroy();
pauseText = null;
}
// Show start button with normal cat, arrow, rat after wave 4
if (waveNumber === 5) {
// Wave number increments before pause check
// Set waiting state for wave 5
waitingForWave5Start = true;
// Show start button
startButton.alpha = 1;
startButton.interactive = true;
// Change tutorial images for wave 4 completion
tutorialCat.destroy();
tutorialCat = LK.getAsset('normalCat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
alpha: 1
});
tutorialCat.x = -120;
tutorialCat.y = -20;
LK.gui.center.addChild(tutorialCat);
tutorialArrow.alpha = 1;
// Change mouse to rat
tutorialMouse.destroy();
tutorialMouse = LK.getAsset('rat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
alpha: 1
});
tutorialMouse.x = 120;
tutorialMouse.y = -20;
LK.gui.center.addChild(tutorialMouse);
}
}
}
return; // Don't spawn enemies during pause or while waiting for wave 5 start
}
// Spawn mice with much more random timing variation
spawnTimer += gameSpeedMultiplier;
var randomSpawnDelay = Math.random() * 60 + Math.random() * 30; // Much more random delay
if (spawnTimer >= spawnRate + randomSpawnDelay && miceSpawned < maxMicePerWave) {
var mouse = new Mouse();
// Much more random spawn positions with larger variation
mouse.x = gamePath[0].x + (Math.random() - 0.5) * 600 + Math.random() * 200;
mouse.y = gamePath[0].y + (Math.random() - 0.5) * 400 + Math.random() * 150;
// More random health variation (±40%)
var baseHealth = 180 + waveNumber * 50;
mouse.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.8;
mouse.maxHealth = mouse.health;
// Much more random speed variation (±50%)
mouse.speed = mouse.speed * (0.5 + Math.random() * 1.0);
mouse.updateHealthBar();
mice.push(mouse);
game.addChild(mouse);
miceSpawned++;
spawnTimer = Math.random() * 20; // Random reset for more chaos
}
// Spawn rats (only after wave 5) with random variations
if (waveNumber >= 5) {
ratSpawnTimer += gameSpeedMultiplier;
var randomRatDelay = Math.random() * 40;
if (ratSpawnTimer >= ratSpawnRate + randomRatDelay && ratsSpawned < maxRatsPerWave) {
var rat = new Rat();
rat.x = gamePath[0].x + (Math.random() - 0.5) * 500;
rat.y = gamePath[0].y + (Math.random() - 0.5) * 250;
// Random health variation (±25%)
var baseHealth = 500 + waveNumber * 120;
rat.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.5;
rat.maxHealth = rat.health;
// Random speed variation (±40%)
rat.speed = rat.speed * (0.6 + Math.random() * 0.8);
rat.updateHealthBar();
rats.push(rat);
game.addChild(rat);
ratsSpawned++;
ratSpawnTimer = 0;
}
}
// Spawn hares (only after wave 10) with random variations
if (waveNumber >= 10) {
hareSpawnTimer += gameSpeedMultiplier;
var randomHareDelay = Math.random() * 50;
if (hareSpawnTimer >= hareSpawnRate + randomHareDelay && haresSpawned < maxHaresPerWave) {
var hare = new Hare();
hare.x = gamePath[0].x + (Math.random() - 0.5) * 600;
hare.y = gamePath[0].y + (Math.random() - 0.5) * 300;
// Random health variation (±30%)
var baseHealth = 700 + waveNumber * 150;
hare.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.6;
hare.maxHealth = hare.health;
// Random speed variation (±35%)
hare.speed = hare.speed * (0.65 + Math.random() * 0.7);
hare.updateHealthBar();
hares.push(hare);
game.addChild(hare);
haresSpawned++;
hareSpawnTimer = 0;
}
}
// Spawn birds (only after wave 15) with random variations
if (waveNumber >= 15) {
birdSpawnTimer += gameSpeedMultiplier;
var randomBirdDelay = Math.random() * 35;
if (birdSpawnTimer >= birdSpawnRate + randomBirdDelay && birdsSpawned < maxBirdsPerWave) {
var bird = new Bird();
bird.x = gamePath[0].x + (Math.random() - 0.5) * 450;
bird.y = gamePath[0].y + (Math.random() - 0.5) * 200;
// Random health variation (±25%)
var baseHealth = 400 + waveNumber * 100;
bird.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.5;
bird.maxHealth = bird.health;
// Random speed variation (±30%)
bird.speed = bird.speed * (0.7 + Math.random() * 0.6);
bird.updateHealthBar();
birds.push(bird);
game.addChild(bird);
birdsSpawned++;
birdSpawnTimer = 0;
}
}
// Spawn dogs (only after wave 20) with random variations
if (waveNumber >= 20) {
dogSpawnTimer += gameSpeedMultiplier;
var randomDogDelay = Math.random() * 60;
if (dogSpawnTimer >= dogSpawnRate + randomDogDelay && dogsSpawned < maxDogsPerWave) {
var dog = new Dog();
dog.x = gamePath[0].x + (Math.random() - 0.5) * 400;
dog.y = gamePath[0].y + (Math.random() - 0.5) * 200;
// Random health variation (±35%)
var baseHealth = 800 + waveNumber * 200;
dog.health = baseHealth + (Math.random() - 0.5) * baseHealth * 0.7;
dog.maxHealth = dog.health;
// Random speed variation (±25%)
dog.speed = dog.speed * (0.75 + Math.random() * 0.5);
dog.updateHealthBar();
dogs.push(dog);
game.addChild(dog);
dogsSpawned++;
dogSpawnTimer = 0;
}
}
// Check if wave is complete
if (miceSpawned >= maxMicePerWave && ratsSpawned >= maxRatsPerWave && haresSpawned >= maxHaresPerWave && birdsSpawned >= maxBirdsPerWave && dogsSpawned >= maxDogsPerWave && mice.length === 0 && rats.length === 0 && hares.length === 0 && birds.length === 0 && dogs.length === 0) {
// Check if wave 4, 14, or 19 just completed
if (waveNumber === 4 || waveNumber === 14 || waveNumber === 19) {
isPaused = true;
pauseTimer = 0;
}
waveNumber++;
miceSpawned = 0;
ratsSpawned = 0;
haresSpawned = 0;
birdsSpawned = 0;
dogsSpawned = 0;
// Random variation in mice count per wave (±30%)
var baseMiceIncrease = waveNumber <= 3 ? 2 : 1;
maxMicePerWave += Math.floor(baseMiceIncrease * (0.7 + Math.random() * 0.6));
// Start spawning rats after wave 5 with random counts
if (waveNumber >= 5) {
var baseRats = Math.max(1, waveNumber - 4);
maxRatsPerWave = Math.floor(baseRats * (0.8 + Math.random() * 0.4));
}
// Start spawning birds after wave 15 with random counts
if (waveNumber >= 15) {
var baseBirds = Math.max(1, waveNumber - 14);
maxBirdsPerWave = Math.floor(baseBirds * (0.7 + Math.random() * 0.6));
}
// Start spawning hares after wave 10 with random counts
if (waveNumber >= 10) {
var baseHares = Math.max(1, waveNumber - 9);
maxHaresPerWave = Math.floor(baseHares * (0.8 + Math.random() * 0.4));
}
// Start spawning dogs after wave 20 with random counts
if (waveNumber >= 20) {
var baseDogs = Math.max(1, waveNumber - 19);
maxDogsPerWave = Math.floor(baseDogs * (0.6 + Math.random() * 0.8));
}
// Random spawn rate variations
var baseSpawnDecrease = waveNumber <= 3 ? 8 : 12;
spawnRate = Math.max(40, spawnRate - Math.floor(baseSpawnDecrease * (0.8 + Math.random() * 0.4)));
ratSpawnRate = Math.max(90, ratSpawnRate - Math.floor(15 * (0.7 + Math.random() * 0.6)));
hareSpawnRate = Math.max(100, hareSpawnRate - Math.floor(10 * (0.8 + Math.random() * 0.4)));
birdSpawnRate = Math.max(70, birdSpawnRate - Math.floor(10 * (0.9 + Math.random() * 0.2)));
dogSpawnRate = Math.max(120, dogSpawnRate - Math.floor(10 * (0.7 + Math.random() * 0.6)));
updateWaveDisplay();
}
// Update all game objects
for (var i = mice.length - 1; i >= 0; i--) {
if (mice[i].parent) {
mice[i].update();
}
}
for (var i = rats.length - 1; i >= 0; i--) {
if (rats[i].parent) {
rats[i].update();
}
}
for (var i = hares.length - 1; i >= 0; i--) {
if (hares[i].parent) {
hares[i].update();
}
}
for (var i = birds.length - 1; i >= 0; i--) {
if (birds[i].parent) {
birds[i].update();
}
}
for (var i = dogs.length - 1; i >= 0; i--) {
if (dogs[i].parent) {
dogs[i].update();
}
}
for (var i = towers.length - 1; i >= 0; i--) {
if (towers[i].parent) {
towers[i].update();
// Check if tower is touching menu area (bottom 200px of screen)
var isTouchingMenu = towers[i].y > 2532; // Menu area starts around y=2532
if (isTouchingMenu && !isDragging) {
// Check if tower is very close to the path (excluding treatpacket position)
var minDistanceFromPath = Infinity;
for (var p = 0; p < gamePath.length - 1; p++) {
var dx = gamePath[p].x - towers[i].x;
var dy = gamePath[p].y - towers[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistanceFromPath) {
minDistanceFromPath = distance;
}
}
// If not very close to path (more than 120px away), turn red
if (minDistanceFromPath > 120) {
towers[i].tint = 0xff0000; // Red tint
} else {
towers[i].tint = 0xffffff; // Reset to normal
}
} else if (!isDragging && towers[i] !== selectedTower) {
// Reset tint if not touching menu and not being dragged/selected
towers[i].tint = 0xffffff;
}
}
}
};
Un emignone souris cartoon style sur ses quatres pattes. In-Game asset. 2d. High contrast. No shadows
Cute tired cat manga cartoon style. In-Game asset. 2d. High contrast. No shadows
A cute manga style cat. In-Game asset. 2d. High contrast. No shadows
An angry but cute wild cat manga cartoon style. In-Game asset. 2d. High contrast. No shadows
A big angry cute tiger. In-Game asset. 2d. High contrast. No shadows
A pretty air view grass plain. In-Game asset. 2d. High contrast. No shadows
A red rectangular button. In-Game asset. 2d. High contrast. No shadows
A cute hare running on 4 paws. In-Game asset. 2d. High contrast. No shadows
cute lil bird flying cartoon style
Make more manga style and cutter with cut colors
a cute angry dog manga style. In-Game asset. 2d. High contrast. No shadows