User prompt
Bug with the start button, the wave start before clicking on it
User prompt
Make game more smooth ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Bug with start button at wave 5
User prompt
Remove wave 3 pause and in the end of wave 4, after 10 secs, show start button with a normal cat, arrow , rat
User prompt
Remove wave 4 start text
User prompt
Add more animations to make game more satisfying ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make de can place cats everywhere wanted but they can attack by farer
User prompt
Make Wild cat attack hares super fast and hare takes 15% of packet
User prompt
Fait tout les texte en gras pour qu’ils soient plus visible
User prompt
Remove text rats invoming
User prompt
Make like normal cat, but now it is wild cat that can attack hares also make hare only start spawn at wave 10 and rats start spawning only at wave 5
User prompt
Add hare as enemy
User prompt
Bug: normal cat attack rats slowly
User prompt
No, actually the tuto is just a tired cat-arow-mouse with images and its on te start button and its disapear when click on it
User prompt
Yes but it is written CLICK TO START instead of the tuto
User prompt
It is good but i see only the arrow
User prompt
Bug: the tuto should bé a l'avant plan
User prompt
No, because the tuto should bé on the start button
User prompt
Bug: I don't see the tired cat arrow mouse thing I think its because the start button is on it
User prompt
Bug : nrml cats attack rats slowly
User prompt
Make we start with 120g instead of 130
User prompt
Make nrml cat costs 150 instead of 200 and don't count tower(treatpacket) as a path
User prompt
Si le défenseur glissé touche le menu il doit être rouge automatiquement sauf si il est très proche du path
User prompt
L'option cliquée doit être transparente
User prompt
Non, c'est le contraire, quand on clique sur le bouton il est transparent don au début vu que ça commence on a pas encore activer l'option vitesse DCP c'est le bouton slow qui est transparent
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ 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]; 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) { // 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 } 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) { // 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]; 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) { // 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 } 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) { // Rat defeated - give reward gameGold += self.reward; updateGoldDisplay(); LK.getSound('mouseHit').play(); self.destroy(); rats.splice(rats.indexOf(self), 1); } }; return self; }); var Tower = Container.expand(function (type) { var self = Container.call(this); var towerGraphics; self.type = type || 'tired'; self.range = 250; 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 } 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 = 280; self.cost = 200; 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 = 300; 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 = 350; 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 = 320; 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 = 400; 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 everything slowly unless targeting rats if (self.type === 'normal') { if (target.constructor.name === 'Rat') { currentFireRate = 2; // Extremely fast against rats for superior effectiveness } else { currentFireRate = 240; // Slow attack rate against everything else (mice and any other enemies) } } if (self.lastShot >= currentFireRate) { self.shoot(target); self.lastShot = 0; } } }; self.findTarget = function () { var closestEnemy = null; var closestDistance = self.range; // 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; } } 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 var originalScaleX = 1; if (dx > 0) { originalScaleX = 1; // Face right towerGraphics.scaleX = 1; } else if (dx < 0) { originalScaleX = -1; // Face left towerGraphics.scaleX = -1; } // Instant damage instead of bullets target.takeDamage(self.damage); LK.getSound('shoot').play(); LK.getSound('hit').play(); // Recoil animation tween(towerGraphics, { scaleX: originalScaleX * 0.8, scaleY: 0.8 }, { duration: 100, onFinish: function onFinish() { tween(towerGraphics, { scaleX: originalScaleX, scaleY: 1 }, { duration: 100 }); } }); }; 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; // 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 towers = []; var gameGold = 130; var packetHealth = 100; var waveNumber = 1; var miceSpawned = 0; var ratsSpawned = 0; var maxMicePerWave = 15; var maxRatsPerWave = 0; var spawnTimer = 0; var ratSpawnTimer = 0; var spawnRate = 90; // frames between spawns (much faster spawning for harder waves) var ratSpawnRate = 100; // frames between rat spawns (faster) 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 var gamePath = [{ x: 1024, y: 50 }, { x: 600, y: 300 }, { x: 1400, y: 600 }, { x: 400, y: 900 }, { x: 1600, y: 1200 }, { x: 800, y: 1500 }, { x: 1200, y: 1800 }, { x: 500, y: 2100 }, { x: 1500, y: 2400 }, { x: 1024, y: 2700 }]; // 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.5 })); 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 distance from path var minDistanceFromPath = Infinity; for (var p = 0; p < gamePath.length; p++) { var dx = gamePath[p].x - x; var dy = gamePath[p].y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistanceFromPath) { minDistanceFromPath = distance; } } // Must be within range of path but not too close (avoid blocking) if (minDistanceFromPath > maxDistanceFromPath || minDistanceFromPath < 80) { 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 }); 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 }); 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 }); 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, alpha: 0 }); startButton.x = 0; startButton.y = 0; startButton.interactive = false; LK.gui.center.addChild(startButton); // Add tutorial images to 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; startButton.addChild(tutorialCat); // Add arrow pointing from cat to mouse var arrow = new Text2('→', { size: 60, fill: 0xFFFFFF }); arrow.anchor.set(0.5, 0.5); arrow.x = 0; arrow.y = -20; arrow.alpha = 0; startButton.addChild(arrow); // 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; startButton.addChild(tutorialMouse); // Add click handler to start button startButton.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; // Hide start button immediately startButton.alpha = 0; startButton.interactive = false; // Hide tutorial images tutorialCat.alpha = 0; arrow.alpha = 0; tutorialMouse.alpha = 0; } }; // 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(arrow, { alpha: 1 }, { duration: 500 }); 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 }); 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('200g', { size: 40, fill: 0xFFD700 }); 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 }); 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 }); 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 }); fastForwardButton.anchor.set(1, 0); fastForwardButton.x = -20; fastForwardButton.y = 120; LK.gui.topRight.addChild(fastForwardButton); var normalSpeedButton = new Text2('▶️', { size: 80, fill: 0xFFFFFF }); normalSpeedButton.anchor.set(1, 0); normalSpeedButton.x = -20; normalSpeedButton.y = 220; fastForwardButton.alpha = 0.5; // Start dimmed since we begin at normal speed normalSpeedButton.alpha = 1; // Start fully opaque 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 fully opaque and normal button transparent tween(fastForwardButton, { alpha: 1 }, { duration: 200 }); tween(normalSpeedButton, { alpha: 0.5 }, { duration: 200 }); }; normalSpeedButton.down = function (x, y, obj) { gameSpeedMultiplier = 1; // Make normal button fully opaque and fast button transparent tween(fastForwardButton, { alpha: 0.5 }, { duration: 200 }); tween(normalSpeedButton, { alpha: 1 }, { 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 }); 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; // 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 >= 200) { // 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; // 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 >= 200) { 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; // 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; // 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('shoot').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('shoot').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('shoot').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('shoot').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('shoot').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 3 if (isPaused) { pauseTimer += gameSpeedMultiplier; if (pauseTimer >= 600) { // 10 seconds at 60fps isPaused = false; // Remove pause text if (pauseText) { pauseText.destroy(); pauseText = null; } // Show wave start text var waveStartText = new Text2('Wave ' + waveNumber + ' - START!', { size: 80, fill: 0xFFFF00 }); waveStartText.anchor.set(0.5, 0.5); waveStartText.x = 0; waveStartText.y = 0; LK.gui.center.addChild(waveStartText); tween(waveStartText, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { waveStartText.destroy(); } }); } return; // Don't spawn enemies during pause } // Spawn mice spawnTimer += gameSpeedMultiplier; if (spawnTimer >= spawnRate && miceSpawned < maxMicePerWave) { var mouse = new Mouse(); mouse.x = gamePath[0].x + (Math.random() - 0.5) * 200; mouse.y = gamePath[0].y + (Math.random() - 0.5) * 100; mouse.health = 180 + waveNumber * 50; // Much higher base health and scaling for harder waves mouse.maxHealth = mouse.health; // Remove speed bonus to ensure mice aren't faster than defenders mouse.updateHealthBar(); mice.push(mouse); game.addChild(mouse); miceSpawned++; spawnTimer = 0; } // Spawn rats (only after wave 3) if (waveNumber > 3) { ratSpawnTimer += gameSpeedMultiplier; if (ratSpawnTimer >= ratSpawnRate && ratsSpawned < maxRatsPerWave) { var rat = new Rat(); rat.x = gamePath[0].x + (Math.random() - 0.5) * 200; rat.y = gamePath[0].y + (Math.random() - 0.5) * 100; rat.health = 500 + waveNumber * 120; // Much higher base health and scaling for harder waves rat.maxHealth = rat.health; // Remove speed bonus to ensure rats aren't faster than defenders rat.updateHealthBar(); rats.push(rat); game.addChild(rat); ratsSpawned++; ratSpawnTimer = 0; } } // Check if wave is complete if (miceSpawned >= maxMicePerWave && ratsSpawned >= maxRatsPerWave && mice.length === 0 && rats.length === 0) { // Check if wave 3 just completed if (waveNumber === 3) { isPaused = true; pauseTimer = 0; // Create pause text pauseText = new Text2('Rats incoming in 10 seconds!', { size: 80, fill: 0xFFFF00 }); pauseText.anchor.set(0.5, 0.5); pauseText.x = 0; pauseText.y = 0; LK.gui.center.addChild(pauseText); // Flash effect tween(pauseText, { alpha: 0.3 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(pauseText, { alpha: 1 }, { duration: 500, easing: tween.easeInOut }); } }); } waveNumber++; miceSpawned = 0; ratsSpawned = 0; maxMicePerWave += waveNumber <= 3 ? 2 : 1; // Increase more for early waves to make them longer // Start spawning rats after wave 3 if (waveNumber > 3) { maxRatsPerWave = Math.max(1, waveNumber - 3); } spawnRate = Math.max(40, spawnRate - (waveNumber <= 3 ? 8 : 12)); // Faster decrease for harder wave progression ratSpawnRate = Math.max(90, ratSpawnRate - 15); // Faster decrease, lower minimum 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 = towers.length - 1; i >= 0; i--) { if (towers[i].parent) { towers[i].update(); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
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];
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) {
// 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
}
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) {
// 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];
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) {
// 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
}
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) {
// Rat defeated - give reward
gameGold += self.reward;
updateGoldDisplay();
LK.getSound('mouseHit').play();
self.destroy();
rats.splice(rats.indexOf(self), 1);
}
};
return self;
});
var Tower = Container.expand(function (type) {
var self = Container.call(this);
var towerGraphics;
self.type = type || 'tired';
self.range = 250;
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
} 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 = 280;
self.cost = 200;
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 = 300;
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 = 350;
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 = 320;
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 = 400;
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 everything slowly unless targeting rats
if (self.type === 'normal') {
if (target.constructor.name === 'Rat') {
currentFireRate = 2; // Extremely fast against rats for superior effectiveness
} else {
currentFireRate = 240; // Slow attack rate against everything else (mice and any other enemies)
}
}
if (self.lastShot >= currentFireRate) {
self.shoot(target);
self.lastShot = 0;
}
}
};
self.findTarget = function () {
var closestEnemy = null;
var closestDistance = self.range;
// 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;
}
}
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
var originalScaleX = 1;
if (dx > 0) {
originalScaleX = 1; // Face right
towerGraphics.scaleX = 1;
} else if (dx < 0) {
originalScaleX = -1; // Face left
towerGraphics.scaleX = -1;
}
// Instant damage instead of bullets
target.takeDamage(self.damage);
LK.getSound('shoot').play();
LK.getSound('hit').play();
// Recoil animation
tween(towerGraphics, {
scaleX: originalScaleX * 0.8,
scaleY: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(towerGraphics, {
scaleX: originalScaleX,
scaleY: 1
}, {
duration: 100
});
}
});
};
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;
// 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 towers = [];
var gameGold = 130;
var packetHealth = 100;
var waveNumber = 1;
var miceSpawned = 0;
var ratsSpawned = 0;
var maxMicePerWave = 15;
var maxRatsPerWave = 0;
var spawnTimer = 0;
var ratSpawnTimer = 0;
var spawnRate = 90; // frames between spawns (much faster spawning for harder waves)
var ratSpawnRate = 100; // frames between rat spawns (faster)
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
var gamePath = [{
x: 1024,
y: 50
}, {
x: 600,
y: 300
}, {
x: 1400,
y: 600
}, {
x: 400,
y: 900
}, {
x: 1600,
y: 1200
}, {
x: 800,
y: 1500
}, {
x: 1200,
y: 1800
}, {
x: 500,
y: 2100
}, {
x: 1500,
y: 2400
}, {
x: 1024,
y: 2700
}];
// 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.5
}));
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 distance from path
var minDistanceFromPath = Infinity;
for (var p = 0; p < gamePath.length; p++) {
var dx = gamePath[p].x - x;
var dy = gamePath[p].y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistanceFromPath) {
minDistanceFromPath = distance;
}
}
// Must be within range of path but not too close (avoid blocking)
if (minDistanceFromPath > maxDistanceFromPath || minDistanceFromPath < 80) {
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
});
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
});
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
});
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,
alpha: 0
});
startButton.x = 0;
startButton.y = 0;
startButton.interactive = false;
LK.gui.center.addChild(startButton);
// Add tutorial images to 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;
startButton.addChild(tutorialCat);
// Add arrow pointing from cat to mouse
var arrow = new Text2('→', {
size: 60,
fill: 0xFFFFFF
});
arrow.anchor.set(0.5, 0.5);
arrow.x = 0;
arrow.y = -20;
arrow.alpha = 0;
startButton.addChild(arrow);
// 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;
startButton.addChild(tutorialMouse);
// Add click handler to start button
startButton.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
// Hide start button immediately
startButton.alpha = 0;
startButton.interactive = false;
// Hide tutorial images
tutorialCat.alpha = 0;
arrow.alpha = 0;
tutorialMouse.alpha = 0;
}
};
// 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(arrow, {
alpha: 1
}, {
duration: 500
});
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
});
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('200g', {
size: 40,
fill: 0xFFD700
});
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
});
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
});
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
});
fastForwardButton.anchor.set(1, 0);
fastForwardButton.x = -20;
fastForwardButton.y = 120;
LK.gui.topRight.addChild(fastForwardButton);
var normalSpeedButton = new Text2('▶️', {
size: 80,
fill: 0xFFFFFF
});
normalSpeedButton.anchor.set(1, 0);
normalSpeedButton.x = -20;
normalSpeedButton.y = 220;
fastForwardButton.alpha = 0.5; // Start dimmed since we begin at normal speed
normalSpeedButton.alpha = 1; // Start fully opaque
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 fully opaque and normal button transparent
tween(fastForwardButton, {
alpha: 1
}, {
duration: 200
});
tween(normalSpeedButton, {
alpha: 0.5
}, {
duration: 200
});
};
normalSpeedButton.down = function (x, y, obj) {
gameSpeedMultiplier = 1;
// Make normal button fully opaque and fast button transparent
tween(fastForwardButton, {
alpha: 0.5
}, {
duration: 200
});
tween(normalSpeedButton, {
alpha: 1
}, {
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
});
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;
// 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 >= 200) {
// 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;
// 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 >= 200) {
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;
// 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;
// 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('shoot').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('shoot').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('shoot').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('shoot').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('shoot').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 3
if (isPaused) {
pauseTimer += gameSpeedMultiplier;
if (pauseTimer >= 600) {
// 10 seconds at 60fps
isPaused = false;
// Remove pause text
if (pauseText) {
pauseText.destroy();
pauseText = null;
}
// Show wave start text
var waveStartText = new Text2('Wave ' + waveNumber + ' - START!', {
size: 80,
fill: 0xFFFF00
});
waveStartText.anchor.set(0.5, 0.5);
waveStartText.x = 0;
waveStartText.y = 0;
LK.gui.center.addChild(waveStartText);
tween(waveStartText, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
waveStartText.destroy();
}
});
}
return; // Don't spawn enemies during pause
}
// Spawn mice
spawnTimer += gameSpeedMultiplier;
if (spawnTimer >= spawnRate && miceSpawned < maxMicePerWave) {
var mouse = new Mouse();
mouse.x = gamePath[0].x + (Math.random() - 0.5) * 200;
mouse.y = gamePath[0].y + (Math.random() - 0.5) * 100;
mouse.health = 180 + waveNumber * 50; // Much higher base health and scaling for harder waves
mouse.maxHealth = mouse.health;
// Remove speed bonus to ensure mice aren't faster than defenders
mouse.updateHealthBar();
mice.push(mouse);
game.addChild(mouse);
miceSpawned++;
spawnTimer = 0;
}
// Spawn rats (only after wave 3)
if (waveNumber > 3) {
ratSpawnTimer += gameSpeedMultiplier;
if (ratSpawnTimer >= ratSpawnRate && ratsSpawned < maxRatsPerWave) {
var rat = new Rat();
rat.x = gamePath[0].x + (Math.random() - 0.5) * 200;
rat.y = gamePath[0].y + (Math.random() - 0.5) * 100;
rat.health = 500 + waveNumber * 120; // Much higher base health and scaling for harder waves
rat.maxHealth = rat.health;
// Remove speed bonus to ensure rats aren't faster than defenders
rat.updateHealthBar();
rats.push(rat);
game.addChild(rat);
ratsSpawned++;
ratSpawnTimer = 0;
}
}
// Check if wave is complete
if (miceSpawned >= maxMicePerWave && ratsSpawned >= maxRatsPerWave && mice.length === 0 && rats.length === 0) {
// Check if wave 3 just completed
if (waveNumber === 3) {
isPaused = true;
pauseTimer = 0;
// Create pause text
pauseText = new Text2('Rats incoming in 10 seconds!', {
size: 80,
fill: 0xFFFF00
});
pauseText.anchor.set(0.5, 0.5);
pauseText.x = 0;
pauseText.y = 0;
LK.gui.center.addChild(pauseText);
// Flash effect
tween(pauseText, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(pauseText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
}
waveNumber++;
miceSpawned = 0;
ratsSpawned = 0;
maxMicePerWave += waveNumber <= 3 ? 2 : 1; // Increase more for early waves to make them longer
// Start spawning rats after wave 3
if (waveNumber > 3) {
maxRatsPerWave = Math.max(1, waveNumber - 3);
}
spawnRate = Math.max(40, spawnRate - (waveNumber <= 3 ? 8 : 12)); // Faster decrease for harder wave progression
ratSpawnRate = Math.max(90, ratSpawnRate - 15); // Faster decrease, lower minimum
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 = towers.length - 1; i >= 0; i--) {
if (towers[i].parent) {
towers[i].update();
}
}
};
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