User prompt
Before flyby starts moving in add cell to titlescreen
User prompt
Move alien head down 10
User prompt
When fireballs naturally complete their lifecycle (hit enemy, go off-screen, etc.), remove them from their parent tower's fireballs array to prevent memory leaks.
User prompt
Modify the existing tower destruction logic to iterate through `tower.fireballs`, stop each fireball's movement interval using `LK.clearInterval()`, and destroy each fireball object.
User prompt
When a fire tower creates a fireball, push both the fireball object AND its interval timer to the tower's fireballs array. This creates a direct ownership relationship
User prompt
Fix this please
User prompt
When creating a fire tower, add a `tower.fireballs = []` property to store references to all fireballs launched by that tower.
User prompt
Play probedroid2 sound once first drone appears in level1 wave2
User prompt
Play probedroid2 sound once first drone appears in level1 wave2
User prompt
Play probedroid sound once when first probedroid appears in level1 wave 1
User prompt
Play probedroid sound when level1 wave1 starts
User prompt
Play fireball sound when fireballs are fired
User prompt
Stop music when flyby leaves backdrop scene
User prompt
Don't stop music at wave1
User prompt
Add electric sound to play when electric tower uses zap effect
User prompt
Play fart sound when dog shoots gas cloud
User prompt
Use explosion effect when towers are destroyed
User prompt
Play confirm sound when green tick is clicked
User prompt
Play explosion sound when tower is destroyed
User prompt
Play explosion sounds when the explosion asset is used
User prompt
Initialise sounds
User prompt
Please fix
User prompt
Make flying aliens spawn every 10 seconds in level2 wave 4
User prompt
How can we fix this efficiently
User prompt
Stop music playing when wave1 starts
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Defense class var Defense = Container.expand(function () { var self = Container.call(this); var defenseGraphics = self.attachAsset('defense', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Defense logic goes here }; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); // Add number text self.numberText = new Text2('1', { size: 60, fill: 0x000000 }); self.numberText.anchor.set(0.5, 0.5); self.numberText.x = 0; self.numberText.y = 0; self.addChild(self.numberText); // Add health bar var healthBarOutline = self.attachAsset('healthBarOutline', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -100 }); var healthBar = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -100, tint: 0x00ff00 }); self.updateHealthBar = function () { var healthPercentage = self.health / self.maxHealth; healthBar.scaleX = healthPercentage; // Change color based on health if (healthPercentage > 0.6) { healthBar.tint = 0x00ff00; // Green } else if (healthPercentage > 0.3) { healthBar.tint = 0xffff00; // Yellow } else { healthBar.tint = 0xff0000; // Red } }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; } self.updateHealthBar(); }; self.update = function () { // Initialize lastX if not set if (self.lastX === undefined) self.lastX = self.x; // Update health bar self.updateHealthBar(); }; return self; }); // Assets will be automatically created and loaded by the LK engine // Tower class var Tower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Tower logic goes here }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 //Init game with black background }); /**** * Game Code ****/ // Game update loop game.update = function () { if (!gameStarted) return; // Spawn enemies enemySpawnTimer++; if (enemySpawnTimer >= enemySpawnInterval) { spawnEnemy(); enemySpawnTimer = 0; } // Update enemies updateEnemies(); // Check win condition if (enemiesSpawned >= maxEnemiesInWave && enemies.length === 0) { LK.showYouWin(); } }; var enemies = []; var towers = []; var gameStarted = false; var enemySpawnTimer = 0; var enemySpawnInterval = 120; // Spawn every 2 seconds at 60fps var enemiesSpawned = 0; var maxEnemiesInWave = 10; // Wave 1 has exactly 10 enemies // Tower defense functions function startTowerDefenseWave1() { gameStarted = true; enemySpawnTimer = 0; enemiesSpawned = 0; } function spawnEnemy() { if (enemiesSpawned >= maxEnemiesInWave) return; var enemy = game.addChild(new Enemy()); // Position enemy at the right side of the screen enemy.x = 2048 - 50; // Start from right side enemy.y = 2732 / 7 + 600; // First guideline position enemy.health = 100; enemy.maxHealth = 100; enemy.speed = -2; // Negative speed to move left enemy.pathIndex = 0; enemy.lastPathIndex = -1; // Set enemy number enemy.numberText.setText((enemiesSpawned + 1).toString()); enemies.push(enemy); enemiesSpawned++; } function updateEnemies() { for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Move enemy using its speed (negative for left movement) enemy.x += enemy.speed; // Check if enemy reached the left side of the screen if (enemy.lastX >= 0 && enemy.x < 0) { // Enemy reached the left side - remove it enemy.destroy(); enemies.splice(i, 1); continue; } // Update last position for next frame enemy.lastX = enemy.x; } } // Display the title // Import tween plugin var titleImage = game.addChild(LK.getAsset('Title', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 + 1400 })); // Add cell asset to title screen var cellImage = game.addChild(LK.getAsset('cell', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 + 800 })); // Add skip intro button to top of title screen var skipButton = new Text2('SKIP INTRO', { size: 60, fill: 0xFFFFFF }); skipButton.anchor.set(0.5, 0); skipButton.x = 2048 / 2; skipButton.y = 150; game.addChild(skipButton); // Function to skip directly to backdrop scene function skipToBackdrop() { // Stop all tweens tween.stop(titleImage); tween.stop(flybyImage); // Remove title and flyby titleImage.destroy(); flybyImage.destroy(); skipButton.destroy(); // Add backdrop asset to game var backdropAsset = game.addChild(LK.getAsset('backdrop', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 1, scaleX: 0.5, scaleY: 0.5 })); // Add flyby asset to backdrop var backdropFlyby = game.addChild(LK.getAsset('Flyby', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 800, alpha: 1, scaleX: 0.8, scaleY: 0.8 })); // Store the original Y position for backdrop flyby var backdropFlybyOriginalY = backdropFlyby.y; // Make flyby move off the right side of backdrop scene tween(backdropFlyby, { x: 2048 + 375 }, { duration: 6000, easing: tween.linear, onFinish: function onFinish() { // After flyby has left the backdrop scene, fade in wave1 asset var wave1Asset = game.addChild(LK.getAsset('Wave1', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 })); // Fade in wave1 asset tween(wave1Asset, { alpha: 1 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { // Keep wave1 visible for 3 seconds then fade out LK.setTimeout(function () { tween(wave1Asset, { alpha: 0 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { wave1Asset.destroy(); // Start first wave of tower defense game startTowerDefenseWave1(); } }); }, 3000); } }); } }); // Add 6 horizontal guide lines immediately var lineSpacing = 2732 / 7; for (var i = 1; i <= 6; i++) { var yPosition = lineSpacing * i; if (i === 1) { yPosition += 600; // Move guideline 1 down by 600 pixels } else if (i === 2) { yPosition += 420; // Move guideline 2 down by 420 pixels } else if (i === 3) { yPosition += 250; // Move guideline 3 down by 250 pixels } else if (i === 4) { yPosition += 120; // Move guideline 4 down by 120 pixels } else if (i === 5) { yPosition -= 50; // Move guideline 5 up by 50 pixels } else if (i === 6) { yPosition -= 200; // Move guideline 6 up by 200 pixels } var guideLine = game.addChild(LK.getAsset('guideLine', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: yPosition, alpha: 0.5 })); } } // Add touch event to skip button skipButton.down = function (x, y, obj) { skipToBackdrop(); }; // Add flyby asset to title - start at right side of screen var flybyImage = game.addChild(LK.getAsset('Flyby', { anchorX: 0.5, anchorY: 0.5, x: 2048 + 375, y: 2732 / 2 + 1400 - 500 })); // Store the original Y position for flyby var flybyOriginalY = flybyImage.y; // Create hover animation function function startFlybyHover() { // Tween up 50 pixels over 2 seconds tween(flybyImage, { y: flybyOriginalY - 50 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Tween down 50 pixels over 2 seconds tween(flybyImage, { y: flybyOriginalY + 50 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Start the cycle again startFlybyHover(); } }); } }); } // Start the hover animation startFlybyHover(); // Start flyby movement from right to left tween(flybyImage, { x: -375 }, { duration: 8000, easing: tween.linear, onFinish: function onFinish() { // After flyby has left the screen, slowly scroll title up tween(titleImage, { y: titleImage.y - titleImage.height }, { duration: 20000, easing: tween.easeOut }); // Stop the title scrolling after 5 seconds LK.setTimeout(function () { tween.stop(titleImage, { y: true }); // Fade in intro asset in the middle of the screen var introAsset = game.addChild(LK.getAsset('intro', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 })); // Tween alpha from 0 to 1 for fade-in effect tween(introAsset, { alpha: 1 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // After intro has faded in, make flyby move from left to right flybyImage.x = -375; // Reset flyby to left side flybyImage.y = 2732 / 2; // Center vertically tween(flybyImage, { x: 2048 + 375 }, { duration: 6000, easing: tween.linear, onFinish: function onFinish() { // After flyby has left the screen, fade out intro and fade in backdrop tween(introAsset, { alpha: 0 }, { duration: 2000, easing: tween.easeInOut }); // Add backdrop asset to game var backdropAsset = game.addChild(LK.getAsset('backdrop', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0, scaleX: 0.5, scaleY: 0.5 })); // Add flyby asset to backdrop var backdropFlyby = game.addChild(LK.getAsset('Flyby', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 800, alpha: 0, scaleX: 0.8, scaleY: 0.8 })); // Store the original Y position for backdrop flyby var backdropFlybyOriginalY = backdropFlyby.y; // Make flyby move off the right side of backdrop scene function startBackdropFlybyHover() { tween(backdropFlyby, { x: 2048 + 375 }, { duration: 6000, easing: tween.linear, onFinish: function onFinish() { // After flyby has left the backdrop scene, fade in wave1 asset var wave1Asset = game.addChild(LK.getAsset('Wave1', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 })); // Fade in wave1 asset tween(wave1Asset, { alpha: 1 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { // Keep wave1 visible for 3 seconds then fade out LK.setTimeout(function () { tween(wave1Asset, { alpha: 0 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { wave1Asset.destroy(); // Start first wave of tower defense game startTowerDefenseWave1(); } }); }, 3000); } }); } }); } // Fade in backdrop tween(backdropAsset, { alpha: 1 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Fade in backdrop flyby tween(backdropFlyby, { alpha: 1 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Start flyby movement to right side after fade in startBackdropFlybyHover(); } }); // Add 6 horizontal guide lines after backdrop fades in var lineSpacing = 2732 / 7; // Divide screen height by 7 to get 6 lines with margins for (var i = 1; i <= 6; i++) { var yPosition = lineSpacing * i; if (i === 1) { yPosition += 600; // Move guideline 1 down by 600 pixels } else if (i === 2) { yPosition += 420; // Move guideline 2 down by 420 pixels } else if (i === 3) { yPosition += 250; // Move guideline 3 down by 250 pixels } else if (i === 4) { yPosition += 120; // Move guideline 4 down by 120 pixels } else if (i === 5) { yPosition -= 50; // Move guideline 5 up by 50 pixels } else if (i === 6) { yPosition -= 200; // Move guideline 6 up by 200 pixels } var guideLine = game.addChild(LK.getAsset('guideLine', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: yPosition, alpha: 0.5 })); } } }); } }); } }); }, 5000); } }); ;
===================================================================
--- original.js
+++ change.js
@@ -5,644 +5,28 @@
/****
* Classes
****/
-// AliencarEnemy class for level 2 wave 3
-var AliencarEnemy = Container.expand(function () {
+// Defense class
+var Defense = Container.expand(function () {
var self = Container.call(this);
- // Attach Aliencar as the main enemy graphic
- var aliencarGraphics = self.attachAsset('Aliencar', {
+ var defenseGraphics = self.attachAsset('defense', {
anchorX: 0.5,
anchorY: 0.5
});
- // Flashing lights removed from aliencar
- // Initialize aliencar properties
- self.speed = -3; // Fast movement speed
- self.health = 200; // High health for level 2
- self.maxHealth = 200;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // Add wheels to aliencar
- var aliencarWheel1 = self.attachAsset('Wheel', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -30,
- y: 125,
- scaleX: 0.6,
- scaleY: 0.6
- });
- var aliencarWheel2 = self.attachAsset('wheel2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 160,
- y: 125,
- scaleX: 0.6,
- scaleY: 0.6
- });
- // Store wheel references for animation
- self.wheel1 = aliencarWheel1;
- self.wheel2 = aliencarWheel2;
- // Add laser fire cooldown tracking
- self.lastLaserFireTime = 0;
- // Add number text
- self.numberText = new Text2('1', {
- size: 60,
- fill: 0x000000
- });
- self.numberText.anchor.set(0.5, 0.5);
- self.numberText.x = 0;
- self.numberText.y = 0;
- self.addChild(self.numberText);
- // Add health bar
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -250
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -250,
- tint: 0xff4400 // Orange health bar for aliencar enemies
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- healthBar.tint = 0xff4400; // Orange
- } else if (healthPercentage > 0.3) {
- healthBar.tint = 0xff6600; // Darker orange
- } else {
- healthBar.tint = 0xff0000; // Red
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- // Aliencar enemies don't have electric effect visuals
- };
- // Add laser fire back attack for aliencar when hit
- self.fireBackAtTower = function (attackingTower) {
- // Check if tower is on the same line as aliencar (within 50 pixels tolerance)
- if (Math.abs(attackingTower.y - self.y) > 50) {
- return; // Tower not on same line, don't fire
- }
- // Check if there are any towers blocking the line of sight to the attacking tower
- for (var i = 0; i < towers.length; i++) {
- var blockingTower = towers[i];
- if (blockingTower === attackingTower) continue; // Skip the target tower
- // Check if blocking tower is on the same line (within 50 pixels tolerance)
- if (Math.abs(blockingTower.y - self.y) > 50) continue;
- // Check if blocking tower is between aliencar and attacking tower
- if (blockingTower.x > self.x && blockingTower.x < attackingTower.x) {
- return; // Tower is blocked, don't fire
- }
- }
- // Check cooldown - fire every 40 ticks (0.67 seconds)
- if (LK.ticks - self.lastLaserFireTime < 40) {
- return; // Still in cooldown
- }
- self.lastLaserFireTime = LK.ticks;
- // Create laser fire back projectile
- var laser = game.addChild(LK.getAsset('Laserfire', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x - 200,
- y: self.y,
- alpha: 0.9,
- tint: 0xffa500 // Orange laser for aliencars
- }));
- // Calculate direction to attacking tower
- var deltaX = attackingTower.x - laser.x;
- var deltaY = attackingTower.y - laser.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 7;
- laser.velocityX = deltaX / distance * speed;
- laser.velocityY = deltaY / distance * speed;
- laser.damage = 25; // High damage for aliencar
- // Set initial rotation to point at tower
- var initialAngle = Math.atan2(deltaY, deltaX);
- laser.rotation = initialAngle;
- // Animate laser movement
- var laserInterval = LK.setInterval(function () {
- laser.x += laser.velocityX;
- laser.y += laser.velocityY;
- // Check if laser hit the attacking tower
- var laserDistance = Math.sqrt(Math.pow(laser.x - attackingTower.x, 2) + Math.pow(laser.y - attackingTower.y, 2));
- if (laserDistance < 100) {
- // Hit tower - deal damage
- attackingTower.takeDamage(laser.damage);
- LK.effects.flashObject(attackingTower, 0xff0000, 300);
- // Remove laser
- LK.clearInterval(laserInterval);
- laser.destroy();
- return;
- }
- // Check if laser went off screen
- if (laser.x > 2048 + 100 || laser.x < -100 || laser.y > 2732 + 100 || laser.y < -100) {
- LK.clearInterval(laserInterval);
- laser.destroy();
- }
- }, 16);
- };
self.update = function () {
- // Initialize lastX if not set
- if (self.lastX === undefined) self.lastX = self.x;
- // Update health bar
- self.updateHealthBar();
- // Rotate wheels based on movement
- if (self.wheel1) {
- tween(self.wheel1, {
- rotation: self.wheel1.rotation - Math.PI / 6
- }, {
- duration: 150,
- easing: tween.linear
- });
- }
- if (self.wheel2) {
- tween(self.wheel2, {
- rotation: self.wheel2.rotation - Math.PI / 6
- }, {
- duration: 150,
- easing: tween.linear
- });
- }
+ // Defense logic goes here
};
- return self;
});
-// Button class
-var Button = Container.expand(function () {
- var self = Container.call(this);
- // Button properties
- self.text = '';
- self.backgroundColor = 0x333333;
- self.textColor = 0xffffff;
- self.width = 200;
- self.height = 80;
- self.fontSize = 40;
- self.isPressed = false;
- // Create button background
- self.background = self.attachAsset('notification', {
- anchorX: 0.5,
- anchorY: 0.5,
- tint: self.backgroundColor
- });
- // Create button text
- self.buttonText = new Text2(self.text, {
- size: self.fontSize,
- fill: self.textColor
- });
- self.buttonText.anchor.set(0.5, 0.5);
- self.buttonText.x = 0;
- self.buttonText.y = 0;
- self.addChild(self.buttonText);
- // Method to set button properties
- self.setup = function (options) {
- if (options.text !== undefined) {
- self.text = options.text;
- self.buttonText.setText(self.text);
- }
- if (options.backgroundColor !== undefined) {
- self.backgroundColor = options.backgroundColor;
- self.background.tint = self.backgroundColor;
- }
- if (options.textColor !== undefined) {
- self.textColor = options.textColor;
- // Recreate text with new color since Text2 doesn't have a modifiable style property
- self.removeChild(self.buttonText);
- self.buttonText = new Text2(self.text, {
- size: self.fontSize,
- fill: self.textColor
- });
- self.buttonText.anchor.set(0.5, 0.5);
- self.buttonText.x = 0;
- self.buttonText.y = 0;
- self.addChild(self.buttonText);
- }
- if (options.width !== undefined) {
- self.width = options.width;
- self.background.width = self.width;
- }
- if (options.height !== undefined) {
- self.height = options.height;
- self.background.height = self.height;
- }
- if (options.fontSize !== undefined) {
- self.fontSize = options.fontSize;
- // Recreate text with new font size since Text2 doesn't have a modifiable style property
- self.removeChild(self.buttonText);
- self.buttonText = new Text2(self.text, {
- size: self.fontSize,
- fill: self.textColor
- });
- self.buttonText.anchor.set(0.5, 0.5);
- self.buttonText.x = 0;
- self.buttonText.y = 0;
- self.addChild(self.buttonText);
- }
- };
- // Touch down event
- self.down = function (x, y, obj) {
- self.isPressed = true;
- // Visual feedback - darken button
- self.background.alpha = 0.7;
- // Call custom down handler if defined
- if (self.onDown) {
- self.onDown(x, y, obj);
- }
- };
- // Touch up event
- self.up = function (x, y, obj) {
- if (self.isPressed) {
- self.isPressed = false;
- // Reset visual state
- self.background.alpha = 1.0;
- // Call custom up handler if defined
- if (self.onUp) {
- self.onUp(x, y, obj);
- }
- // Call click handler if defined
- if (self.onClick) {
- self.onClick(x, y, obj);
- }
- }
- };
- return self;
-});
-// Drone class for wave 2
-var Drone = Container.expand(function () {
- var self = Container.call(this);
- // Attach drone as the main enemy graphic
- var droneGraphics = self.attachAsset('Drone', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- // Add flashing lights to drone
- var droneLight1 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -30,
- y: 5,
- scaleX: 0.025,
- scaleY: 0.025,
- tint: 0xff0000,
- alpha: 0.6
- });
- var droneLight2 = self.attachAsset('squareLight', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 40,
- y: 0,
- scaleX: 0.7,
- scaleY: 0.7,
- tint: 0x00ff00,
- alpha: 0.6
- });
- var droneLight3 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -90,
- scaleX: 0.02,
- scaleY: 0.02,
- tint: 0x0000ff,
- alpha: 0.6
- });
- // Start flashing animations for drone lights
- function startDroneLightFlashing() {
- // Red light flashing
- tween(droneLight1, {
- alpha: 0.1
- }, {
- duration: 600,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(droneLight1, {
- alpha: 0.7
- }, {
- duration: 600,
- easing: tween.easeInOut,
- onFinish: startDroneLightFlashing
- });
- }
- });
- // Green light flashing (offset timing)
- LK.setTimeout(function () {
- tween(droneLight2, {
- alpha: 0.15
- }, {
- duration: 500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(droneLight2, {
- alpha: 0.7
- }, {
- duration: 500,
- easing: tween.easeInOut
- });
- }
- });
- }, 200);
- // Blue light flashing (different timing)
- LK.setTimeout(function () {
- tween(droneLight3, {
- alpha: 0.2
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(droneLight3, {
- alpha: 0.7
- }, {
- duration: 800,
- easing: tween.easeInOut
- });
- }
- });
- }, 400);
- }
- // Start the flashing animation
- startDroneLightFlashing();
- // Initialize drone properties
- self.speed = -2; // Same speed as probedroids
- self.health = 80; // Less health than probedroids
- self.maxHealth = 80;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // Add number text
- self.numberText = new Text2('1', {
- size: 60,
- fill: 0x000000
- });
- self.numberText.anchor.set(0.5, 0.5);
- self.numberText.x = 0;
- self.numberText.y = 0;
- self.addChild(self.numberText);
- // Add health bar
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -150
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -150,
- tint: 0x00ff00
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- healthBar.tint = 0xffff00; // Yellow
- } else {
- healthBar.tint = 0xff0000; // Red
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- // Drones don't have electric effect visuals like probedroids
- // This is implemented for consistency with tower interactions
- };
- // Add laser fire cooldown tracking
- self.lastLaserFireTime = 0;
- // Add laser fire back attack for drone when hit
- self.fireBackAtTower = function (attackingTower) {
- // Check if tower is on the same line as drone (within 50 pixels tolerance)
- if (Math.abs(attackingTower.y - self.y) > 50) {
- return; // Tower not on same line, don't fire
- }
- // Check if there are any towers blocking the line of sight to the attacking tower
- for (var i = 0; i < towers.length; i++) {
- var blockingTower = towers[i];
- if (blockingTower === attackingTower) continue; // Skip the target tower
- // Check if blocking tower is on the same line (within 50 pixels tolerance)
- if (Math.abs(blockingTower.y - self.y) > 50) continue;
- // Check if blocking tower is between drone and attacking tower
- if (blockingTower.x > self.x && blockingTower.x < attackingTower.x) {
- return; // Tower is blocked, don't fire
- }
- }
- // Check cooldown - fire every 45 ticks (0.75 seconds) instead of immediately
- if (LK.ticks - self.lastLaserFireTime < 45) {
- return; // Still in cooldown
- }
- self.lastLaserFireTime = LK.ticks;
- // Create laser fire back projectile
- var laser = game.addChild(LK.getAsset('Laserfire', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x - 200,
- y: self.y,
- alpha: 0.9,
- tint: 0xff0000 // Red laser for drones
- }));
- // Calculate direction to attacking tower
- var deltaX = attackingTower.x - laser.x;
- var deltaY = attackingTower.y - laser.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 6;
- laser.velocityX = deltaX / distance * speed;
- laser.velocityY = deltaY / distance * speed;
- laser.damage = 15; // Increased damage from 5 to 15
- // Set initial rotation to point at tower
- var initialAngle = Math.atan2(deltaY, deltaX);
- laser.rotation = initialAngle;
- // Animate laser movement
- var laserInterval = LK.setInterval(function () {
- laser.x += laser.velocityX;
- laser.y += laser.velocityY;
- // Check if laser hit the attacking tower
- var laserDistance = Math.sqrt(Math.pow(laser.x - attackingTower.x, 2) + Math.pow(laser.y - attackingTower.y, 2));
- if (laserDistance < 100) {
- // Hit tower - deal damage
- attackingTower.takeDamage(laser.damage);
- LK.effects.flashObject(attackingTower, 0xff0000, 300);
- // Remove laser
- LK.clearInterval(laserInterval);
- laser.destroy();
- return;
- }
- // Check if laser went off screen
- if (laser.x > 2048 + 100 || laser.x < -100 || laser.y > 2732 + 100 || laser.y < -100) {
- LK.clearInterval(laserInterval);
- laser.destroy();
- }
- }, 16);
- };
- self.update = function () {
- // Initialize lastX if not set
- if (self.lastX === undefined) self.lastX = self.x;
- // Update health bar
- self.updateHealthBar();
- };
- return self;
-});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
- // Attach probedroid as the main enemy graphic
- var enemyGraphics = self.attachAsset('Probedroid', {
+ var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
- anchorY: 0.5
- });
- // Add flashing lights to probe droid
- var light1 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
anchorY: 0.5,
- x: -25,
- y: -85,
- scaleX: 0.03,
- scaleY: 0.03,
- tint: 0xff0000,
- alpha: 0.5
+ scaleX: 0.3,
+ scaleY: 0.3
});
- var light2 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 50,
- y: -80,
- scaleX: 0.03,
- scaleY: 0.03,
- tint: 0x00ff00,
- alpha: 0.5
- });
- var light3 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -100,
- scaleX: 0.02,
- scaleY: 0.02,
- tint: 0x0000ff,
- alpha: 0.5
- });
- // Add electric effect to probe droid
- var electricEffect = self.attachAsset('Electriceffect', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -50,
- scaleX: 1.0,
- scaleY: 1.0,
- alpha: 0.7,
- visible: false
- });
- // Start flashing animations for the lights
- function startLightFlashing() {
- // Red light flashing
- tween(light1, {
- alpha: 0.1
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(light1, {
- alpha: 0.6
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: startLightFlashing
- });
- }
- });
- // Green light flashing (offset timing)
- LK.setTimeout(function () {
- tween(light2, {
- alpha: 0.1
- }, {
- duration: 600,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(light2, {
- alpha: 0.6
- }, {
- duration: 600,
- easing: tween.easeInOut
- });
- }
- });
- }, 300);
- // Blue light flashing (different timing)
- LK.setTimeout(function () {
- tween(light3, {
- alpha: 0.15
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(light3, {
- alpha: 0.6
- }, {
- duration: 1000,
- easing: tween.easeInOut
- });
- }
- });
- }, 600);
- }
- // Start the flashing animation
- startLightFlashing();
- // Start electric effect animation
- function startElectricEffect() {
- // Animate electric effect fading in and out
- tween(electricEffect, {
- alpha: 0.2
- }, {
- duration: 400,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(electricEffect, {
- alpha: 0.9
- }, {
- duration: 600,
- easing: tween.easeInOut,
- onFinish: startElectricEffect
- });
- }
- });
- }
- // Store electric effect reference
- self.electricEffect = electricEffect;
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- if (!self.electricEffectVisible) {
- self.electricEffectVisible = true;
- self.electricEffect.visible = true;
- }
- };
- // Start the electric effect animation
- startElectricEffect();
- // Initialize enemy properties
- self.speed = -2; // Default movement speed
- self.health = 100; // Default health
- self.maxHealth = 100; // Default max health
- self.pathLine = 1; // Default path line
- self.lastX = undefined; // Track last X position
- self.electricEffectVisible = false; // Track if electric effect is visible
// Add number text
self.numberText = new Text2('1', {
size: 60,
fill: 0x000000
@@ -655,15 +39,15 @@
var healthBarOutline = self.attachAsset('healthBarOutline', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
- y: -150
+ y: -100
});
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
- y: -150,
+ y: -100,
tint: 0x00ff00
});
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
@@ -691,1374 +75,20 @@
self.updateHealthBar();
};
return self;
});
-// FlyingalienEnemy class for level 2 wave 4
-var FlyingalienEnemy = Container.expand(function () {
+// Assets will be automatically created and loaded by the LK engine
+// Tower class
+var Tower = Container.expand(function () {
var self = Container.call(this);
- // Attach Flyingalien as the main enemy graphic
- var flyingalienGraphics = self.attachAsset('Flyingalien', {
+ var towerGraphics = self.attachAsset('tower', {
anchorX: 0.5,
anchorY: 0.5
});
- // Flashing lights removed from flyingalien
- // Initialize flyingalien properties
- self.speed = -4; // Fast movement speed
- self.health = 250; // High health for level 2
- self.maxHealth = 250;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // Add laser fire cooldown tracking
- self.lastLaserFireTime = 0;
- // Add number text
- self.numberText = new Text2('1', {
- size: 60,
- fill: 0x000000
- });
- self.numberText.anchor.set(0.5, 0.5);
- self.numberText.x = 0;
- self.numberText.y = 0;
- self.addChild(self.numberText);
- // Add health bar
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -270
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -270,
- tint: 0x00ff00 // Green health bar for flyingalien enemies
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- healthBar.tint = 0xffff00; // Yellow
- } else {
- healthBar.tint = 0xff0000; // Red
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- // Flyingalien enemies don't have electric effect visuals
- };
- // Add autonomous fireball shooting for flying aliens
- self.shootFireballAtTowers = function () {
- // Check cooldown - fire every 120 ticks (2 seconds)
- if (LK.ticks - self.lastLaserFireTime < 120) {
- return; // Still in cooldown
- }
- // Find all towers in range
- var validTargets = [];
- for (var i = 0; i < towers.length; i++) {
- var tower = towers[i];
- if (tower.health > 0) {
- var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
- if (distance < 1000) {
- // Within 1000 pixel range
- validTargets.push(tower);
- }
- }
- }
- // If we have valid targets, shoot at the closest one
- if (validTargets.length > 0) {
- // Find closest tower
- var closestTower = validTargets[0];
- var closestDistance = Math.sqrt(Math.pow(closestTower.x - self.x, 2) + Math.pow(closestTower.y - self.y, 2));
- for (var i = 1; i < validTargets.length; i++) {
- var tower = validTargets[i];
- var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
- if (distance < closestDistance) {
- closestTower = tower;
- closestDistance = distance;
- }
- }
- self.lastLaserFireTime = LK.ticks;
- // Play fireball sound
- LK.getSound('Fireball').play();
- // Create small fireball projectile
- var fireball = game.addChild(LK.getAsset('Fireball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x,
- y: self.y,
- scaleX: 0.3,
- // Small fireball
- scaleY: 0.3,
- alpha: 0.9,
- rotation: Math.random() * Math.PI * 2 // Random rotation
- }));
- fireball.createdTime = LK.ticks;
- // Calculate direction to target tower
- var deltaX = closestTower.x - fireball.x;
- var deltaY = closestTower.y - fireball.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 6; // Moderate speed
- fireball.velocityX = deltaX / distance * speed;
- fireball.velocityY = deltaY / distance * speed;
- fireball.damage = 20; // Moderate damage
- // Animate fireball movement
- var fireballInterval = LK.setInterval(function () {
- fireball.x += fireball.velocityX;
- fireball.y += fireball.velocityY;
- // Rotate fireball while flying
- fireball.rotation += 0.2;
- // Check if fireball hit the target tower
- var fireballDistance = Math.sqrt(Math.pow(fireball.x - closestTower.x, 2) + Math.pow(fireball.y - closestTower.y, 2));
- if (fireballDistance < 80) {
- // Hit tower - deal damage
- closestTower.takeDamage(fireball.damage);
- LK.effects.flashObject(closestTower, 0xff0000, 300);
- // Create small explosion effect
- var explosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fireball.x,
- y: fireball.y,
- scaleX: 0.2,
- scaleY: 0.2
- }));
- // Animate explosion
- tween(explosion, {
- scaleX: 0.5,
- scaleY: 0.5,
- alpha: 0
- }, {
- duration: 400,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- explosion.destroy();
- }
- });
- // Remove fireball
- LK.clearInterval(fireballInterval);
- fireball.destroy();
- return;
- }
- // Check if fireball went off screen
- if (fireball.x > 2048 + 100 || fireball.x < -100 || fireball.y > 2732 + 100 || fireball.y < -100) {
- LK.clearInterval(fireballInterval);
- fireball.destroy();
- }
- }, 16);
- }
- };
- // Add laser fire back attack for flyingalien when hit
- self.fireBackAtTower = function (attackingTower) {
- // Check if tower is on the same line as flyingalien (within 50 pixels tolerance)
- if (Math.abs(attackingTower.y - self.y) > 50) {
- return; // Tower not on same line, don't fire
- }
- // Check if there are any towers blocking the line of sight to the attacking tower
- for (var i = 0; i < towers.length; i++) {
- var blockingTower = towers[i];
- if (blockingTower === attackingTower) continue; // Skip the target tower
- // Check if blocking tower is on the same line (within 50 pixels tolerance)
- if (Math.abs(blockingTower.y - self.y) > 50) continue;
- // Check if blocking tower is between flyingalien and attacking tower
- if (blockingTower.x > self.x && blockingTower.x < attackingTower.x) {
- return; // Tower is blocked, don't fire
- }
- }
- // Check cooldown - fire every 35 ticks (0.58 seconds)
- if (LK.ticks - self.lastLaserFireTime < 35) {
- return; // Still in cooldown
- }
- self.lastLaserFireTime = LK.ticks;
- // Create laser fire back projectile
- var laser = game.addChild(LK.getAsset('Laserfire', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x - 200,
- y: self.y,
- alpha: 0.9,
- tint: 0x00ff00 // Green laser for flyingaliens
- }));
- // Calculate direction to attacking tower
- var deltaX = attackingTower.x - laser.x;
- var deltaY = attackingTower.y - laser.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 8;
- laser.velocityX = deltaX / distance * speed;
- laser.velocityY = deltaY / distance * speed;
- laser.damage = 30; // High damage for flyingalien
- // Set initial rotation to point at tower
- var initialAngle = Math.atan2(deltaY, deltaX);
- laser.rotation = initialAngle;
- // Animate laser movement
- var laserInterval = LK.setInterval(function () {
- laser.x += laser.velocityX;
- laser.y += laser.velocityY;
- // Check if laser hit the attacking tower
- var laserDistance = Math.sqrt(Math.pow(laser.x - attackingTower.x, 2) + Math.pow(laser.y - attackingTower.y, 2));
- if (laserDistance < 100) {
- // Hit tower - deal damage
- attackingTower.takeDamage(laser.damage);
- LK.effects.flashObject(attackingTower, 0xff0000, 300);
- // Remove laser
- LK.clearInterval(laserInterval);
- laser.destroy();
- return;
- }
- // Check if laser went off screen
- if (laser.x > 2048 + 100 || laser.x < -100 || laser.y > 2732 + 100 || laser.y < -100) {
- LK.clearInterval(laserInterval);
- laser.destroy();
- }
- }, 16);
- };
self.update = function () {
- // Initialize lastX if not set
- if (self.lastX === undefined) self.lastX = self.x;
- // Update health bar
- self.updateHealthBar();
- // Shoot fireballs at towers autonomously
- self.shootFireballAtTowers();
- // Initialize floating animation if not already started
- if (!self.floatingInitialized) {
- // Create floating animation function
- var _startFloatingAnimation = function startFloatingAnimation() {
- // Float up 30 pixels over 2 seconds
- tween(self, {
- y: self.originalY - 30
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Float down 30 pixels over 2 seconds
- tween(self, {
- y: self.originalY + 30
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Update original Y to current position for smooth continuation
- self.originalY = self.y;
- // Continue the floating cycle
- _startFloatingAnimation();
- }
- });
- }
- });
- }; // Start the floating animation
- self.floatingInitialized = true;
- self.originalY = self.y;
- _startFloatingAnimation();
- }
+ // Tower logic goes here
};
- return self;
});
-// Level2Enemy class for level 2 waves - uses 1,2,3,4 assets with switching visibility
-var Level2Enemy = Container.expand(function () {
- var self = Container.call(this);
- // Attach all 4 enemy graphics, initially hidden
- var enemy1 = self.attachAsset('1', {
- anchorX: 0.5,
- anchorY: 0.5,
- visible: true,
- tint: 0x606060
- });
- var enemy2 = self.attachAsset('2', {
- anchorX: 0.5,
- anchorY: 0.5,
- visible: false,
- tint: 0x606060
- });
- var enemy3 = self.attachAsset('3', {
- anchorX: 0.5,
- anchorY: 0.5,
- visible: false,
- tint: 0x606060
- });
- var enemy4 = self.attachAsset('4', {
- anchorX: 0.5,
- anchorY: 0.5,
- visible: false,
- tint: 0x606060
- });
- // Add alien head as a fixed visual element (always visible)
- var alienHead = self.attachAsset('Alien', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 15,
- y: -95
- });
- // Store references to all graphics
- self.enemyGraphics = [enemy1, enemy2, enemy3, enemy4];
- self.currentGraphicIndex = 0;
- // Add laser fire cooldown tracking
- self.lastLaserFireTime = 0;
- // Start visibility switching animation
- function startVisibilitySwitching() {
- // Switch every 0.3 seconds (18 ticks at 60fps)
- LK.setInterval(function () {
- if (self.parent) {
- // Hide current graphic
- self.enemyGraphics[self.currentGraphicIndex].visible = false;
- // Move to next graphic
- self.currentGraphicIndex = (self.currentGraphicIndex + 1) % 4;
- // Show next graphic
- self.enemyGraphics[self.currentGraphicIndex].visible = true;
- }
- }, 300); // 0.3 seconds
- }
- startVisibilitySwitching();
- // Initialize enemy properties - extremely strong health for level 2
- self.speed = -1.2; // Even slower but more persistent movement
- self.health = 1000; // Extremely high health - extremely hard to kill
- self.maxHealth = 1000;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // Add number text
- self.numberText = new Text2('1', {
- size: 60,
- fill: 0x000000
- });
- self.numberText.anchor.set(0.5, 0.5);
- self.numberText.x = 0;
- self.numberText.y = 0;
- self.addChild(self.numberText);
- // Add health bar
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -300
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -300,
- tint: 0xff0000 // Red health bar for level 2 enemies
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage;
- // Change color based on health - darker colors for stronger enemy
- if (healthPercentage > 0.7) {
- healthBar.tint = 0x800000; // Dark red
- } else if (healthPercentage > 0.4) {
- healthBar.tint = 0xcc0000; // Medium red
- } else {
- healthBar.tint = 0x660000; // Very dark red
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- // Level 2 enemies don't have electric effect visuals
- };
- // Add laser fire method for Level2Enemy when assets 1,2 are visible
- self.fireAtTowers = function () {
- // Only shoot when asset 1 or 2 is visible (index 0 or 1)
- if (self.currentGraphicIndex !== 0 && self.currentGraphicIndex !== 1) {
- return; // Don't fire when assets 3 or 4 are visible
- }
- // Check cooldown - fire every 90 ticks (1.5 seconds)
- if (LK.ticks - self.lastLaserFireTime < 90) {
- return; // Still in cooldown
- }
- // Find towers to shoot at
- var validTargets = [];
- for (var i = 0; i < towers.length; i++) {
- var tower = towers[i];
- if (tower.health > 0) {
- // Check if tower is on the same line or adjacent lines
- var lineDifference = Math.abs(tower.y - self.y);
- if (lineDifference < 200) {
- // Within shooting range
- // Check if tower is to the left of the enemy (in shooting direction)
- if (tower.x < self.x) {
- validTargets.push(tower);
- }
- }
- }
- }
- // If we have valid targets, shoot at the closest one
- if (validTargets.length > 0) {
- // Find closest tower
- var closestTower = validTargets[0];
- var closestDistance = Math.sqrt(Math.pow(closestTower.x - self.x, 2) + Math.pow(closestTower.y - self.y, 2));
- for (var i = 1; i < validTargets.length; i++) {
- var tower = validTargets[i];
- var distance = Math.sqrt(Math.pow(tower.x - self.x, 2) + Math.pow(tower.y - self.y, 2));
- if (distance < closestDistance) {
- closestTower = tower;
- closestDistance = distance;
- }
- }
- self.lastLaserFireTime = LK.ticks;
- // Create laser fire projectile
- var laser = game.addChild(LK.getAsset('Laserfire', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x - 100,
- y: self.y - 20,
- alpha: 0.9,
- tint: 0x00ff00 // Green laser for Level2Enemy
- }));
- // Calculate direction to target tower
- var deltaX = closestTower.x - laser.x;
- var deltaY = closestTower.y - laser.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 8; // Fast laser speed
- laser.velocityX = deltaX / distance * speed;
- laser.velocityY = deltaY / distance * speed;
- laser.damage = 50; // Very high damage for level 2 enemies - more powerful
- // Set initial rotation to point at tower
- var initialAngle = Math.atan2(deltaY, deltaX);
- laser.rotation = initialAngle;
- // Animate laser movement
- var laserInterval = LK.setInterval(function () {
- laser.x += laser.velocityX;
- laser.y += laser.velocityY;
- // Check if laser hit the target tower
- var laserDistance = Math.sqrt(Math.pow(laser.x - closestTower.x, 2) + Math.pow(laser.y - closestTower.y, 2));
- if (laserDistance < 100) {
- // Hit tower - deal damage
- closestTower.takeDamage(laser.damage);
- // Check if tower is destroyed and create explosive effect
- if (closestTower.health <= 0) {
- // Create explosive effect when level2 enemy laser destroys a tower
- var towerExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: closestTower.x,
- y: closestTower.y,
- scaleX: 0.4,
- scaleY: 0.4
- }));
- // Animate explosion with tween
- tween(towerExplosion, {
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0
- }, {
- duration: 1200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- towerExplosion.destroy();
- }
- });
- }
- LK.effects.flashObject(closestTower, 0xff0000, 500);
- // Remove laser
- LK.clearInterval(laserInterval);
- laser.destroy();
- return;
- }
- // Check if laser went off screen
- if (laser.x > 2048 + 100 || laser.x < -100 || laser.y > 2732 + 100 || laser.y < -100) {
- LK.clearInterval(laserInterval);
- laser.destroy();
- }
- }, 16);
- }
- };
- self.update = function () {
- // Initialize lastX if not set
- if (self.lastX === undefined) self.lastX = self.x;
- // Update health bar
- self.updateHealthBar();
- // Fire lasers when assets 1,2 are visible
- self.fireAtTowers();
- // Alien head walking animation - initialize walking properties
- if (!self.walkingInitialized) {
- self.walkingInitialized = true;
- self.walkingTimer = 0;
- self.walkingDirection = 1; // 1 for right, -1 for left
- self.isPaused = false;
- self.pauseTimer = 0;
- self.alienHeadBaseX = alienHead.x; // Store original position
- }
- // Update walking timer
- self.walkingTimer++;
- self.pauseTimer++;
- // Check if we need to pause (every 0.4 seconds = 24 ticks)
- if (!self.isPaused && self.walkingTimer >= 24) {
- self.isPaused = true;
- self.pauseTimer = 0;
- self.walkingTimer = 0;
- }
- // Check if pause duration is complete (0.3 seconds = 18 ticks)
- if (self.isPaused && self.pauseTimer >= 18) {
- self.isPaused = false;
- self.pauseTimer = 0;
- self.walkingTimer = 0;
- // Switch direction
- self.walkingDirection *= -1;
- }
- // Apply walking movement when not paused
- if (!self.isPaused) {
- // Check if asset 3 is currently visible
- var asset3Visible = self.currentGraphicIndex === 2; // Asset 3 is at index 2
- var targetX;
- if (asset3Visible) {
- // When asset 3 is visible, always move left
- targetX = self.alienHeadBaseX - 5;
- } else {
- // Normal walking animation with direction switching
- targetX = self.alienHeadBaseX + self.walkingDirection * 5;
- }
- // Smoothly animate to target position
- tween(alienHead, {
- x: targetX
- }, {
- duration: 100,
- easing: tween.linear
- });
- }
- };
- return self;
-});
-// Robot class for wave 3
-var Robot = Container.expand(function () {
- var self = Container.call(this);
- // Attach robot as the main enemy graphic
- var robotGraphics = self.attachAsset('Robot', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- // Add wheel to robot
- var wheel = self.attachAsset('Wheel', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -25,
- y: 100,
- scaleX: 0.8,
- scaleY: 0.8
- });
- // Add second wheel to robot
- var wheel2 = self.attachAsset('wheel2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 25,
- y: 100,
- scaleX: 0.8,
- scaleY: 0.8
- });
- // Add roboarm to robot
- var roboarm = self.attachAsset('Roboarm', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -5,
- y: 0,
- scaleX: 0.6,
- scaleY: 0.6
- });
- // Initialize robot properties
- self.speed = -6; // Faster speed
- self.health = 120; // High health
- self.maxHealth = 120;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // Add health bar
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -200
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -200,
- tint: 0x00ff00
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage;
- if (healthPercentage > 0.6) {
- healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- healthBar.tint = 0xffff00; // Yellow
- } else {
- healthBar.tint = 0xff0000; // Red
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Add showElectricEffect function for wave 3 robots
- self.showElectricEffect = function () {
- // Wave 3 robots don't have electric effect visuals, so this is a no-op
- };
- // Add laser fire cooldown tracking
- self.lastLaserFireTime = 0;
- // Add laser fire back attack for robot when hit
- self.fireBackAtTower = function (attackingTower) {
- // Check if tower is on the same line as robot (within 50 pixels tolerance)
- if (Math.abs(attackingTower.y - self.y) > 50) {
- return; // Tower not on same line, don't fire
- }
- // Check if there are any towers blocking the line of sight to the attacking tower
- for (var i = 0; i < towers.length; i++) {
- var blockingTower = towers[i];
- if (blockingTower === attackingTower) continue; // Skip the target tower
- // Check if blocking tower is on the same line (within 50 pixels tolerance)
- if (Math.abs(blockingTower.y - self.y) > 50) continue;
- // Check if blocking tower is between robot and attacking tower
- if (blockingTower.x > self.x && blockingTower.x < attackingTower.x) {
- return; // Tower is blocked, don't fire
- }
- }
- // Check cooldown - fire every 30 ticks (0.5 seconds) instead of immediately
- if (LK.ticks - self.lastLaserFireTime < 30) {
- return; // Still in cooldown
- }
- self.lastLaserFireTime = LK.ticks;
- // Create laser fire back projectile
- var laser = game.addChild(LK.getAsset('Laserfire', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x - 200,
- y: self.y,
- alpha: 0.9,
- tint: 0x00ff00 // Green laser for robots
- }));
- // Calculate direction to attacking tower
- var deltaX = attackingTower.x - laser.x;
- var deltaY = attackingTower.y - laser.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 6;
- laser.velocityX = deltaX / distance * speed;
- laser.velocityY = deltaY / distance * speed;
- laser.damage = 15; // Increased damage from 5 to 15
- // Set initial rotation to point at tower
- var initialAngle = Math.atan2(deltaY, deltaX);
- laser.rotation = initialAngle;
- // Animate laser movement
- var laserInterval = LK.setInterval(function () {
- laser.x += laser.velocityX;
- laser.y += laser.velocityY;
- // Update laser rotation to continuously point at tower
- var currentDeltaX = attackingTower.x - laser.x;
- var currentDeltaY = attackingTower.y - laser.y;
- var currentAngle = Math.atan2(currentDeltaY, currentDeltaX);
- // Animate rotation change smoothly
- tween(laser, {
- rotation: currentAngle
- }, {
- duration: 100,
- easing: tween.easeOut
- });
- // Check if laser hit the attacking tower
- var laserDistance = Math.sqrt(Math.pow(laser.x - attackingTower.x, 2) + Math.pow(laser.y - attackingTower.y, 2));
- if (laserDistance < 100) {
- // Hit tower - deal damage
- attackingTower.takeDamage(laser.damage);
- LK.effects.flashObject(attackingTower, 0xff0000, 300);
- // Remove laser
- LK.clearInterval(laserInterval);
- laser.destroy();
- return;
- }
- // Check if laser went off screen
- if (laser.x > 2048 + 100 || laser.x < -100 || laser.y > 2732 + 100 || laser.y < -100) {
- LK.clearInterval(laserInterval);
- laser.destroy();
- }
- }, 16);
- };
- self.update = function () {
- if (self.lastX === undefined) self.lastX = self.x;
- self.updateHealthBar();
- // Rotate wheel slowly anticlockwise
- if (wheel) {
- tween(wheel, {
- rotation: wheel.rotation - Math.PI / 8
- }, {
- duration: 200,
- easing: tween.linear
- });
- }
- // Rotate second wheel slowly anticlockwise
- if (wheel2) {
- tween(wheel2, {
- rotation: wheel2.rotation - Math.PI / 8
- }, {
- duration: 200,
- easing: tween.linear
- });
- }
- };
- return self;
-});
-// SpaceDrone class for wave 4
-var SpaceDrone = Container.expand(function () {
- var self = Container.call(this);
- // Attach SpaceDrone as the main enemy graphic
- var spaceDroneGraphics = self.attachAsset('SpaceDrone', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- // Add flashing lights to space drone
- var droneLight1 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -40,
- y: 10,
- scaleX: 0.03,
- scaleY: 0.03,
- tint: 0xff0000,
- alpha: 0.7
- });
- var droneLight2 = self.attachAsset('squareLight', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 50,
- y: 5,
- scaleX: 0.8,
- scaleY: 0.8,
- tint: 0x00ff00,
- alpha: 0.7
- });
- var droneLight3 = self.attachAsset('rangeCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -80,
- scaleX: 0.025,
- scaleY: 0.025,
- tint: 0x0000ff,
- alpha: 0.7
- });
- // Start flashing animations for space drone lights
- function startSpaceDroneLightFlashing() {
- // Red light flashing
- tween(droneLight1, {
- alpha: 0.2
- }, {
- duration: 500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(droneLight1, {
- alpha: 0.8
- }, {
- duration: 500,
- easing: tween.easeInOut,
- onFinish: startSpaceDroneLightFlashing
- });
- }
- });
- // Green light flashing (offset timing)
- LK.setTimeout(function () {
- tween(droneLight2, {
- alpha: 0.2
- }, {
- duration: 400,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(droneLight2, {
- alpha: 0.8
- }, {
- duration: 400,
- easing: tween.easeInOut
- });
- }
- });
- }, 150);
- // Blue light flashing (different timing)
- LK.setTimeout(function () {
- tween(droneLight3, {
- alpha: 0.3
- }, {
- duration: 700,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(droneLight3, {
- alpha: 0.8
- }, {
- duration: 700,
- easing: tween.easeInOut
- });
- }
- });
- }, 300);
- }
- // Start the flashing animation
- startSpaceDroneLightFlashing();
- // Initialize space drone properties
- self.speed = -4; // Increased speed from -3 to -4 (faster)
- self.health = 150; // Higher health than previous enemies
- self.maxHealth = 150;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // Add rotation properties
- self.rotationTimer = 0;
- self.isRotating = false;
- self.rotationStartTime = 0;
- // Add number text
- self.numberText = new Text2('1', {
- size: 60,
- fill: 0x000000
- });
- self.numberText.anchor.set(0.5, 0.5);
- self.numberText.x = 0;
- self.numberText.y = 0;
- self.addChild(self.numberText);
- // Add longer health bar for SpaceDrone
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -130,
- scaleX: 1.5,
- // Make health bar longer
- scaleY: 1.2 // Make health bar slightly taller
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -130,
- tint: 0x00ff00,
- scaleX: 1.5,
- // Make health bar longer
- scaleY: 1.2 // Make health bar slightly taller
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage * 1.5; // Maintain longer scale
- // Change color based on health
- if (healthPercentage > 0.6) {
- healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- healthBar.tint = 0xffff00; // Yellow
- } else {
- healthBar.tint = 0xff0000; // Red
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- // SpaceDrones don't have electric effect visuals like probedroids
- // This is implemented for consistency with tower interactions
- };
- // Add laser fire cooldown tracking
- self.lastLaserFireTime = 0;
- // Add laser fire back attack for SpaceDrone when hit
- self.fireBackAtTower = function (attackingTower) {
- // Check if tower is on the same line as SpaceDrone (within 50 pixels tolerance)
- if (Math.abs(attackingTower.y - self.y) > 50) {
- return; // Tower not on same line, don't fire
- }
- // Check if there are any towers blocking the line of sight to the attacking tower
- for (var i = 0; i < towers.length; i++) {
- var blockingTower = towers[i];
- if (blockingTower === attackingTower) continue; // Skip the target tower
- // Check if blocking tower is on the same line (within 50 pixels tolerance)
- if (Math.abs(blockingTower.y - self.y) > 50) continue;
- // Check if blocking tower is between SpaceDrone and attacking tower
- if (blockingTower.x > self.x && blockingTower.x < attackingTower.x) {
- return; // Tower is blocked, don't fire
- }
- }
- // Check cooldown - fire every 30 ticks (0.5 seconds) instead of immediately
- if (LK.ticks - self.lastLaserFireTime < 30) {
- return; // Still in cooldown
- }
- self.lastLaserFireTime = LK.ticks;
- // Create laser fire back projectile
- var laser = game.addChild(LK.getAsset('Laserfire', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: self.x - 200,
- y: self.y,
- alpha: 0.9,
- tint: 0x0000ff // Blue laser for SpaceDrones
- }));
- // Calculate direction to attacking tower
- var deltaX = attackingTower.x - laser.x;
- var deltaY = attackingTower.y - laser.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var speed = 7; // Slightly faster than other enemies
- laser.velocityX = deltaX / distance * speed;
- laser.velocityY = deltaY / distance * speed;
- laser.damage = 20; // Increased damage from 8 to 20
- // Set initial rotation to point at tower
- var initialAngle = Math.atan2(deltaY, deltaX);
- laser.rotation = initialAngle;
- // Animate laser movement
- var laserInterval = LK.setInterval(function () {
- laser.x += laser.velocityX;
- laser.y += laser.velocityY;
- // Update laser rotation to continuously point at tower
- var currentDeltaX = attackingTower.x - laser.x;
- var currentDeltaY = attackingTower.y - laser.y;
- var currentAngle = Math.atan2(currentDeltaY, currentDeltaX);
- // Animate rotation change smoothly
- tween(laser, {
- rotation: currentAngle
- }, {
- duration: 100,
- easing: tween.easeOut
- });
- // Check if laser hit the attacking tower
- var laserDistance = Math.sqrt(Math.pow(laser.x - attackingTower.x, 2) + Math.pow(laser.y - attackingTower.y, 2));
- if (laserDistance < 100) {
- // Hit tower - deal damage
- attackingTower.takeDamage(laser.damage);
- LK.effects.flashObject(attackingTower, 0xff0000, 300);
- // Remove laser
- LK.clearInterval(laserInterval);
- laser.destroy();
- return;
- }
- // Check if laser went off screen
- if (laser.x > 2048 + 100 || laser.x < -100 || laser.y > 2732 + 100 || laser.y < -100) {
- LK.clearInterval(laserInterval);
- laser.destroy();
- }
- }, 16);
- };
- self.update = function () {
- // Initialize lastX if not set
- if (self.lastX === undefined) self.lastX = self.x;
- // Update health bar
- self.updateHealthBar();
- // Handle rotation every 3 seconds
- self.rotationTimer += gameSpeed;
- if (self.rotationTimer >= 180 && !self.isRotating) {
- // 3 seconds at 60fps
- self.isRotating = true;
- self.rotationStartTime = LK.ticks;
- self.rotationTimer = 0;
- // Start 180 degree rotation
- tween(spaceDroneGraphics, {
- rotation: spaceDroneGraphics.rotation + Math.PI
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- self.isRotating = false;
- }
- });
- }
- };
- return self;
-});
-// UFO boss class for wave 5
-var UFO = Container.expand(function () {
- var self = Container.call(this);
- // Attach UFO as the main boss graphic
- var ufoGraphics = self.attachAsset('UFO', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- // Add blowing asset (initially invisible)
- var blowingEffect = self.attachAsset('Blowing', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: 100,
- scaleX: 0.8,
- scaleY: 0.8,
- alpha: 0.8,
- visible: false
- });
- // Store blowing effect reference
- self.blowingEffect = blowingEffect;
- // Initialize UFO boss properties
- self.speed = -1; // Slow movement speed
- self.health = 1200; // High health - takes around 120 hits to kill
- self.maxHealth = 1200;
- self.pathLine = 1;
- self.lastX = undefined;
- self.electricEffectVisible = false;
- // UFO specific properties
- self.hoverTarget = null; // Currently targeted tower
- self.isHovering = false; // Is UFO hovering over a tower
- self.hoverStartTime = 0; // When hovering started
- self.pauseTimer = 0; // Timer for initial pause
- self.hasPaused = false; // Has UFO completed initial pause
- self.abductionTimer = 0; // Timer for tower abduction
- self.isAbducting = false; // Is UFO currently abducting a tower
- self.allTowersDefeatedTime = null; // Timer for 3-second wait after defeating all towers
- // Add number text
- self.numberText = new Text2('', {
- size: 80,
- fill: 0xff0000
- });
- self.numberText.anchor.set(0.5, 0.5);
- self.numberText.x = 0;
- self.numberText.y = 0;
- self.addChild(self.numberText);
- // Add much longer health bar for UFO boss
- var healthBarOutline = self.attachAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -200,
- scaleX: 4.0,
- // Make health bar much longer
- scaleY: 2.0 // Make health bar taller
- });
- var healthBar = self.attachAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: -200,
- tint: 0xff0000,
- // Red health bar for boss
- scaleX: 4.0,
- // Make health bar much longer
- scaleY: 2.0 // Make health bar taller
- });
- self.updateHealthBar = function () {
- var healthPercentage = self.health / self.maxHealth;
- healthBar.scaleX = healthPercentage * 4.0; // Maintain longer scale
- // Change color based on health
- if (healthPercentage > 0.6) {
- healthBar.tint = 0xff0000; // Red
- } else if (healthPercentage > 0.3) {
- healthBar.tint = 0xff8800; // Orange
- } else {
- healthBar.tint = 0xff4400; // Dark orange
- }
- };
- self.takeDamage = function (damage) {
- self.health -= damage;
- if (self.health <= 0) {
- self.health = 0;
- }
- self.updateHealthBar();
- };
- // Function to select random tower to hover over
- self.selectRandomTower = function () {
- // Filter for towers with health > 0
- var validTowers = [];
- for (var i = 0; i < towers.length; i++) {
- if (towers[i].health > 0) {
- validTowers.push(towers[i]);
- }
- }
- if (validTowers.length === 0) return null;
- var randomIndex = Math.floor(Math.random() * validTowers.length);
- return validTowers[randomIndex];
- };
- // Function to start tower abduction
- self.startAbduction = function (tower) {
- if (!tower || tower.health <= 0) return;
- self.isAbducting = true;
- self.abductionTimer = 0;
- self.blowingEffect.visible = true;
- // Position UFO on the same row as the tower for abduction
- self.pathLine = tower.pathLine || 1; // Use tower's line or default to line 1
- // Position blowing effect over the tower
- self.blowingEffect.x = 0; // Relative to UFO position
- self.blowingEffect.y = 150; // Below UFO
- // Make blowing effect more transparent for better tower visibility
- self.blowingEffect.alpha = 0.3;
- // Ensure blowing effect renders in front of towers by re-adding to game
- game.removeChild(self.blowingEffect);
- game.addChild(self.blowingEffect);
- // Update blowing effect position relative to UFO during abduction
- var updateBlowingPosition = function updateBlowingPosition() {
- if (self.blowingEffect.visible && self.isAbducting) {
- self.blowingEffect.x = self.x;
- self.blowingEffect.y = self.y + 150;
- }
- };
- // Start position update interval
- var positionInterval = LK.setInterval(updateBlowingPosition, 16);
- // Add pulsing effect to blowing asset to enhance tractor beam look
- var _pulseBlowingEffect = function pulseBlowingEffect() {
- if (self.blowingEffect.visible && self.isAbducting) {
- tween(self.blowingEffect, {
- alpha: 0.15,
- scaleX: 0.9,
- scaleY: 0.9
- }, {
- duration: 300,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- if (self.blowingEffect.visible && self.isAbducting) {
- tween(self.blowingEffect, {
- alpha: 0.3,
- scaleX: 0.8,
- scaleY: 0.8
- }, {
- duration: 300,
- easing: tween.easeInOut,
- onFinish: _pulseBlowingEffect
- });
- }
- }
- });
- }
- };
- // Start pulsing effect
- _pulseBlowingEffect();
- // Animate tower being sucked up into UFO
- tween(tower, {
- y: tower.y - 200,
- scaleX: 0.5,
- scaleY: 0.5,
- alpha: 0.3
- }, {
- duration: 2000,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- // Clear position update interval
- LK.clearInterval(positionInterval);
- // Remove tower completely after abduction
- // Play explosion sound when tower is destroyed by UFO abduction
- LK.getSound('Explosion').play();
- // Create explosion effect when tower is destroyed by UFO abduction
- var ufoTowerExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: tower.x,
- y: tower.y,
- scaleX: 0.4,
- scaleY: 0.4
- }));
- // Animate explosion with tween
- tween(ufoTowerExplosion, {
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0
- }, {
- duration: 1200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- ufoTowerExplosion.destroy();
- }
- });
- // Remove health bar components
- if (tower.healthBarOutline) {
- tower.healthBarOutline.destroy();
- }
- if (tower.healthBar) {
- tower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (tower.blades) {
- tower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (tower.plasma) {
- tower.plasma.destroy();
- }
- // Remove tower from game and towers array
- tower.destroy();
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === tower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Hide blowing effect after abduction
- self.blowingEffect.visible = false;
- self.isAbducting = false;
- self.isHovering = false;
- self.hoverTarget = null;
- // Resume UFO movement after abduction is complete
- if (towers.length === 0) {
- self.speed = -1; // Resume movement toward goal if no towers left
- }
- }
- });
- };
- // Function to make electric effect visible
- self.showElectricEffect = function () {
- // UFOs don't have electric effect visuals like other enemies
- // This is implemented for consistency with tower interactions
- };
- self.update = function () {
- // Initialize lastX if not set
- if (self.lastX === undefined) self.lastX = self.x;
- // Update health bar
- self.updateHealthBar();
- // Get count of valid towers (towers with health > 0)
- var validTowerCount = 0;
- for (var i = 0; i < towers.length; i++) {
- if (towers[i].health > 0) {
- validTowerCount++;
- }
- }
- // Stop UFO movement when abducting towers or hovering
- if (self.isAbducting || self.isHovering) {
- self.speed = 0; // Stop horizontal movement during abduction/hovering
- }
- // Check if UFO has reached the goal (left side of screen)
- if (self.lastX >= 0 && self.x < 0) {
- // UFO reached goal - check if all valid towers have been abducted
- if (validTowerCount > 0) {
- // There are still valid towers, UFO cannot win yet
- // Push UFO back to right side and continue abducting
- self.x = 200; // Move UFO back to a position where it can continue
- // Reset UFO state to continue abduction process
- self.isHovering = false;
- self.isAbducting = false;
- self.hoverTarget = null;
- self.speed = 0; // Stop movement until new target selected
- return;
- } else {
- // All valid towers abducted - check if 3-second wait period has completed
- if (!self.allTowersDefeatedTime) {
- // First time all towers are defeated, start the 3-second timer
- self.allTowersDefeatedTime = LK.ticks;
- // Push UFO back to prevent immediate victory
- self.x = 200;
- self.speed = 0; // Stop movement during wait period
- return;
- }
- // Check if 3 seconds have passed since all towers were defeated
- var waitTime = 180; // 3 seconds at 60fps
- if (LK.ticks - self.allTowersDefeatedTime < waitTime) {
- // Still waiting, push UFO back
- self.x = 200;
- self.speed = 0; // Keep UFO stationary during wait
- return;
- }
- // 3 seconds have passed, UFO wins
- // Track wave completion for UFO boss
- if (currentWave === 5) {
- // UFO has successfully abducted all towers and reached the goal
- // Player loses - show game over
- LK.showGameOver();
- return;
- }
- }
- }
- // UFO behavior: hover down from above, pause, then select towers to abduct
- if (!self.hasPaused) {
- // Initial pause for 2 seconds after appearing
- self.pauseTimer += gameSpeed;
- if (self.pauseTimer >= 120) {
- // 2 seconds at 60fps
- self.hasPaused = true;
- }
- return; // Don't do anything else during initial pause
- }
- // Main UFO logic - only proceed if not currently busy
- if (!self.isHovering && !self.isAbducting) {
- // Check if current target is still valid
- if (self.hoverTarget && self.hoverTarget.health <= 0) {
- self.hoverTarget = null; // Clear invalid target
- }
- // Select new target if needed and valid towers exist
- if (!self.hoverTarget && validTowerCount > 0) {
- self.hoverTarget = self.selectRandomTower();
- }
- // If we have a valid target, start hovering
- if (self.hoverTarget && self.hoverTarget.health > 0) {
- self.isHovering = true;
- self.hoverStartTime = LK.ticks;
- // Set UFO's path line to match the tower's row
- self.pathLine = self.hoverTarget.pathLine || 1;
- // Calculate the row Y position based on tower's position
- var targetY = self.hoverTarget.y - 300;
- // Stop UFO horizontal movement during positioning
- self.speed = 0;
- // Move UFO to hover over the selected tower on the same row
- tween(self, {
- x: self.hoverTarget.x,
- y: targetY
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Verify target is still valid before starting abduction
- if (self.hoverTarget && self.hoverTarget.health > 0) {
- self.startAbduction(self.hoverTarget);
- } else {
- // Target became invalid, reset state
- self.isHovering = false;
- self.hoverTarget = null;
- }
- }
- });
- // Update UFO's position immediately to enable tower attacks during movement
- self.y = targetY;
- } else if (validTowerCount === 0) {
- // No valid towers remaining, move toward goal
- if (!self.allTowersDefeatedTime) {
- self.allTowersDefeatedTime = LK.ticks;
- }
- // Only start moving toward goal after 3-second wait
- var waitTime = 180; // 3 seconds at 60fps
- if (LK.ticks - self.allTowersDefeatedTime >= waitTime) {
- self.speed = -1; // Resume movement toward goal
- } else {
- self.speed = 0; // Wait before moving to goal
- }
- }
- }
- // Update last position
- self.lastX = self.x;
- // Handle UFO rendering order - render in front of towers above it, behind towers below it
- // Sort all display objects (towers and UFO) by Y position for proper depth ordering
- var allTowersAndUFO = towers.slice(); // Copy towers array
- allTowersAndUFO.push(self); // Add UFO to the list
- // Sort by Y position (lower Y values should be behind higher Y values)
- allTowersAndUFO.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add all objects to game in sorted order to ensure proper rendering depth
- for (var i = 0; i < allTowersAndUFO.length; i++) {
- var obj = allTowersAndUFO[i];
- if (obj.parent) {
- game.removeChild(obj);
- // Find the first wave asset in children to insert before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert before wave asset
- game.addChildAt(obj, waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(obj);
- }
- }
- }
- };
- return self;
-});
/****
* Initialize Game
****/
@@ -2068,4234 +98,84 @@
/****
* Game Code
****/
-// Cutscene update loop - handles story sequences
-function updateCutscene() {
- // Handle cutscene-specific logic here
- // Currently cutscenes are handled by their own tween animations
- // This function exists for future cutscene-specific updates
-}
-// Gameplay update loop - handles tower defense mechanics
-function updateGameplay() {
+// Game update loop
+game.update = function () {
+ if (!gameStarted) return;
// Spawn enemies
- enemySpawnTimer += gameSpeed;
+ enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnInterval) {
spawnEnemy();
enemySpawnTimer = 0;
}
- // Update fan tower cooldowns
- for (var i = 0; i < towers.length; i++) {
- var tower = towers[i];
- // Check if this is a fan tower
- if (tower.blades) {
- tower.cooldownTimer += gameSpeed;
- // Check if cooldown should start
- if (tower.isRunning && tower.cooldownTimer >= tower.cooldownDuration) {
- // Start cooldown - stop fan
- tower.cooldownActive = true;
- tower.isRunning = false;
- tower.cooldownTimer = 0;
- // Stop blade spinning
- if (tower.blades) {
- tween.stop(tower.blades);
- }
- // Flash fan red to indicate cooldown
- LK.effects.flashObject(tower, 0xff0000, 1000);
- }
- // Check if cooldown should end (10 seconds cooldown)
- if (tower.cooldownActive && tower.cooldownTimer >= 10 * 60 / gameSpeed) {
- // End cooldown - restart fan
- tower.cooldownActive = false;
- tower.isRunning = true;
- tower.cooldownTimer = 0;
- // Resume blade spinning
- var _spinBlades2 = function spinBlades() {
- if (tower.blades && tower.isRunning) {
- tween(tower.blades, {
- rotation: tower.blades.rotation + Math.PI * 2
- }, {
- duration: 500,
- easing: tween.linear,
- onFinish: _spinBlades2
- });
- }
- };
- _spinBlades2();
- // Flash fan green to indicate restart
- LK.effects.flashObject(tower, 0x00ff00, 500);
- }
- }
- }
- // Handle plasma tower attacks
- for (var i = 0; i < towers.length; i++) {
- var tower = towers[i];
- if (tower._assetId === 'Plasmaball' && tower.health > 0) {
- handlePlasmaAttack(tower);
- }
- }
- // Clean up orphaned electric tower zap effects
- for (var i = 0; i < towers.length; i++) {
- var tower = towers[i];
- if (tower._assetId === 'Bugzapper' && tower.activeZaps && tower.zapTargets) {
- // Check each zap effect for orphaned or out-of-range targets
- for (var zapIndex = tower.activeZaps.length - 1; zapIndex >= 0; zapIndex--) {
- var zapEffect = tower.activeZaps[zapIndex];
- var targetEnemy = tower.zapTargets[zapIndex];
- // Check if zap effect is orphaned (no target, destroyed target, or target out of range)
- var shouldRemoveZap = false;
- if (!zapEffect || !zapEffect.parent) {
- // Zap effect was destroyed but not removed from array
- shouldRemoveZap = true;
- } else if (!targetEnemy || !targetEnemy.parent) {
- // Target enemy was destroyed
- shouldRemoveZap = true;
- } else {
- // Check if enemy is still in range and on same line
- var enemyInRange = false;
- var canAttackUFO = false;
- // For UFO boss, check if tower can attack based on UFO's current position and pathLine
- if (targetEnemy._assetId === 'UFO' && targetEnemy.pathLine && tower.pathLine) {
- if (Math.abs(targetEnemy.pathLine - tower.pathLine) === 0) {
- canAttackUFO = true;
- }
- }
- // Check if enemy is on the same horizontal line as the tower OR can attack UFO
- if (Math.abs(targetEnemy.y - tower.y) < 100 || canAttackUFO) {
- // For UFO, check if within range regardless of direction; for others, check right side and range
- if (targetEnemy._assetId === 'UFO') {
- var distance = Math.sqrt(Math.pow(targetEnemy.x - tower.x, 2) + Math.pow(targetEnemy.y - tower.y, 2));
- enemyInRange = distance < 800;
- } else {
- enemyInRange = targetEnemy.x > tower.x && targetEnemy.x - tower.x < 800;
- }
- }
- if (!enemyInRange) {
- shouldRemoveZap = true;
- }
- }
- // Remove orphaned zap effect
- if (shouldRemoveZap) {
- if (zapEffect && zapEffect.parent) {
- tween.stop(zapEffect);
- zapEffect.destroy();
- }
- tower.activeZaps.splice(zapIndex, 1);
- tower.zapTargets.splice(zapIndex, 1);
- }
- }
- }
- }
// Update enemies
updateEnemies();
- // Clean up gas clouds
- for (var i = gasClouds.length - 1; i >= 0; i--) {
- var gasCloud = gasClouds[i];
- if (!gasCloud || !gasCloud.parent || gasCloud.createdTime && LK.ticks - gasCloud.createdTime > 180) {
- if (gasCloud && gasCloud.parent) gasCloud.destroy();
- gasClouds.splice(i, 1);
- }
+ // Check win condition
+ if (enemiesSpawned >= maxEnemiesInWave && enemies.length === 0) {
+ LK.showYouWin();
}
- // Clean up water squirts - limit to max 15 simultaneous
- for (var i = waterSquirts.length - 1; i >= 0; i--) {
- var squirt = waterSquirts[i];
- if (!squirt || !squirt.parent || squirt.createdTime && LK.ticks - squirt.createdTime > 300 || waterSquirts.length > 15) {
- if (squirt && squirt.parent) squirt.destroy();
- waterSquirts.splice(i, 1);
- }
- }
- // Clean up plasma rays - limit to max 50 simultaneous
- var plasmaRayCount = 0;
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Plasmaray1') {
- plasmaRayCount++;
- if (!child.createdTime) child.createdTime = LK.ticks;
- if (LK.ticks - child.createdTime > 300 || plasmaRayCount > 50) {
- child.destroy();
- }
- }
- }
- // Clean up fireballs
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Fireball') {
- if (!child.createdTime) child.createdTime = LK.ticks;
- if (child.x > 2248 || child.x < -200 || child.y > 2932 || child.y < -200 || LK.ticks - child.createdTime > 300) {
- tween.stop(child);
- child.destroy();
- }
- }
- }
- // Clean up orphaned blades
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Blades') {
- var hasOwner = false;
- for (var j = 0; j < towers.length; j++) {
- if (towers[j].blades === child) {
- hasOwner = true;
- break;
- }
- }
- if (!hasOwner) child.destroy();
- }
- }
-}
-// Main game update loop - routes to appropriate update method
-game.update = function () {
- if (!gameStarted) return;
- // Check if we're in a cutscene by looking for active story assets
- var inCutscene = false;
- for (var i = 0; i < game.children.length; i++) {
- var child = game.children[i];
- if (child.assetId === 'Story1' || child.assetId === 'intro' || child.assetId === 'Title') {
- inCutscene = true;
- break;
- }
- }
- // Set gameplay state
- gameplayActive = !inCutscene;
- // Route to appropriate update method
- if (gameplayActive) {
- updateGameplay();
- } else {
- updateCutscene();
- }
- // Check wave 1 completion - different for level 1 vs level 2
- if (currentWave === 1 && (!window.isLevel2 && wave1EnemiesCompleted >= 10 || window.isLevel2 && wave1EnemiesCompleted >= 40)) {
- // Award player $50 for completing wave 1
- playerCash += 50;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 2
- currentWave = 2;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0; // Reset defeated counter for new wave
- // Level 2 wave 2 has 80 enemies, level 1 wave 2 has 30 drones
- maxEnemiesInWave = window.isLevel2 ? 80 : 30;
- enemySpawnInterval = 180; // 3 seconds between spawns at 60fps
- // Fade in wave2 asset in middle of screen
- var wave2Asset = game.addChild(LK.getAsset('Wave2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave2 asset
- tween(wave2Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave2 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave2Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave2Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- }
- // Check wave 2 completion and initialize wave 3 - different for level 1 vs level 2
- if (currentWave === 2 && (!window.isLevel2 && wave2EnemiesCompleted >= 30 || window.isLevel2 && wave2EnemiesCompleted >= 80)) {
- // Award player $50 for completing wave 2
- playerCash += 50;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 3
- currentWave = 3;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0; // Reset defeated counter for new wave
- maxEnemiesInWave = window.isLevel2 ? 40 : 20; // Level 2 wave 3 has 40 aliencars, level 1 has 20 robots
- enemySpawnInterval = 300; // 5 seconds between spawns at 60fps
- // Fade in wave3 asset in middle of screen
- var wave3Asset = game.addChild(LK.getAsset('Wave3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave3 asset
- tween(wave3Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave3 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave3Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave3Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- }
- // Check wave 3 completion and initialize wave 4
- if (currentWave === 3 && enemiesSpawned >= maxEnemiesInWave && enemies.length === 0) {
- // Award player $50 for completing wave 3
- playerCash += 50;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 4
- currentWave = 4;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0; // Reset defeated counter for new wave
- maxEnemiesInWave = window.isLevel2 ? 60 : 50; // Level 2 wave 4 has 60 flyingaliens, level 1 has 50 SpaceDrones
- enemySpawnInterval = window.isLevel2 ? 300 : 120; // Level 2: 5 seconds, Level 1: 2 seconds between spawns at 60fps
- // Fade in wave4 asset in middle of screen
- var wave4Asset = game.addChild(LK.getAsset('Wave4', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave4 asset
- tween(wave4Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave4 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave4Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave4Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- }
- // Check wave 4 completion and initialize wave 5
- if (currentWave === 4 && enemiesSpawned >= maxEnemiesInWave && enemies.length === 0) {
- // Award player $200 for completing wave 4
- playerCash += 200;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 5
- currentWave = 5;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0; // Reset defeated counter for new wave
- maxEnemiesInWave = 1; // Wave 5 has 1 UFO boss
- enemySpawnInterval = 300; // 5 seconds before boss appears
- // Boss level - player only has 1 life
- playerLives = 1;
- if (livesText) {
- livesText.setText('Lives: ' + playerLives);
- }
- // Fade in wave5 asset in middle of screen
- var wave5Asset = game.addChild(LK.getAsset('Wave5', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave5 asset
- tween(wave5Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave5 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave5Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave5Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- }
- // Check wave 5 completion for level 1 and level 2
- if (currentWave === 5 && enemiesSpawned >= maxEnemiesInWave && enemies.length === 0) {
- // Award player $500 for completing wave 5
- playerCash += 500;
- cashText.setText('Cash: $' + playerCash);
- // Restore all 3 lives
- playerLives = 3;
- if (livesText) {
- livesText.setText('Lives: ' + playerLives);
- }
- // Check if this is level 1 or level 2
- if (!window.isLevel2) {
- // End of level 1: Start level 2 with a cutscene (story1 scene)
- // Set cutscene mode for Story1 transition
- gameplayActive = false;
- // Fade in Story1 asset for level 2 transition
- var story1Asset = game.addChild(LK.getAsset('Story1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- tween(story1Asset, {
- alpha: 1
- }, {
- duration: 1200,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Function to proceed to level 2
- var proceedToLevel2 = function proceedToLevel2() {
- // Initialize level 2 variables here
- currentWave = 1; // Reset to wave 1 for level 2
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0;
- maxEnemiesInWave = 40; // Level 2 wave 1 has 40 enemies
- enemySpawnInterval = 900; // Start with 15 seconds (900 ticks at 60fps)
- wave1EnemiesCompleted = 0;
- wave2EnemiesCompleted = 0;
- wave3EnemiesCompleted = 0;
- // Set level 2 flag
- window.isLevel2 = true;
- // Fade out story asset and continue level 2
- tween(story1Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- story1Asset.destroy();
- // Restore gameplay state after cutscene
- gameplayActive = true;
- // Start level 2 wave 1 with wave asset animation
- var wave1Asset = game.addChild(LK.getAsset('Wave1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave1 asset
- tween(wave1Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave1 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave1Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave1Asset.destroy();
- // Level 2 is now ready to continue
- }
- });
- }, 2000);
- }
- });
- }
- });
- };
- // Add click handler to story1Asset to dismiss it manually
- story1Asset.down = function (x, y, obj) {
- proceedToLevel2();
- };
- // Add automatic timeout after 5 seconds to prevent getting stuck
- LK.setTimeout(function () {
- if (story1Asset && story1Asset.parent) {
- proceedToLevel2();
- }
- }, 5000);
- }
- });
- } else {
- // Level 2 wave 5 complete - player beats the game
- LK.showYouWin();
- }
- }
- // Final check - destroy all towers with 0 or less health at end of update cycle
- for (var i = towers.length - 1; i >= 0; i--) {
- var tower = towers[i];
- if (tower.health <= 0) {
- // Play explosion sound when tower is destroyed
- LK.getSound('Explosion').play();
- // Create explosion effect when tower is destroyed
- var towerExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: tower.x,
- y: tower.y,
- scaleX: 0.4,
- scaleY: 0.4
- }));
- // Animate explosion with tween
- tween(towerExplosion, {
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0
- }, {
- duration: 1200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- towerExplosion.destroy();
- }
- });
- // Remove health bar components
- if (tower.healthBarOutline) {
- tower.healthBarOutline.destroy();
- }
- if (tower.healthBar) {
- tower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (tower.blades) {
- tower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (tower.plasma) {
- tower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (tower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < tower.plasmaRays.length; rayIndex++) {
- if (tower.plasmaRays[rayIndex] && tower.plasmaRays[rayIndex].parent) {
- tower.plasmaRays[rayIndex].destroy();
- }
- }
- tower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower with comprehensive cleanup
- if (tower.activeZaps) {
- for (var zapIndex = 0; zapIndex < tower.activeZaps.length; zapIndex++) {
- var zapEffect = tower.activeZaps[zapIndex];
- if (zapEffect && zapEffect.parent) {
- tween.stop(zapEffect);
- zapEffect.destroy();
- }
- }
- tower.activeZaps = [];
- tower.zapTargets = [];
- }
- // Clean up fireball animations if this is a fire tower
- if (tower._assetId === 'Fireworks' && tower.fireballs) {
- // Iterate through the tower's tracked fireballs array
- for (var fireballIndex = tower.fireballs.length - 1; fireballIndex >= 0; fireballIndex--) {
- var fireballData = tower.fireballs[fireballIndex];
- if (fireballData) {
- // Stop the fireball's movement interval
- if (fireballData.interval) {
- LK.clearInterval(fireballData.interval);
- }
- // Stop all tween animations on this fireball
- if (fireballData.fireball && fireballData.fireball.parent) {
- tween.stop(fireballData.fireball);
- // Destroy the fireball
- fireballData.fireball.destroy();
- }
- }
- }
- // Clear the fireballs array
- tower.fireballs = [];
- }
- // Remove tower from the game
- tower.destroy();
- towers.splice(i, 1);
- }
- }
};
-// Mouse move handler for tower preview
-game.move = function (x, y, obj) {
- if (isPlacingTower && towerPreview) {
- // Snap preview to nearest guideline X position (columns)
- var snappedX = getNearestGuidelineX(x);
- towerPreview.x = snappedX;
- // Snap preview to nearest guideline Y position
- var snappedY = getNearestGuidelineY(y);
- towerPreview.y = snappedY;
- // Update blades position if fan preview has blades
- if (towerPreview.blades) {
- towerPreview.blades.x = towerPreview.x + 50;
- towerPreview.blades.y = towerPreview.y - 40 - 100 + 25 + 25;
- }
- // Update plasma position if plasma preview has plasma
- if (towerPreview.plasma) {
- towerPreview.plasma.x = towerPreview.x;
- towerPreview.plasma.y = towerPreview.y - 20;
- }
- }
-};
var enemies = [];
var towers = [];
-var waterSquirts = []; // Track all water squirts for cleanup
-var gasClouds = []; // Track all gas clouds for cleanup
-// Function to clean up gas clouds that have exceeded their lifetime
-function cleanupGasClouds() {
- // Moved to consolidated cleanup for better performance
-}
var gameStarted = false;
var enemySpawnTimer = 0;
-var enemySpawnInterval = 600; // Spawn every 10 seconds at 60fps
+var enemySpawnInterval = 120; // Spawn every 2 seconds at 60fps
var enemiesSpawned = 0;
-var maxEnemiesInWave = 10; // Wave 1 has exactly 10 probedroids
-var currentWave = 1; // Track current wave number
-var wave1EnemiesCompleted = 0; // Track completed enemies in wave 1
-var wave2EnemiesCompleted = 0; // Track completed enemies in wave 2
-var wave3EnemiesCompleted = 0; // Track completed enemies in wave 3
-var enemiesDefeated = 0; // Track enemies actually defeated by player (not reached goal)
-var playerCash = 50; // Player starts with $50
-var playerLives = 3; // Player starts with 3 lives
-var playerScore = 0; // Player starts with 0 score
-var livesText = null; // Global reference to lives text display
-var isPlacingTower = false;
-var selectedTowerType = null;
-var towerPreview = null;
-var selectedTower = null; // Track currently selected tower for deletion
-var deleteButton = null; // Red X button for tower deletion
-var guidelines = [];
-var verticalGuidelines = [];
-var cashText = null;
-var confirmButton = null;
-var gameSpeed = 1; // Global game speed multiplier
-var gameplayActive = true; // Track if we're in active gameplay vs cutscene
-// Define path positions for different lines
-var pathPositions = {
- line6: 2732 / 7 * 6 - 310 + 50,
- // Line 6 position
- line2: 2732 / 7 * 2 + 320 + 50,
- // Line 2 position
- line3: 2732 / 7 * 3 + 150 + 50,
- // Line 3 position
- line4: 2732 / 7 * 4 + 10 + 50,
- // Line 4 position
- line5: 2732 / 7 * 5 - 150 + 50,
- // Line 5 position
- line1: 2732 / 7 * 1 + 480 + 50 // Line 1 position
-};
-// Helper function to get nearest guideline Y position
-function getNearestGuidelineY(y) {
- var nearestY = y;
- var minDistance = Infinity;
- for (var i = 0; i < guidelines.length; i++) {
- var guideline = guidelines[i];
- var distance = Math.abs(guideline.y - y);
- if (distance < minDistance) {
- minDistance = distance;
- nearestY = guideline.y;
- }
- }
- return nearestY;
-}
-// Helper function to get nearest vertical guideline X position
-function getNearestGuidelineX(x) {
- var nearestX = x;
- var minDistance = Infinity;
- for (var i = 0; i < verticalGuidelines.length; i++) {
- var guideline = verticalGuidelines[i];
- var distance = Math.abs(guideline.x - x);
- if (distance < minDistance) {
- minDistance = distance;
- nearestX = guideline.x;
- }
- }
- return nearestX;
-}
-// Clean up tower placement mode
-function cleanupPlacementMode() {
- isPlacingTower = false;
- selectedTowerType = null;
- // Clear tower selection when entering placement mode
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- selectedTower = null;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Comprehensive blade cleanup - destroy all preview blades
- if (towerPreview && towerPreview.blades) {
- // Stop any running animations on the blades
- tween.stop(towerPreview.blades);
- towerPreview.blades.destroy();
- towerPreview.blades = null;
- }
- // Search and destroy all orphaned blade previews with any alpha value
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Blades') {
- // Check if this blade belongs to any active tower
- var hasOwner = false;
- for (var j = 0; j < towers.length; j++) {
- if (towers[j].blades === child) {
- hasOwner = true;
- break;
- }
- }
- // If no owner found, this is a preview blade - destroy it
- if (!hasOwner) {
- tween.stop(child);
- child.destroy();
- }
- }
- }
- // Destroy preview plasma if it exists
- if (towerPreview && towerPreview.plasma) {
- tween.stop(towerPreview.plasma);
- towerPreview.plasma.destroy();
- towerPreview.plasma = null;
- }
- // Clean up any remaining water squirts
- for (var waterIndex = game.children.length - 1; waterIndex >= 0; waterIndex--) {
- var child = game.children[waterIndex];
- if (child.assetId === 'Water') {
- child.destroy();
- }
- }
- if (towerPreview) {
- towerPreview.destroy();
- towerPreview = null;
- }
- if (confirmButton) {
- confirmButton.destroy();
- confirmButton = null;
- }
-}
-// Helper function to check if tower position is too close to existing towers
-function canPlaceTowerAt(x, y) {
- var minDistance = 200; // Minimum distance between towers
- for (var i = 0; i < towers.length; i++) {
- var tower = towers[i];
- var distance = Math.sqrt(Math.pow(x - tower.x, 2) + Math.pow(y - tower.y, 2));
- if (distance < minDistance) {
- return false;
- }
- }
- return true;
-}
-// Function to clean up water squirts when tower is not attacking
-function cleanupWaterSquirts() {
- // Only run cleanup every 30 ticks to reduce performance impact
- if (LK.ticks % 30 !== 0) return;
- for (var i = waterSquirts.length - 1; i >= 0; i--) {
- var squirt = waterSquirts[i];
- if (!squirt || !squirt.parent) {
- // Water squirt already destroyed, remove from tracking
- waterSquirts.splice(i, 1);
- continue;
- }
- // Check if water squirt has exceeded maximum lifetime (5 seconds)
- if (!squirt.createdTime) {
- squirt.createdTime = LK.ticks;
- }
- if (LK.ticks - squirt.createdTime > 300) {
- // 5 seconds at 60fps
- if (squirt.parent) {
- squirt.destroy();
- }
- waterSquirts.splice(i, 1);
- continue;
- }
- // Check if water squirt's tower is still active and attacking
- var towerStillActive = false;
- for (var j = 0; j < towers.length; j++) {
- var tower = towers[j];
- if (tower._assetId === 'Tower1' && tower.health > 0) {
- // Check if tower has enemies in range
- var hasEnemiesInRange = false;
- for (var k = 0; k < enemies.length; k++) {
- var enemy = enemies[k];
- if (Math.abs(enemy.y - tower.y) < 50 && enemy.x > tower.x && enemy.x - tower.x < 700) {
- hasEnemiesInRange = true;
- break;
- }
- }
- if (hasEnemiesInRange) {
- towerStillActive = true;
- break;
- }
- }
- }
- // If no towers are actively attacking, clean up this water squirt
- if (!towerStillActive) {
- if (squirt.parent) {
- squirt.destroy();
- }
- waterSquirts.splice(i, 1);
- }
- }
-}
-// Function to clean up all fireball projectiles that are off-screen or have invalid targets
-function cleanupFireballs() {
- // Find all fireball assets in the game
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Fireball') {
- // Check if fireball is off-screen
- if (child.x > 2048 + 200 || child.x < -200 || child.y > 2732 + 200 || child.y < -200) {
- tween.stop(child);
- child.destroy();
- continue;
- }
- // Check if fireball has been on screen for too long (5 seconds)
- if (!child.createdTime) {
- child.createdTime = LK.ticks;
- }
- if (LK.ticks - child.createdTime > 300) {
- // 5 seconds at 60fps
- tween.stop(child);
- child.destroy();
- }
- }
- }
-}
-// Function to clean up plasma rays that are orphaned or have exceeded their lifetime
-function cleanupPlasmaBeams() {
- // Only run cleanup every 30 ticks to reduce performance impact
- if (LK.ticks % 30 !== 0) return;
- // Find all plasma ray assets in the game
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Plasmaray1') {
- // Check if plasma ray has been on screen for too long (5 seconds - reduced from 10)
- if (!child.createdTime) {
- child.createdTime = LK.ticks;
- }
- if (LK.ticks - child.createdTime > 300) {
- // 5 seconds at 60fps (reduced from 10 seconds)
- child.destroy();
- continue;
- }
- // Check if the plasma ray is orphaned (no tower owns it or tower is destroyed)
- var isOrphaned = true;
- for (var j = 0; j < towers.length; j++) {
- var tower = towers[j];
- // Check if tower has plasma (is a plasma tower) and is alive
- if (tower.plasma && tower.health > 0 && tower.plasmaRays) {
- for (var k = 0; k < tower.plasmaRays.length; k++) {
- if (tower.plasmaRays[k] === child) {
- isOrphaned = false;
- break;
- }
- }
- }
- if (!isOrphaned) break;
- }
- // If orphaned, destroy it
- if (isOrphaned) {
- child.destroy();
- continue;
- }
- }
- }
-}
-// Function to clean up blade assets that are orphaned
-function cleanupBlades() {
- // Only run cleanup every 30 ticks to reduce performance impact
- if (LK.ticks % 30 !== 0) return;
- // Find all blade assets in the game
- for (var i = game.children.length - 1; i >= 0; i--) {
- var child = game.children[i];
- if (child.assetId === 'Blades') {
- // Check if the blade is orphaned (no tower owns it)
- var isOrphaned = true;
- for (var j = 0; j < towers.length; j++) {
- var tower = towers[j];
- if (tower.blades === child) {
- isOrphaned = false;
- break;
- }
- }
- // If orphaned, destroy it
- if (isOrphaned) {
- child.destroy();
- continue;
- }
- }
- }
-}
+var maxEnemiesInWave = 10; // Wave 1 has exactly 10 enemies
// Tower defense functions
function startTowerDefenseWave1() {
gameStarted = true;
enemySpawnTimer = 0;
enemiesSpawned = 0;
- // Add score display to top of screen
- var scoreText = new Text2('Score: 0', {
- size: 80,
- fill: 0xFFFFFF
- });
- scoreText.anchor.set(0.5, 0);
- scoreText.x = 2048 / 2;
- scoreText.y = 50;
- game.addChild(scoreText);
- // Store scoreText reference globally for updating
- window.scoreText = scoreText;
- // Add cash display to top of screen
- cashText = new Text2('Cash: $' + playerCash, {
- size: 80,
- fill: 0xFFD700
- });
- cashText.anchor.set(0.5, 0);
- cashText.x = 2048 / 2 + 300 + 200;
- cashText.y = 50;
- game.addChild(cashText);
- // Add speed up button under cash display
- var speedUpButton = new Button();
- speedUpButton.setup({
- text: '2X SPEED',
- backgroundColor: 0x00AA00,
- textColor: 0xFFFFFF,
- width: 250,
- height: 80,
- fontSize: 35
- });
- speedUpButton.x = 2048 / 2 + 300 + 200;
- speedUpButton.y = 180;
- game.addChild(speedUpButton);
- // Speed up functionality
- speedUpButton.onClick = function () {
- if (gameSpeed === 1) {
- gameSpeed = 2;
- speedUpButton.setup({
- text: '1X SPEED',
- backgroundColor: 0xFF6600,
- textColor: 0xFFFFFF,
- width: 250,
- height: 80,
- fontSize: 35
- });
- } else {
- gameSpeed = 1;
- speedUpButton.setup({
- text: '2X SPEED',
- backgroundColor: 0x00AA00,
- textColor: 0xFFFFFF,
- width: 250,
- height: 80,
- fontSize: 35
- });
- }
- };
- // Add lives display to top of screen
- livesText = new Text2('Lives: ' + playerLives, {
- size: 80,
- fill: 0xFF4444
- });
- livesText.anchor.set(0.5, 0);
- livesText.x = 2048 / 2 - 300 - 200;
- livesText.y = 50;
- game.addChild(livesText);
- // Add skip wave button to top of screen
- var skipWaveButton = new Text2('SKIP WAVE', {
- size: 60,
- fill: 0xFFFFFF
- });
- skipWaveButton.anchor.set(0.5, 0);
- skipWaveButton.x = 2048 / 2;
- skipWaveButton.y = 150;
- game.addChild(skipWaveButton);
- // Add touch event to skip wave button
- skipWaveButton.down = function (x, y, obj) {
- // Skip to next wave immediately
- if (currentWave === 1) {
- // Skip to wave 2
- // Award player $50 for completing wave 1
- playerCash += 50;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 2
- currentWave = 2;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- // Level 2 wave 2 has 80 enemies, level 1 wave 2 has 30 drones
- maxEnemiesInWave = window.isLevel2 ? 80 : 30;
- enemySpawnInterval = 180; // 3 seconds between spawns at 60fps
- wave1EnemiesCompleted = window.isLevel2 ? 40 : 10; // Mark wave 1 as completed
- // Clear existing enemies
- for (var i = enemies.length - 1; i >= 0; i--) {
- enemies[i].destroy();
- }
- enemies = [];
- // Fade in wave2 asset in middle of screen
- var wave2Asset = game.addChild(LK.getAsset('Wave2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave2 asset
- tween(wave2Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave2 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave2Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave2Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- } else if (currentWave === 2) {
- // Skip to wave 3
- // Award player $50 for completing wave 2
- playerCash += 50;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 3
- currentWave = 3;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- maxEnemiesInWave = 20; // Wave 3 has 20 robots
- enemySpawnInterval = 180; // 3 seconds between spawns at 60fps
- wave2EnemiesCompleted = window.isLevel2 ? 80 : 30; // Mark wave 2 as completed
- // Clear existing enemies
- for (var i = enemies.length - 1; i >= 0; i--) {
- enemies[i].destroy();
- }
- enemies = [];
- // Fade in wave3 asset in middle of screen
- var wave3Asset = game.addChild(LK.getAsset('Wave3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave3 asset
- tween(wave3Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave3 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave3Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave3Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- } else if (currentWave === 3) {
- // Skip to wave 4
- // Award player $50 for completing wave 3
- playerCash += 50;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 4
- currentWave = 4;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- maxEnemiesInWave = 50; // Wave 4 has 50 SpaceDrones
- enemySpawnInterval = 120; // 2 seconds between spawns at 60fps
- wave3EnemiesCompleted = 20; // Mark wave 3 as completed
- // Clear existing enemies
- for (var i = enemies.length - 1; i >= 0; i--) {
- enemies[i].destroy();
- }
- enemies = [];
- // Fade in wave4 asset in middle of screen
- var wave4Asset = game.addChild(LK.getAsset('Wave4', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave4 asset
- tween(wave4Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave4 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave4Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave4Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- } else if (currentWave === 4) {
- // Skip to wave 5
- // Award player $200 for completing wave 4
- playerCash += 200;
- cashText.setText('Cash: $' + playerCash);
- // Initialize wave 5
- currentWave = 5;
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0; // Reset defeated counter for new wave
- maxEnemiesInWave = 1; // Wave 5 has 1 UFO boss
- enemySpawnInterval = 300; // 5 seconds before boss appears
- // Boss level - player only has 1 life
- playerLives = 1;
- if (livesText) {
- livesText.setText('Lives: ' + playerLives);
- }
- // Clear existing enemies
- for (var i = enemies.length - 1; i >= 0; i--) {
- enemies[i].destroy();
- }
- enemies = [];
- // Fade in wave5 asset in middle of screen
- var wave5Asset = game.addChild(LK.getAsset('Wave5', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave5 asset
- tween(wave5Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave5 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave5Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave5Asset.destroy();
- }
- });
- }, 2000);
- }
- });
- } else if (currentWave === 5) {
- // Skip to level 2 cutscene directly from wave 5 skip
- // Award player $500 for completing wave 5
- playerCash += 500;
- cashText.setText('Cash: $' + playerCash);
- // Restore all 3 lives for next level
- playerLives = 3;
- if (livesText) {
- livesText.setText('Lives: ' + playerLives);
- }
- // Clear existing enemies
- for (var i = enemies.length - 1; i >= 0; i--) {
- enemies[i].destroy();
- }
- enemies = [];
- // Set cutscene mode for Story1 transition
- gameplayActive = false;
- // Fade in Story1 asset for level 2 transition
- var story1Asset = game.addChild(LK.getAsset('Story1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- tween(story1Asset, {
- alpha: 1
- }, {
- duration: 1200,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Function to proceed to level 2
- var proceedToLevel2 = function proceedToLevel2() {
- // Initialize level 2 variables here
- currentWave = 1; // Reset to wave 1 for level 2
- enemiesSpawned = 0;
- enemySpawnTimer = 0;
- enemiesDefeated = 0;
- maxEnemiesInWave = 40; // Level 2 wave 1 has 40 enemies
- enemySpawnInterval = 900; // Start with 15 seconds
- wave1EnemiesCompleted = 0;
- wave2EnemiesCompleted = 0;
- wave3EnemiesCompleted = 0;
- // Set level 2 flag
- window.isLevel2 = true;
- // Fade out story asset and continue level 2
- tween(story1Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- story1Asset.destroy();
- // Restore gameplay state after cutscene
- gameplayActive = true;
- // Start level 2 wave 1 with wave asset animation
- var wave1Asset = game.addChild(LK.getAsset('Wave1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0
- }));
- // Fade in wave1 asset
- tween(wave1Asset, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Keep wave1 visible for 2 seconds then fade out
- LK.setTimeout(function () {
- tween(wave1Asset, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- wave1Asset.destroy();
- // Level 2 is now ready to continue
- }
- });
- }, 2000);
- }
- });
- }
- });
- };
- // Add click handler to story1Asset to dismiss it manually
- story1Asset.down = function (x, y, obj) {
- proceedToLevel2();
- };
- // Add automatic timeout after 5 seconds to prevent getting stuck
- LK.setTimeout(function () {
- if (story1Asset && story1Asset.parent) {
- proceedToLevel2();
- }
- }, 5000);
- }
- });
- }
- };
- // Add Gasbutton to bottom of game scene
- var gasButton = game.addChild(LK.getAsset('Gasbutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 426.67 + 50 + 50,
- y: 2732 - 350
- }));
- // Add Waterbutton to bottom left of game scene
- var waterButton = game.addChild(LK.getAsset('Waterbutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 50,
- y: 2732 - 350
- }));
- // Water button click handler
- waterButton.down = function (x, y, obj) {
- // Play tower select sound
- LK.getSound('Towerselect').play();
- // Check if player has enough cash
- if (playerCash >= 10) {
- // Start tower placement mode
- isPlacingTower = true;
- selectedTowerType = 'water';
- // Create tower preview
- if (towerPreview) {
- towerPreview.destroy();
- }
- towerPreview = game.addChild(LK.getAsset('Tower1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0.5
- }));
- // Create green tick button for confirming placement
- if (confirmButton) {
- confirmButton.destroy();
- }
- confirmButton = game.addChild(new Button());
- confirmButton.setup({
- text: '✓',
- backgroundColor: 0x00FF00,
- textColor: 0xFFFFFF,
- width: 120,
- height: 120,
- fontSize: 80
- });
- confirmButton.x = 2048 - 150;
- confirmButton.y = 2732 / 2;
- confirmButton.onClick = function () {
- // Play confirm sound when green tick is clicked
- LK.getSound('Confirm').play();
- // Place tower at current preview position
- if (towerPreview) {
- // Align tower position to nearest guidelines
- var alignedX = getNearestGuidelineX(towerPreview.x);
- var alignedY = getNearestGuidelineY(towerPreview.y);
- // Check if tower can be placed at this position
- if (!canPlaceTowerAt(alignedX, alignedY)) {
- // Flash red to indicate invalid placement
- LK.effects.flashObject(towerPreview, 0xff0000, 500);
- return;
- }
- var newTower = game.addChild(LK.getAsset('Tower1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY,
- alpha: 1
- }));
- newTower._assetId = 'Tower1'; // Mark this as a water tower
- newTower.health = 100;
- newTower.maxHealth = 100;
- newTower.isBeingDamaged = false;
- newTower.lastDamageTime = 0;
- newTower.lastFireTime = 0; // Initialize fire rate tracking
- // Determine which path line this tower is on based on its Y position
- for (var lineKey in pathPositions) {
- if (Math.abs(alignedY - pathPositions[lineKey]) < 100) {
- newTower.pathLine = parseInt(lineKey.replace('line', ''));
- break;
- }
- }
- if (!newTower.pathLine) newTower.pathLine = 1; // Default to line 1
- // Add health bar to tower
- var healthBarOutline = game.addChild(LK.getAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY - 120
- }));
- var healthBar = game.addChild(LK.getAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY - 120,
- tint: 0x00ff00
- }));
- newTower.healthBarOutline = healthBarOutline;
- newTower.healthBar = healthBar;
- newTower.takeDamage = function (damage) {
- newTower.health -= damage;
- if (newTower.health <= 0) {
- newTower.health = 0;
- }
- // Update health bar
- var healthPercentage = newTower.health / newTower.maxHealth;
- newTower.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- newTower.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- newTower.healthBar.tint = 0xffff00; // Yellow
- } else {
- newTower.healthBar.tint = 0xff0000; // Red
- }
- };
- // Add tower selection functionality
- newTower.down = function (x, y, obj) {
- // Only allow selection if not placing a tower
- if (!isPlacingTower) {
- // Clear previous selection
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Select this tower
- selectedTower = newTower;
- selectedTower.alpha = 0.7; // Dim selected tower
- // Create red X delete button
- deleteButton = game.addChild(new Button());
- deleteButton.setup({
- text: '✖',
- backgroundColor: 0xFF0000,
- textColor: 0xFFFFFF,
- width: 80,
- height: 80,
- fontSize: 50
- });
- deleteButton.x = selectedTower.x + 120;
- deleteButton.y = selectedTower.y - 80;
- deleteButton.onClick = function () {
- // Delete the selected tower
- if (selectedTower) {
- // Remove health bar components
- if (selectedTower.healthBarOutline) {
- selectedTower.healthBarOutline.destroy();
- }
- if (selectedTower.healthBar) {
- selectedTower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (selectedTower.blades) {
- selectedTower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (selectedTower.plasma) {
- selectedTower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (selectedTower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < selectedTower.plasmaRays.length; rayIndex++) {
- if (selectedTower.plasmaRays[rayIndex] && selectedTower.plasmaRays[rayIndex].parent) {
- selectedTower.plasmaRays[rayIndex].destroy();
- }
- }
- selectedTower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower
- if (selectedTower.activeZaps) {
- for (var zapIndex = 0; zapIndex < selectedTower.activeZaps.length; zapIndex++) {
- selectedTower.activeZaps[zapIndex].destroy();
- }
- selectedTower.activeZaps = [];
- selectedTower.zapTargets = [];
- }
- // Remove tower from towers array
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === selectedTower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Destroy the tower
- selectedTower.destroy();
- selectedTower = null;
- // Remove delete button
- deleteButton.destroy();
- deleteButton = null;
- }
- };
- }
- };
- towers.push(newTower);
- // Check for enemies in range immediately after placing
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance)
- if (Math.abs(enemy.y - newTower.y) < 50) {
- // Check if enemy is to the right of the tower and within range of 700 pixels
- if (enemy.x > newTower.x && enemy.x - newTower.x < 700) {
- // Fire immediately
- newTower.lastFireTime = LK.ticks;
- // Create water squirt visual
- var waterSquirt = game.addChild(LK.getAsset('Water', {
- anchorX: 0,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y,
- scaleX: 0.3,
- scaleY: 0.1,
- alpha: 0.7,
- tint: 0x4169E1
- }));
- // Track creation time and add to cleanup tracking
- waterSquirt.createdTime = LK.ticks;
- waterSquirts.push(waterSquirt);
- // Animate water squirt
- tween(waterSquirt, {
- scaleX: 0.35,
- alpha: 0.3
- }, {
- duration: 500,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- // Remove from tracking array when destroyed
- for (var squirtIndex = 0; squirtIndex < waterSquirts.length; squirtIndex++) {
- if (waterSquirts[squirtIndex] === waterSquirt) {
- waterSquirts.splice(squirtIndex, 1);
- break;
- }
- }
- waterSquirt.destroy();
- }
- });
- // Deal damage to enemy
- enemy.takeDamage(8);
- // Make electric effect visible when hit by water
- enemy.showElectricEffect();
- // Robot fires back when hit by water tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(newTower);
- }
- break; // Found an enemy in range
- }
- }
- }
- // Sort all towers by Y position (higher Y values should be in front)
- towers.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add towers to game in sorted order, but ensure they render behind wave assets
- for (var i = 0; i < towers.length; i++) {
- game.removeChild(towers[i]);
- // Find the first wave asset in children to insert towers before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert tower before wave asset
- game.addChildAt(towers[i], waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(towers[i]);
- }
- }
- // Deduct cost and update display
- playerCash -= 10;
- cashText.setText('Cash: $' + playerCash);
- // Clean up placement mode
- cleanupPlacementMode();
- }
- };
- }
- };
- // Gas button click handler
- gasButton.down = function (x, y, obj) {
- // Play tower select sound
- LK.getSound('Towerselect').play();
- // Check if player has enough cash
- if (playerCash >= 20) {
- // Start tower placement mode
- isPlacingTower = true;
- selectedTowerType = 'gas';
- // Create tower preview
- if (towerPreview) {
- towerPreview.destroy();
- }
- towerPreview = game.addChild(LK.getAsset('Dog', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0.5
- }));
- // Create green tick button for confirming placement
- if (confirmButton) {
- confirmButton.destroy();
- }
- confirmButton = game.addChild(new Button());
- confirmButton.setup({
- text: '✓',
- backgroundColor: 0x00FF00,
- textColor: 0xFFFFFF,
- width: 120,
- height: 120,
- fontSize: 80
- });
- confirmButton.x = 2048 - 150;
- confirmButton.y = 2732 / 2;
- confirmButton.onClick = function () {
- // Play confirm sound when green tick is clicked
- LK.getSound('Confirm').play();
- // Place tower at current preview position
- if (towerPreview) {
- // Align tower position to nearest guidelines
- var alignedX = getNearestGuidelineX(towerPreview.x);
- var alignedY = getNearestGuidelineY(towerPreview.y);
- // Check if tower can be placed at this position
- if (!canPlaceTowerAt(alignedX, alignedY)) {
- // Flash red to indicate invalid placement
- LK.effects.flashObject(towerPreview, 0xff0000, 500);
- return;
- }
- var newTower = game.addChild(LK.getAsset('Dog', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY,
- alpha: 1
- }));
- newTower._assetId = 'Dog'; // Mark this as a gas tower
- newTower.health = 100;
- newTower.maxHealth = 100;
- newTower.isBeingDamaged = false;
- newTower.lastDamageTime = 0;
- newTower.lastFireTime = 0; // Initialize fire rate tracking
- // Add health bar to tower
- var healthBarOutline = game.addChild(LK.getAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 120
- }));
- var healthBar = game.addChild(LK.getAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 120,
- tint: 0x00ff00
- }));
- newTower.healthBarOutline = healthBarOutline;
- newTower.healthBar = healthBar;
- newTower.takeDamage = function (damage) {
- newTower.health -= damage;
- if (newTower.health <= 0) {
- newTower.health = 0;
- }
- // Update health bar
- var healthPercentage = newTower.health / newTower.maxHealth;
- newTower.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- newTower.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- newTower.healthBar.tint = 0xffff00; // Yellow
- } else {
- newTower.healthBar.tint = 0xff0000; // Red
- }
- };
- // Add tower selection functionality
- newTower.down = function (x, y, obj) {
- // Only allow selection if not placing a tower
- if (!isPlacingTower) {
- // Clear previous selection
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Select this tower
- selectedTower = newTower;
- selectedTower.alpha = 0.7; // Dim selected tower
- // Create red X delete button
- deleteButton = game.addChild(new Button());
- deleteButton.setup({
- text: '✖',
- backgroundColor: 0xFF0000,
- textColor: 0xFFFFFF,
- width: 80,
- height: 80,
- fontSize: 50
- });
- deleteButton.x = selectedTower.x + 120;
- deleteButton.y = selectedTower.y - 80;
- deleteButton.onClick = function () {
- // Delete the selected tower
- if (selectedTower) {
- // Remove health bar components
- if (selectedTower.healthBarOutline) {
- selectedTower.healthBarOutline.destroy();
- }
- if (selectedTower.healthBar) {
- selectedTower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (selectedTower.blades) {
- selectedTower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (selectedTower.plasma) {
- selectedTower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (selectedTower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < selectedTower.plasmaRays.length; rayIndex++) {
- if (selectedTower.plasmaRays[rayIndex] && selectedTower.plasmaRays[rayIndex].parent) {
- selectedTower.plasmaRays[rayIndex].destroy();
- }
- }
- selectedTower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower
- if (selectedTower.activeZaps) {
- for (var zapIndex = 0; zapIndex < selectedTower.activeZaps.length; zapIndex++) {
- selectedTower.activeZaps[zapIndex].destroy();
- }
- selectedTower.activeZaps = [];
- selectedTower.zapTargets = [];
- }
- // Remove tower from towers array
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === selectedTower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Destroy the tower
- selectedTower.destroy();
- selectedTower = null;
- // Remove delete button
- deleteButton.destroy();
- deleteButton = null;
- }
- };
- }
- };
- towers.push(newTower);
- // Check for enemies in range immediately after placing
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance)
- if (Math.abs(enemy.y - newTower.y) < 50) {
- // Check if enemy is to the right of the tower and within range of 600 pixels
- if (enemy.x > newTower.x && enemy.x - newTower.x < 600) {
- // Fire immediately
- newTower.lastFireTime = LK.ticks;
- // Switch dog asset to dog1 for fart animation
- var fartingDog = game.addChild(LK.getAsset('Dog1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y,
- alpha: 1
- }));
- // Copy tower properties to the new farting dog
- fartingDog._assetId = 'Dog';
- fartingDog.health = newTower.health;
- fartingDog.maxHealth = newTower.maxHealth;
- fartingDog.isBeingDamaged = newTower.isBeingDamaged;
- fartingDog.lastDamageTime = newTower.lastDamageTime;
- fartingDog.lastFireTime = newTower.lastFireTime;
- fartingDog.healthBarOutline = newTower.healthBarOutline;
- fartingDog.healthBar = newTower.healthBar;
- fartingDog.takeDamage = newTower.takeDamage;
- // Replace tower in towers array
- for (var towerIndex = 0; towerIndex < towers.length; towerIndex++) {
- if (towers[towerIndex] === newTower) {
- towers[towerIndex] = fartingDog;
- break;
- }
- }
- // Remove original tower
- newTower.destroy();
- // Create gas cloud visual
- var gasCloud = game.addChild(LK.getAsset('GasCloud', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fartingDog.x + 150,
- y: fartingDog.y,
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0.6,
- tint: 0x90EE90
- }));
- // Track gas cloud creation time and add to cleanup tracking
- gasCloud.createdTime = LK.ticks;
- gasClouds.push(gasCloud);
- // Animate gas cloud expanding and fading
- tween(gasCloud, {
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.2
- }, {
- duration: 1000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- gasCloud.destroy();
- }
- });
- // Switch back to normal dog after 500ms
- LK.setTimeout(function () {
- fartingDog.destroy();
- var normalDog = game.addChild(LK.getAsset('Dog', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fartingDog.x,
- y: fartingDog.y,
- alpha: 1
- }));
- // Copy properties back to normal dog
- normalDog._assetId = 'Dog';
- normalDog.health = fartingDog.health;
- normalDog.maxHealth = fartingDog.maxHealth;
- normalDog.isBeingDamaged = fartingDog.isBeingDamaged;
- normalDog.lastDamageTime = fartingDog.lastDamageTime;
- normalDog.lastFireTime = fartingDog.lastFireTime;
- normalDog.healthBarOutline = fartingDog.healthBarOutline;
- normalDog.healthBar = fartingDog.healthBar;
- normalDog.takeDamage = fartingDog.takeDamage;
- // Replace in towers array
- for (var towerIndex = 0; towerIndex < towers.length; towerIndex++) {
- if (towers[towerIndex] === fartingDog) {
- towers[towerIndex] = normalDog;
- break;
- }
- }
- }, 500);
- // Deal damage to enemy if affected by gas
- var isAffectedByGas = true;
- if (enemy.attachedAssets && enemy.attachedAssets.length > 0) {
- var enemyAssetId = enemy.attachedAssets[0].assetId;
- if (enemyAssetId === 'Robot' || enemyAssetId === 'Drone' || enemyAssetId === 'SpaceDrone' || enemyAssetId === 'Probedroid') {
- isAffectedByGas = false;
- }
- }
- if (isAffectedByGas) {
- enemy.takeDamage(2);
- // Move enemy to random adjacent row on guideline
- var currentLine = enemy.pathLine;
- var availableLines = [];
- // Add adjacent lines (above and below current line)
- if (currentLine > 1) availableLines.push(currentLine - 1);
- if (currentLine < 6) availableLines.push(currentLine + 1);
- // If we have adjacent lines available, move to one randomly
- if (availableLines.length > 0) {
- var randomIndex = Math.floor(Math.random() * availableLines.length);
- var newLine = availableLines[randomIndex];
- enemy.pathLine = newLine;
- // Get the new Y position for the new line
- var newY = pathPositions['line' + newLine];
- // Animate the enemy to the new line position
- tween(enemy, {
- y: newY
- }, {
- duration: 500,
- easing: tween.easeInOut
- });
- }
- // Robot fires back when hit by gas tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(fartingDog);
- }
- }
- break; // Found an enemy in range
- }
- }
- }
- // Sort all towers by Y position (higher Y values should be in front)
- towers.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add towers to game in sorted order, but ensure they render behind wave assets
- for (var i = 0; i < towers.length; i++) {
- game.removeChild(towers[i]);
- // Find the first wave asset in children to insert towers before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert tower before wave asset
- game.addChildAt(towers[i], waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(towers[i]);
- }
- }
- // Deduct cost and update display
- playerCash -= 20;
- cashText.setText('Cash: $' + playerCash);
- // Clean up placement mode
- cleanupPlacementMode();
- }
- };
- }
- };
- // Add Airbutton to the right side of gasbutton
- var airButton = game.addChild(LK.getAsset('Airbutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 426.67 + 50 + 420 + 50 + 50,
- y: 2732 - 350
- }));
- // Air button click handler
- airButton.down = function (x, y, obj) {
- // Play tower select sound
- LK.getSound('Towerselect').play();
- // Check if player has enough cash
- if (playerCash >= 30) {
- // Start tower placement mode
- isPlacingTower = true;
- selectedTowerType = 'air';
- // Create tower preview
- if (towerPreview) {
- towerPreview.destroy();
- }
- towerPreview = game.addChild(LK.getAsset('Fan', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0.5
- }));
- // Add blades to fan preview
- var previewBlades = game.addChild(LK.getAsset('Blades', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: towerPreview.x + 50,
- y: towerPreview.y - 40 - 100 + 25 + 25,
- alpha: 0.5
- }));
- // Store blades reference in tower preview
- towerPreview.blades = previewBlades;
- // Create green tick button for confirming placement
- if (confirmButton) {
- confirmButton.destroy();
- }
- confirmButton = game.addChild(new Button());
- confirmButton.setup({
- text: '✓',
- backgroundColor: 0x00FF00,
- textColor: 0xFFFFFF,
- width: 120,
- height: 120,
- fontSize: 80
- });
- confirmButton.x = 2048 - 150;
- confirmButton.y = 2732 / 2;
- confirmButton.onClick = function () {
- // Play confirm sound when green tick is clicked
- LK.getSound('Confirm').play();
- // Place tower at current preview position
- if (towerPreview) {
- // Align tower position to nearest guidelines
- var alignedX = getNearestGuidelineX(towerPreview.x);
- var alignedY = getNearestGuidelineY(towerPreview.y);
- // Check if tower can be placed at this position
- if (!canPlaceTowerAt(alignedX, alignedY)) {
- // Flash red to indicate invalid placement
- LK.effects.flashObject(towerPreview, 0xff0000, 500);
- return;
- }
- // Create spinning animation for blades
- var _spinBlades = function spinBlades() {
- tween(blades, {
- rotation: blades.rotation + Math.PI * 2
- }, {
- duration: 500,
- easing: tween.linear,
- onFinish: _spinBlades
- });
- };
- var newTower = game.addChild(LK.getAsset('Fan', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY,
- alpha: 1
- }));
- // Add blades asset to fan tower
- var blades = game.addChild(LK.getAsset('Blades', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x + 50,
- y: newTower.y - 40 - 100 + 25 + 25
- }));
- _spinBlades();
- // Store blades reference in tower
- newTower.blades = blades;
- newTower.health = 100;
- newTower.maxHealth = 100;
- newTower.isBeingDamaged = false;
- newTower.lastDamageTime = 0;
- // Add cooldown properties for fan
- newTower.cooldownTimer = 0;
- newTower.cooldownDuration = 20 * 60; // 20 seconds at 60fps
- newTower.cooldownActive = false;
- newTower.isRunning = true;
- // Add health bar to tower
- var healthBarOutline = game.addChild(LK.getAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 170
- }));
- var healthBar = game.addChild(LK.getAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 170,
- tint: 0x00ff00
- }));
- newTower.healthBarOutline = healthBarOutline;
- newTower.healthBar = healthBar;
- newTower.takeDamage = function (damage) {
- newTower.health -= damage;
- if (newTower.health <= 0) {
- newTower.health = 0;
- }
- // Update health bar
- var healthPercentage = newTower.health / newTower.maxHealth;
- newTower.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- newTower.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- newTower.healthBar.tint = 0xffff00; // Yellow
- } else {
- newTower.healthBar.tint = 0xff0000; // Red
- }
- };
- // Add tower selection functionality
- newTower.down = function (x, y, obj) {
- // Only allow selection if not placing a tower
- if (!isPlacingTower) {
- // Clear previous selection
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Select this tower
- selectedTower = newTower;
- selectedTower.alpha = 0.7; // Dim selected tower
- // Create red X delete button
- deleteButton = game.addChild(new Button());
- deleteButton.setup({
- text: '✖',
- backgroundColor: 0xFF0000,
- textColor: 0xFFFFFF,
- width: 80,
- height: 80,
- fontSize: 50
- });
- deleteButton.x = selectedTower.x + 120;
- deleteButton.y = selectedTower.y - 80;
- deleteButton.onClick = function () {
- // Delete the selected tower
- if (selectedTower) {
- // Remove health bar components
- if (selectedTower.healthBarOutline) {
- selectedTower.healthBarOutline.destroy();
- }
- if (selectedTower.healthBar) {
- selectedTower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (selectedTower.blades) {
- selectedTower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (selectedTower.plasma) {
- selectedTower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (selectedTower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < selectedTower.plasmaRays.length; rayIndex++) {
- if (selectedTower.plasmaRays[rayIndex] && selectedTower.plasmaRays[rayIndex].parent) {
- selectedTower.plasmaRays[rayIndex].destroy();
- }
- }
- selectedTower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower
- if (selectedTower.activeZaps) {
- for (var zapIndex = 0; zapIndex < selectedTower.activeZaps.length; zapIndex++) {
- selectedTower.activeZaps[zapIndex].destroy();
- }
- selectedTower.activeZaps = [];
- selectedTower.zapTargets = [];
- }
- // Remove tower from towers array
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === selectedTower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Destroy the tower
- selectedTower.destroy();
- selectedTower = null;
- // Remove delete button
- deleteButton.destroy();
- deleteButton = null;
- }
- };
- }
- };
- towers.push(newTower);
- // Sort all towers by Y position (higher Y values should be in front)
- towers.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add towers to game in sorted order, but ensure they render behind wave assets
- for (var i = 0; i < towers.length; i++) {
- game.removeChild(towers[i]);
- // Find the first wave asset in children to insert towers before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert tower before wave asset
- game.addChildAt(towers[i], waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(towers[i]);
- }
- // Re-add blades if this tower has them to ensure they render in front
- if (towers[i].blades) {
- game.removeChild(towers[i].blades);
- game.addChild(towers[i].blades);
- }
- }
- // Deduct cost and update display
- playerCash -= 30;
- cashText.setText('Cash: $' + playerCash);
- // Clean up placement mode
- isPlacingTower = false;
- selectedTowerType = null;
- // Clean up placement mode
- cleanupPlacementMode();
- }
- };
- }
- };
- // Add Firebutton to the right side of airbutton
- var fireButton = game.addChild(LK.getAsset('Firebutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 426.67 + 50 + 420 + 50 + 426 + 50 + 50,
- y: 2732 - 350
- }));
- // Fire button click handler
- fireButton.down = function (x, y, obj) {
- // Play tower select sound
- LK.getSound('Towerselect').play();
- // Check if player has enough cash
- if (playerCash >= 40) {
- // Start tower placement mode
- isPlacingTower = true;
- selectedTowerType = 'fire';
- // Create tower preview
- if (towerPreview) {
- towerPreview.destroy();
- }
- towerPreview = game.addChild(LK.getAsset('Fireworks', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0.5
- }));
- // Create green tick button for confirming placement
- if (confirmButton) {
- confirmButton.destroy();
- }
- confirmButton = game.addChild(new Button());
- confirmButton.setup({
- text: '✓',
- backgroundColor: 0x00FF00,
- textColor: 0xFFFFFF,
- width: 120,
- height: 120,
- fontSize: 80
- });
- confirmButton.x = 2048 - 150;
- confirmButton.y = 2732 / 2;
- confirmButton.onClick = function () {
- // Play confirm sound when green tick is clicked
- LK.getSound('Confirm').play();
- // Place tower at current preview position
- if (towerPreview) {
- // Align tower position to nearest guidelines
- var alignedX = getNearestGuidelineX(towerPreview.x);
- var alignedY = getNearestGuidelineY(towerPreview.y);
- // Check if tower can be placed at this position
- if (!canPlaceTowerAt(alignedX, alignedY)) {
- // Flash red to indicate invalid placement
- LK.effects.flashObject(towerPreview, 0xff0000, 500);
- return;
- }
- var newTower = game.addChild(LK.getAsset('Fireworks', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY,
- alpha: 1
- }));
- newTower._assetId = 'Fireworks'; // Mark this as a fire tower
- newTower.fireballs = []; // Track all fireballs launched by this tower
- newTower.health = 100;
- newTower.maxHealth = 100;
- newTower.isBeingDamaged = false;
- newTower.lastDamageTime = 0;
- // Add health bar to tower
- var healthBarOutline = game.addChild(LK.getAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 210
- }));
- var healthBar = game.addChild(LK.getAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 210,
- tint: 0x00ff00
- }));
- newTower.healthBarOutline = healthBarOutline;
- newTower.healthBar = healthBar;
- newTower.takeDamage = function (damage) {
- newTower.health -= damage;
- if (newTower.health <= 0) {
- newTower.health = 0;
- }
- // Update health bar
- var healthPercentage = newTower.health / newTower.maxHealth;
- newTower.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- newTower.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- newTower.healthBar.tint = 0xffff00; // Yellow
- } else {
- newTower.healthBar.tint = 0xff0000; // Red
- }
- };
- // Add tower selection functionality
- newTower.down = function (x, y, obj) {
- // Only allow selection if not placing a tower
- if (!isPlacingTower) {
- // Clear previous selection
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Select this tower
- selectedTower = newTower;
- selectedTower.alpha = 0.7; // Dim selected tower
- // Create red X delete button
- deleteButton = game.addChild(new Button());
- deleteButton.setup({
- text: '✖',
- backgroundColor: 0xFF0000,
- textColor: 0xFFFFFF,
- width: 80,
- height: 80,
- fontSize: 50
- });
- deleteButton.x = selectedTower.x + 120;
- deleteButton.y = selectedTower.y - 80;
- deleteButton.onClick = function () {
- // Delete the selected tower
- if (selectedTower) {
- // Remove health bar components
- if (selectedTower.healthBarOutline) {
- selectedTower.healthBarOutline.destroy();
- }
- if (selectedTower.healthBar) {
- selectedTower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (selectedTower.blades) {
- selectedTower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (selectedTower.plasma) {
- selectedTower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (selectedTower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < selectedTower.plasmaRays.length; rayIndex++) {
- if (selectedTower.plasmaRays[rayIndex] && selectedTower.plasmaRays[rayIndex].parent) {
- selectedTower.plasmaRays[rayIndex].destroy();
- }
- }
- selectedTower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower
- if (selectedTower.activeZaps) {
- for (var zapIndex = 0; zapIndex < selectedTower.activeZaps.length; zapIndex++) {
- selectedTower.activeZaps[zapIndex].destroy();
- }
- selectedTower.activeZaps = [];
- selectedTower.zapTargets = [];
- }
- // Remove tower from towers array
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === selectedTower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Destroy the tower
- selectedTower.destroy();
- selectedTower = null;
- // Remove delete button
- deleteButton.destroy();
- deleteButton = null;
- }
- };
- }
- };
- towers.push(newTower);
- // Check for enemies in range immediately after placing
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance)
- if (Math.abs(enemy.y - newTower.y) < 50) {
- // Check if enemy is to the right of the tower and within range of 1500 pixels
- if (enemy.x > newTower.x && enemy.x - newTower.x < 1500) {
- // Fire immediately
- newTower.lastFireTime = LK.ticks;
- // Play fireball sound
- LK.getSound('Fireball').play();
- // Create fireball projectile
- var fireball = game.addChild(LK.getAsset('Fireball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x + 50,
- y: newTower.y,
- scaleX: 0.5,
- scaleY: 0.5,
- rotation: 35 * Math.PI / 180
- }));
- fireball.createdTime = LK.ticks; // Track creation time for cleanup
- fireball.targetX = enemy.x;
- fireball.targetY = enemy.y;
- fireball.speed = 8;
- fireball.damage = 10;
- // Calculate direction to enemy
- var deltaX = enemy.x - fireball.x;
- var deltaY = enemy.y - fireball.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- fireball.velocityX = deltaX / distance * fireball.speed;
- fireball.velocityY = deltaY / distance * fireball.speed;
- // Animate fireball movement
- var fireballInterval = LK.setInterval(function () {
- fireball.x += fireball.velocityX;
- fireball.y += fireball.velocityY;
- // Check if fireball hit any enemy
- for (var enemyIndex = 0; enemyIndex < enemies.length; enemyIndex++) {
- var targetEnemy = enemies[enemyIndex];
- var fireballDistance = Math.sqrt(Math.pow(fireball.x - targetEnemy.x, 2) + Math.pow(fireball.y - targetEnemy.y, 2));
- if (fireballDistance < 80) {
- // Check if this is a SpaceDrone that is currently rotating
- if (targetEnemy._assetId === 'SpaceDrone' && targetEnemy.isRotating) {
- // Deflect fireball back at the original firing tower
- var deflectedFireball = game.addChild(LK.getAsset('Fireball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fireball.x,
- y: fireball.y,
- scaleX: 0.5,
- scaleY: 0.5,
- rotation: fireball.rotation + Math.PI,
- tint: 0x0088FF // Blue tint to show it's deflected
- }));
- // Store reference to the original firing tower for precise targeting
- deflectedFireball.targetTower = newTower;
- // Calculate direction back to the exact same tower that fired this fireball
- var deltaX = newTower.x - deflectedFireball.x;
- var deltaY = newTower.y - deflectedFireball.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- deflectedFireball.velocityX = deltaX / distance * fireball.speed;
- deflectedFireball.velocityY = deltaY / distance * fireball.speed;
- deflectedFireball.damage = fireball.damage;
- // Animate deflected fireball movement
- var deflectedInterval = LK.setInterval(function () {
- deflectedFireball.x += deflectedFireball.velocityX;
- deflectedFireball.y += deflectedFireball.velocityY;
- // Check if deflected fireball hit the original firing tower
- var deflectedDistance = Math.sqrt(Math.pow(deflectedFireball.x - deflectedFireball.targetTower.x, 2) + Math.pow(deflectedFireball.y - deflectedFireball.targetTower.y, 2));
- if (deflectedDistance < 100) {
- // Hit the same tower that originally fired this fireball - deal damage
- deflectedFireball.targetTower.takeDamage(deflectedFireball.damage);
- LK.effects.flashObject(deflectedFireball.targetTower, 0xff0000, 300);
- // Remove deflected fireball
- LK.clearInterval(deflectedInterval);
- tween.stop(deflectedFireball);
- deflectedFireball.destroy();
- return;
- }
- // Check if deflected fireball went off screen
- if (deflectedFireball.x > 2048 + 100 || deflectedFireball.x < -100 || deflectedFireball.y > 2732 + 100 || deflectedFireball.y < -100) {
- LK.clearInterval(deflectedInterval);
- tween.stop(deflectedFireball);
- deflectedFireball.destroy();
- }
- }, 16);
- // Remove original fireball
- LK.clearInterval(fireballInterval);
- tween.stop(fireball);
- fireball.destroy();
- return;
- }
- // Hit enemy - deal damage
- targetEnemy.takeDamage(fireball.damage);
- // Robot fires back when hit by fire tower
- if (targetEnemy.fireBackAtTower) {
- targetEnemy.fireBackAtTower(newTower);
- }
- // Remove fireball
- LK.clearInterval(fireballInterval);
- tween.stop(fireball);
- fireball.destroy();
- return;
- }
- }
- // Check if fireball went off screen
- if (fireball.x > 2048 + 100 || fireball.x < -100 || fireball.y > 2732 + 100 || fireball.y < -100) {
- LK.clearInterval(fireballInterval);
- tween.stop(fireball);
- fireball.destroy();
- }
- }, 16);
- break; // Found an enemy in range
- }
- }
- }
- // Sort all towers by Y position (higher Y values should be in front)
- towers.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add towers to game in sorted order, but ensure they render behind wave assets
- for (var i = 0; i < towers.length; i++) {
- game.removeChild(towers[i]);
- // Find the first wave asset in children to insert towers before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert tower before wave asset
- game.addChildAt(towers[i], waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(towers[i]);
- }
- }
- // Deduct cost and update display
- playerCash -= 40;
- cashText.setText('Cash: $' + playerCash);
- // Clean up placement mode
- cleanupPlacementMode();
- }
- };
- }
- };
- // Add mystery button under air button
- var mysteryButton1 = game.addChild(LK.getAsset('Mysterybutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 426.67 + 50 + 420 + 50 + 50,
- y: 2732 - 350 + 200 + 20
- }));
- // Add Electricbutton to bottom of screen under water button
- var electricButton = game.addChild(LK.getAsset('Electricbutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 50,
- y: 2732 - 350 + 200 + 20
- }));
- // Electric button click handler
- electricButton.down = function (x, y, obj) {
- // Play tower select sound
- LK.getSound('Towerselect').play();
- // Check if player has enough cash
- if (playerCash >= 50) {
- // Start tower placement mode
- isPlacingTower = true;
- selectedTowerType = 'electric';
- // Create tower preview
- if (towerPreview) {
- towerPreview.destroy();
- }
- towerPreview = game.addChild(LK.getAsset('Bugzapper', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0.5
- }));
- // Create green tick button for confirming placement
- if (confirmButton) {
- confirmButton.destroy();
- }
- confirmButton = game.addChild(new Button());
- confirmButton.setup({
- text: '✓',
- backgroundColor: 0x00FF00,
- textColor: 0xFFFFFF,
- width: 120,
- height: 120,
- fontSize: 80
- });
- confirmButton.x = 2048 - 150;
- confirmButton.y = 2732 / 2;
- confirmButton.onClick = function () {
- // Play confirm sound when green tick is clicked
- LK.getSound('Confirm').play();
- // Place tower at current preview position
- if (towerPreview) {
- // Align tower position to nearest guidelines
- var alignedX = getNearestGuidelineX(towerPreview.x);
- var alignedY = getNearestGuidelineY(towerPreview.y);
- // Check if tower can be placed at this position
- if (!canPlaceTowerAt(alignedX, alignedY)) {
- // Flash red to indicate invalid placement
- LK.effects.flashObject(towerPreview, 0xff0000, 500);
- return;
- }
- var newTower = game.addChild(LK.getAsset('Bugzapper', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY,
- alpha: 1
- }));
- newTower._assetId = 'Bugzapper'; // Mark this as an electric tower
- newTower.health = 100;
- newTower.maxHealth = 100;
- newTower.isBeingDamaged = false;
- newTower.lastDamageTime = 0;
- // Add health bar to tower
- var healthBarOutline = game.addChild(LK.getAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 210
- }));
- var healthBar = game.addChild(LK.getAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 210,
- tint: 0x00ff00
- }));
- newTower.healthBarOutline = healthBarOutline;
- newTower.healthBar = healthBar;
- newTower.takeDamage = function (damage) {
- newTower.health -= damage;
- if (newTower.health <= 0) {
- newTower.health = 0;
- }
- // Update health bar
- var healthPercentage = newTower.health / newTower.maxHealth;
- newTower.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- newTower.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- newTower.healthBar.tint = 0xffff00; // Yellow
- } else {
- newTower.healthBar.tint = 0xff0000; // Red
- }
- };
- // Add tower selection functionality
- newTower.down = function (x, y, obj) {
- // Only allow selection if not placing a tower
- if (!isPlacingTower) {
- // Clear previous selection
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Select this tower
- selectedTower = newTower;
- selectedTower.alpha = 0.7; // Dim selected tower
- // Create red X delete button
- deleteButton = game.addChild(new Button());
- deleteButton.setup({
- text: '✖',
- backgroundColor: 0xFF0000,
- textColor: 0xFFFFFF,
- width: 80,
- height: 80,
- fontSize: 50
- });
- deleteButton.x = selectedTower.x + 120;
- deleteButton.y = selectedTower.y - 80;
- deleteButton.onClick = function () {
- // Delete the selected tower
- if (selectedTower) {
- // Remove health bar components
- if (selectedTower.healthBarOutline) {
- selectedTower.healthBarOutline.destroy();
- }
- if (selectedTower.healthBar) {
- selectedTower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (selectedTower.blades) {
- selectedTower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (selectedTower.plasma) {
- selectedTower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (selectedTower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < selectedTower.plasmaRays.length; rayIndex++) {
- if (selectedTower.plasmaRays[rayIndex] && selectedTower.plasmaRays[rayIndex].parent) {
- selectedTower.plasmaRays[rayIndex].destroy();
- }
- }
- selectedTower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower
- if (selectedTower.activeZaps) {
- for (var zapIndex = 0; zapIndex < selectedTower.activeZaps.length; zapIndex++) {
- selectedTower.activeZaps[zapIndex].destroy();
- }
- selectedTower.activeZaps = [];
- selectedTower.zapTargets = [];
- }
- // Remove tower from towers array
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === selectedTower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Destroy the tower
- selectedTower.destroy();
- selectedTower = null;
- // Remove delete button
- deleteButton.destroy();
- deleteButton = null;
- }
- };
- }
- };
- towers.push(newTower);
- // Initialize zap arrays for electric tower
- newTower.activeZaps = [];
- newTower.zapTargets = [];
- // Check for enemies in range immediately after placing
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance)
- if (Math.abs(enemy.y - newTower.y) < 50) {
- // Check if enemy is to the right of the tower and within range of 800 pixels
- if (enemy.x > newTower.x && enemy.x - newTower.x < 800) {
- // Create zap3 visual positioned at enemy's location
- var newZap = game.addChild(LK.getAsset('Zap3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: enemy.x - 400,
- y: enemy.y,
- scaleX: 1.0,
- scaleY: 1.0,
- alpha: 0.9,
- tint: 0x00FFFF
- }));
- // Play electric sound when zap effect is created
- LK.getSound('Electric').play();
- // Store zap effect and target
- newTower.activeZaps.push(newZap);
- newTower.zapTargets.push(enemy);
- // Deal damage to enemy
- enemy.takeDamage(5);
- // Make electric effect visible when hit by electricity
- enemy.showElectricEffect();
- // Robot fires back when hit by electric tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(newTower);
- }
- break; // Found an enemy in range
- }
- }
- }
- // Sort all towers by Y position (higher Y values should be in front)
- towers.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add towers to game in sorted order, but ensure they render behind wave assets
- for (var i = 0; i < towers.length; i++) {
- game.removeChild(towers[i]);
- // Find the first wave asset in children to insert towers before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert tower before wave asset
- game.addChildAt(towers[i], waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(towers[i]);
- }
- }
- // Deduct cost and update display
- playerCash -= 50;
- cashText.setText('Cash: $' + playerCash);
- // Clean up placement mode
- cleanupPlacementMode();
- }
- };
- }
- };
- // Add Plasmabutton to bottom of screen under gas button
- var plasmaButton = game.addChild(LK.getAsset('Plasmabutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 426.67 + 50 + 50,
- y: 2732 - 350 + 200 + 20
- }));
- // Plasma button click handler
- plasmaButton.down = function (x, y, obj) {
- // Play tower select sound
- LK.getSound('Towerselect').play();
- // Check if player has enough cash
- if (playerCash >= 60) {
- // Start tower placement mode
- isPlacingTower = true;
- selectedTowerType = 'plasma';
- // Create tower preview
- if (towerPreview) {
- towerPreview.destroy();
- }
- towerPreview = game.addChild(LK.getAsset('Plasmaball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- alpha: 0.5
- }));
- // Add plasma asset to plasma tower preview and render it in front
- var previewPlasma = game.addChild(LK.getAsset('Plasma', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: towerPreview.x,
- y: towerPreview.y - 20,
- alpha: 0.5
- }));
- // Store plasma reference in tower preview
- towerPreview.plasma = previewPlasma;
- // Start plasma animation for preview
- animatePlasma(previewPlasma);
- // Create green tick button for confirming placement
- if (confirmButton) {
- confirmButton.destroy();
- }
- confirmButton = game.addChild(new Button());
- confirmButton.setup({
- text: '✓',
- backgroundColor: 0x00FF00,
- textColor: 0xFFFFFF,
- width: 120,
- height: 120,
- fontSize: 80
- });
- confirmButton.x = 2048 - 150;
- confirmButton.y = 2732 / 2;
- confirmButton.onClick = function () {
- // Play confirm sound when green tick is clicked
- LK.getSound('Confirm').play();
- // Place tower at current preview position
- if (towerPreview) {
- // Align tower position to nearest guidelines
- var alignedX = getNearestGuidelineX(towerPreview.x);
- var alignedY = getNearestGuidelineY(towerPreview.y);
- // Check if tower can be placed at this position
- if (!canPlaceTowerAt(alignedX, alignedY)) {
- // Flash red to indicate invalid placement
- LK.effects.flashObject(towerPreview, 0xff0000, 500);
- return;
- }
- var newTower = game.addChild(LK.getAsset('Plasmaball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: alignedX,
- y: alignedY,
- alpha: 1
- }));
- newTower._assetId = 'Plasmaball'; // Mark this as a plasma tower
- // Add plasma asset to plasmaball tower and render it in front
- var plasma = game.addChild(LK.getAsset('Plasma', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 20,
- alpha: 1
- }));
- // Store plasma reference in tower
- newTower.plasma = plasma;
- // Start plasma animation
- animatePlasma(plasma);
- newTower.health = 100;
- newTower.maxHealth = 100;
- newTower.isBeingDamaged = false;
- newTower.lastDamageTime = 0;
- // Add health bar to tower
- var healthBarOutline = game.addChild(LK.getAsset('healthBarOutline', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 150
- }));
- var healthBar = game.addChild(LK.getAsset('healthBar', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: newTower.x,
- y: newTower.y - 150,
- tint: 0x00ff00
- }));
- newTower.healthBarOutline = healthBarOutline;
- newTower.healthBar = healthBar;
- newTower.takeDamage = function (damage) {
- newTower.health -= damage;
- if (newTower.health <= 0) {
- newTower.health = 0;
- }
- // Update health bar
- var healthPercentage = newTower.health / newTower.maxHealth;
- newTower.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- newTower.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- newTower.healthBar.tint = 0xffff00; // Yellow
- } else {
- newTower.healthBar.tint = 0xff0000; // Red
- }
- };
- // Add tower selection functionality
- newTower.down = function (x, y, obj) {
- // Only allow selection if not placing a tower
- if (!isPlacingTower) {
- // Clear previous selection
- if (selectedTower) {
- selectedTower.alpha = 1.0;
- }
- if (deleteButton) {
- deleteButton.destroy();
- deleteButton = null;
- }
- // Select this tower
- selectedTower = newTower;
- selectedTower.alpha = 0.7; // Dim selected tower
- // Create red X delete button
- deleteButton = game.addChild(new Button());
- deleteButton.setup({
- text: '✖',
- backgroundColor: 0xFF0000,
- textColor: 0xFFFFFF,
- width: 80,
- height: 80,
- fontSize: 50
- });
- deleteButton.x = selectedTower.x + 120;
- deleteButton.y = selectedTower.y - 80;
- deleteButton.onClick = function () {
- // Delete the selected tower
- if (selectedTower) {
- // Remove health bar components
- if (selectedTower.healthBarOutline) {
- selectedTower.healthBarOutline.destroy();
- }
- if (selectedTower.healthBar) {
- selectedTower.healthBar.destroy();
- }
- // Remove blades if this is a fan tower
- if (selectedTower.blades) {
- selectedTower.blades.destroy();
- }
- // Remove plasma if this is a plasma tower
- if (selectedTower.plasma) {
- selectedTower.plasma.destroy();
- }
- // Clean up plasma rays when stopping plasma attack
- if (selectedTower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < selectedTower.plasmaRays.length; rayIndex++) {
- if (selectedTower.plasmaRays[rayIndex] && selectedTower.plasmaRays[rayIndex].parent) {
- selectedTower.plasmaRays[rayIndex].destroy();
- }
- }
- selectedTower.plasmaRays = [];
- }
- // Remove active zaps if this is an electric tower
- if (selectedTower.activeZaps) {
- for (var zapIndex = 0; zapIndex < selectedTower.activeZaps.length; zapIndex++) {
- selectedTower.activeZaps[zapIndex].destroy();
- }
- selectedTower.activeZaps = [];
- selectedTower.zapTargets = [];
- }
- // Remove tower from towers array
- for (var i = towers.length - 1; i >= 0; i--) {
- if (towers[i] === selectedTower) {
- towers.splice(i, 1);
- break;
- }
- }
- // Destroy the tower
- selectedTower.destroy();
- selectedTower = null;
- // Remove delete button
- deleteButton.destroy();
- deleteButton = null;
- }
- };
- }
- };
- towers.push(newTower);
- // Check for enemies in range immediately after placing
- var enemiesInRange = [];
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- var distance = Math.sqrt(Math.pow(enemy.x - newTower.x, 2) + Math.pow(enemy.y - newTower.y, 2));
- if (distance <= 800) {
- enemiesInRange.push(enemy);
- }
- }
- // If enemies are in range, start attack immediately
- if (enemiesInRange.length > 0) {
- newTower.plasmaAttackActive = true;
- newTower.plasmaAttackStartTime = LK.ticks;
- newTower.plasmaRays = [];
- // Create 10 plasma ray assets
- for (var j = 0; j < 10; j++) {
- var angle = j * 36 * Math.PI / 180;
- var rayX = newTower.x + Math.cos(angle) * 150;
- var rayY = newTower.y + Math.sin(angle) * 150;
- var plasmaRay = game.addChild(LK.getAsset('Plasmaray1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: rayX,
- y: rayY,
- rotation: angle + Math.PI / 2,
- alpha: 0.8,
- scaleX: 0.8,
- scaleY: 0.8
- }));
- plasmaRay.createdTime = LK.ticks; // Track creation time for cleanup
- newTower.plasmaRays.push(plasmaRay);
- }
- // Deal damage to enemies in range
- for (var i = 0; i < enemiesInRange.length; i++) {
- var enemy = enemiesInRange[i];
- enemy.takeDamage(15);
- // Make electric effect visible when hit by plasma
- enemy.showElectricEffect();
- // Robot fires back when hit by plasma tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(newTower);
- }
- }
- }
- // Sort all towers by Y position (higher Y values should be in front)
- towers.sort(function (a, b) {
- return a.y - b.y;
- });
- // Re-add towers to game in sorted order, but ensure they render behind wave assets
- for (var i = 0; i < towers.length; i++) {
- game.removeChild(towers[i]);
- // Find the first wave asset in children to insert towers before it
- var waveAssetIndex = -1;
- for (var j = 0; j < game.children.length; j++) {
- var child = game.children[j];
- if (child.assetId === 'Wave1' || child.assetId === 'Wave2' || child.assetId === 'Wave3' || child.assetId === 'Wave4' || child.assetId === 'Wave5') {
- waveAssetIndex = j;
- break;
- }
- }
- if (waveAssetIndex >= 0) {
- // Insert tower before wave asset
- game.addChildAt(towers[i], waveAssetIndex);
- } else {
- // No wave asset found, add normally
- game.addChild(towers[i]);
- }
- // Re-add plasma if this tower has it to ensure it renders in front
- if (towers[i].plasma) {
- game.removeChild(towers[i].plasma);
- game.addChild(towers[i].plasma);
- // Restart plasma animation after re-adding
- animatePlasma(towers[i].plasma);
- }
- }
- // Deduct cost and update display
- playerCash -= 60;
- cashText.setText('Cash: $' + playerCash);
- // Clean up placement mode
- cleanupPlacementMode();
- }
- };
- }
- };
- // Add mystery button under fire button
- var mysteryButton2 = game.addChild(LK.getAsset('Mysterybutton', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 4 - 250 + 426.67 + 50 + 420 + 50 + 426 + 50 + 50,
- y: 2732 - 350 + 200 + 20
- }));
}
function spawnEnemy() {
- // Don't spawn enemies during cutscenes
- if (!gameplayActive) return;
if (enemiesSpawned >= maxEnemiesInWave) return;
- var enemy;
- // Check if we're in level 2 (after story1 scene has been shown)
- var isLevel2 = typeof window.isLevel2 !== 'undefined' ? window.isLevel2 : false;
- if (isLevel2 && currentWave === 1) {
- // Level 2 wave 1 - spawn Level2Enemy
- enemy = game.addChild(new Level2Enemy());
- enemy._assetId = 'Level2Enemy';
- // Implement gradual spawn speed increase for level 2 wave 1
- // Start at 15 seconds, gradually reduce to 3 seconds over the course of the wave
- var progressRatio = enemiesSpawned / maxEnemiesInWave;
- var newInterval = 900 - progressRatio * 540; // 900 ticks (15s) down to 360 ticks (6s)
- enemySpawnInterval = Math.max(180, newInterval); // Minimum 3 seconds
- } else if (isLevel2 && currentWave === 2) {
- // Level 2 wave 2 - spawn smaller and harder Level2Enemy instead of drones
- enemy = game.addChild(new Level2Enemy());
- enemy._assetId = 'Level2Enemy';
- // Make them smaller by scaling both axes
- enemy.scaleX = 0.7;
- enemy.scaleY = 0.7;
- // Make them much harder to kill - increase health significantly
- enemy.health = 1500; // Increased from 1000 to 1500
- enemy.maxHealth = 1500;
- } else if (isLevel2 && currentWave === 3) {
- // Level 2 wave 3 - spawn AliencarEnemy
- enemy = game.addChild(new AliencarEnemy());
- enemy._assetId = 'AliencarEnemy';
- } else if (isLevel2 && currentWave === 4) {
- // Level 2 wave 4 - spawn FlyingalienEnemy every 10 seconds
- enemySpawnInterval = 600; // 10 seconds at 60fps
- enemy = game.addChild(new FlyingalienEnemy());
- enemy._assetId = 'FlyingalienEnemy';
- } else if (currentWave === 1) {
- if (enemiesSpawned === 0) {
- LK.getSound('Probedroid').play();
- }
- enemy = game.addChild(new Enemy());
- } else if (currentWave === 2) {
- if (enemiesSpawned === 0) {
- LK.getSound('Probedroid2').play();
- }
- enemy = game.addChild(new Drone());
- } else if (currentWave === 3) {
- enemy = game.addChild(new Robot());
- } else if (currentWave === 4) {
- enemy = game.addChild(new SpaceDrone());
- enemy._assetId = 'SpaceDrone'; // Mark for deflection detection
- } else if (currentWave === 5 && !window.isLevel2) {
- enemy = game.addChild(new UFO());
- enemy._assetId = 'UFO'; // Mark as UFO boss
- }
- // Check if enemy was created before setting properties
- if (!enemy) {
- return; // Exit function if no enemy was created
- }
- if (currentWave === 5 && !window.isLevel2) {
- // Position UFO boss above the center of the screen (hover down from above)
- enemy.x = 2048 / 2; // Center horizontally
- enemy.y = -200; // Start above screen
- enemy.pathLine = 1;
- // Animate UFO hovering down from above
- tween(enemy, {
- y: 400
- }, {
- duration: 3000,
- easing: tween.easeInOut
- });
- enemy.health = 1200;
- enemy.maxHealth = 1200;
- enemy.speed = 0; // UFO doesn't move horizontally initially
- } else {
- // Position enemy at the right side of the screen
- enemy.x = 2048 - 50; // Start from right side
- // Randomly assign path from all 6 available lines
- var availableLines = [1, 2, 3, 4, 5, 6];
- var randomLineIndex = Math.floor(Math.random() * availableLines.length);
- var selectedLine = availableLines[randomLineIndex];
- // Set enemy position based on randomly selected line
- if (selectedLine === 1) {
- enemy.y = pathPositions.line1;
- enemy.pathLine = 1;
- } else if (selectedLine === 2) {
- enemy.y = pathPositions.line2;
- enemy.pathLine = 2;
- } else if (selectedLine === 3) {
- enemy.y = pathPositions.line3;
- enemy.pathLine = 3;
- } else if (selectedLine === 4) {
- enemy.y = pathPositions.line4;
- enemy.pathLine = 4;
- } else if (selectedLine === 5) {
- enemy.y = pathPositions.line5;
- enemy.pathLine = 5;
- } else if (selectedLine === 6) {
- enemy.y = pathPositions.line6;
- enemy.pathLine = 6;
- }
- enemy.health = 100;
- enemy.maxHealth = 100;
- enemy.speed = -2; // Negative speed to move left
- }
+ var enemy = game.addChild(new Enemy());
+ // Position enemy at the right side of the screen
+ enemy.x = 2048 - 50; // Start from right side
+ enemy.y = 2732 / 7 + 600; // First guideline position
+ enemy.health = 100;
+ enemy.maxHealth = 100;
+ enemy.speed = -2; // Negative speed to move left
enemy.pathIndex = 0;
enemy.lastPathIndex = -1;
+ // Set enemy number
+ enemy.numberText.setText((enemiesSpawned + 1).toString());
enemies.push(enemy);
enemiesSpawned++;
}
function updateEnemies() {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Move enemy using its speed (negative for left movement)
- enemy.x += enemy.speed * gameSpeed;
- // Check if enemy reached the left side of the screen (goal)
+ enemy.x += enemy.speed;
+ // Check if enemy reached the left side of the screen
if (enemy.lastX >= 0 && enemy.x < 0) {
- // Enemy reached the goal - player loses a life
- playerLives -= 1;
- // Update lives display using direct reference
- if (livesText) {
- livesText.setText('Lives: ' + playerLives);
- }
- // Check if player has no lives left
- if (playerLives <= 0) {
- // Game over - show game over screen
- LK.showGameOver();
- return;
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
// Enemy reached the left side - remove it
enemy.destroy();
enemies.splice(i, 1);
continue;
}
- // Optimize collision detection - only check towers within reasonable distance first
- var nearbyTowers = [];
- for (var j = 0; j < towers.length; j++) {
- var tower = towers[j];
- var quickDistance = Math.abs(enemy.x - tower.x) + Math.abs(enemy.y - tower.y); // Manhattan distance is faster
- if (quickDistance < 1200) {
- // Only consider towers within 1200 pixels
- nearbyTowers.push(tower);
- }
- }
- // Check each nearby tower type separately (no early exits)
- for (var j = 0; j < nearbyTowers.length; j++) {
- var tower = nearbyTowers[j];
- // Check if tower is a water tower (Tower1 asset)
- if (tower._assetId === 'Tower1') {
- // For UFO boss, check if tower can attack based on UFO's current position and pathLine
- var canAttackUFO = false;
- if (enemy._assetId === 'UFO' && enemy.pathLine && tower.pathLine) {
- // UFO can be attacked by towers on the same line when hovering
- if (Math.abs(enemy.pathLine - tower.pathLine) === 0) {
- canAttackUFO = true;
- }
- }
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance) OR can attack UFO
- if (Math.abs(enemy.y - tower.y) < 50 || canAttackUFO) {
- // For UFO, check if within range regardless of direction; for others, check right side and range
- var inRange = false;
- if (enemy._assetId === 'UFO') {
- // UFO can be attacked from any direction within range
- var distance = Math.sqrt(Math.pow(enemy.x - tower.x, 2) + Math.pow(enemy.y - tower.y, 2));
- inRange = distance < 700;
- } else {
- // Normal enemies must be to the right and within range
- inRange = enemy.x > tower.x && enemy.x - tower.x < 700;
- }
- if (inRange) {
- // Initialize fire rate tracking for this tower
- if (!tower.lastFireTime) {
- tower.lastFireTime = 0;
- }
- // Fire every 30 ticks (0.5 seconds at 60fps)
- if (LK.ticks - tower.lastFireTime >= 30 / gameSpeed) {
- tower.lastFireTime = LK.ticks;
- // Play water sound when tower attacks
- LK.getSound('Water').play();
- // Only create water squirt visual if we have less than 10 active squirts
- if (waterSquirts.length < 10) {
- var waterSquirt = game.addChild(LK.getAsset('Water', {
- anchorX: 0,
- anchorY: 0.5,
- x: tower.x,
- y: tower.y,
- scaleX: 0.3,
- scaleY: 0.1,
- alpha: 0.7,
- tint: 0x4169E1
- }));
- waterSquirt.createdTime = LK.ticks;
- waterSquirts.push(waterSquirt);
- // Simplified water squirt animation
- tween(waterSquirt, {
- scaleX: 0.35,
- alpha: 0.2
- }, {
- duration: 300,
- easing: tween.linear
- });
- // Auto-destroy after 2 seconds instead of complex tracking
- LK.setTimeout(function () {
- if (waterSquirt && waterSquirt.parent) {
- waterSquirt.destroy();
- var index = waterSquirts.indexOf(waterSquirt);
- if (index !== -1) waterSquirts.splice(index, 1);
- }
- }, 2000);
- }
- // Deal damage to enemy - reduced damage for UFO boss
- if (enemy._assetId === 'UFO') {
- enemy.takeDamage(4);
- } else {
- enemy.takeDamage(8);
- }
- // Make electric effect visible when hit by water
- enemy.showElectricEffect();
- // Robot fires back when hit by water tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(tower);
- }
- // Check if enemy is destroyed
- if (enemy.health <= 0) {
- // Create explosion effect when probedroid is destroyed by water
- var waterExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: enemy.x,
- y: enemy.y,
- scaleX: 0.3,
- scaleY: 0.3
- }));
- // Play explosion sound
- LK.getSound('Explosion').play();
- // Animate explosion with tween
- tween(waterExplosion, {
- scaleX: 1.2,
- scaleY: 1.2,
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- waterExplosion.destroy();
- }
- });
- enemy.destroy();
- enemies.splice(i, 1);
- // Give player money for destroying enemy
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Give player additional $5 cash for water tower kill
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Award 50 points for kill
- playerScore += 50;
- LK.setScore(playerScore);
- if (window.scoreText) {
- window.scoreText.setText('Score: ' + playerScore);
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
- // Track defeated enemies for win condition
- enemiesDefeated++;
- i--; // Adjust index since we removed an enemy
- return; // Exit function for this enemy
- }
- }
- }
- }
- }
- // Check if tower is a gas tower (Dog asset)
- if (tower._assetId === 'Dog') {
- // Check tower health before any firing logic - if dead, skip all processing
- if (tower.health <= 0) {
- continue; // Skip to next tower
- }
- // For UFO boss, check if tower can attack based on UFO's current position and pathLine
- var canAttackUFO = false;
- if (enemy._assetId === 'UFO' && enemy.pathLine && tower.pathLine) {
- // UFO can be attacked by towers on the same line when hovering
- if (Math.abs(enemy.pathLine - tower.pathLine) === 0) {
- canAttackUFO = true;
- }
- }
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance) OR can attack UFO
- if (Math.abs(enemy.y - tower.y) < 50 || canAttackUFO) {
- // For UFO, check if within range regardless of direction; for others, check right side and range
- var inRange = false;
- if (enemy._assetId === 'UFO') {
- // UFO can be attacked from any direction within range
- var distance = Math.sqrt(Math.pow(enemy.x - tower.x, 2) + Math.pow(enemy.y - tower.y, 2));
- inRange = distance < 600;
- } else {
- // Normal enemies must be to the right and within range
- inRange = enemy.x > tower.x && enemy.x - tower.x < 600;
- }
- if (inRange) {
- // Initialize fire rate tracking for this tower
- if (!tower.lastFireTime) {
- tower.lastFireTime = 0;
- }
- // Fire every 45 ticks (0.75 seconds at 60fps)
- if (LK.ticks - tower.lastFireTime >= 45 / gameSpeed) {
- tower.lastFireTime = LK.ticks;
- // Switch dog asset to dog1 for fart animation
- tower.destroy();
- var fartingDog = game.addChild(LK.getAsset('Dog1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: tower.x,
- y: tower.y,
- alpha: 1
- })); // Copy tower properties to the new farting dog
- fartingDog._assetId = 'Dog';
- fartingDog.health = tower.health;
- fartingDog.maxHealth = tower.maxHealth;
- fartingDog.isBeingDamaged = tower.isBeingDamaged;
- fartingDog.lastDamageTime = tower.lastDamageTime;
- fartingDog.lastFireTime = tower.lastFireTime;
- fartingDog.healthBarOutline = tower.healthBarOutline;
- fartingDog.healthBar = tower.healthBar;
- fartingDog.takeDamage = function (damage) {
- fartingDog.health -= damage;
- if (fartingDog.health <= 0) {
- fartingDog.health = 0;
- }
- // Update health bar
- var healthPercentage = fartingDog.health / fartingDog.maxHealth;
- fartingDog.healthBar.scaleX = healthPercentage;
- // Change color based on health
- if (healthPercentage > 0.6) {
- fartingDog.healthBar.tint = 0x00ff00; // Green
- } else if (healthPercentage > 0.3) {
- fartingDog.healthBar.tint = 0xffff00; // Yellow
- } else {
- fartingDog.healthBar.tint = 0xff0000; // Red
- }
- };
- // Replace tower in towers array
- for (var towerIndex = 0; towerIndex < towers.length; towerIndex++) {
- if (towers[towerIndex] === tower) {
- towers[towerIndex] = fartingDog;
- break;
- }
- }
- // Play fart sound when dog shoots gas cloud
- LK.getSound('Fart').play();
- // Create gas cloud visual
- var gasCloud = game.addChild(LK.getAsset('GasCloud', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: tower.x + 150,
- // Position gas cloud 100 pixels further left when dog farts
- y: tower.y,
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0.6,
- tint: 0x90EE90
- })); // Track gas cloud creation time and add to cleanup tracking
- gasCloud.createdTime = LK.ticks;
- gasClouds.push(gasCloud);
- // Animate gas cloud expanding and fading
- tween(gasCloud, {
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.2
- }, {
- duration: 1000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- gasCloud.destroy();
- }
- });
- // Switch back to normal dog after 500ms
- LK.setTimeout(function () {
- // Check if farting dog is still alive before replacing
- if (fartingDog.health <= 0) {
- // Farting dog is dead, don't replace it, just destroy it
- // Remove health bar components
- if (fartingDog.healthBarOutline) {
- fartingDog.healthBarOutline.destroy();
- }
- if (fartingDog.healthBar) {
- fartingDog.healthBar.destroy();
- }
- fartingDog.destroy();
- // Remove from towers array
- for (var towerIndex = towers.length - 1; towerIndex >= 0; towerIndex--) {
- if (towers[towerIndex] === fartingDog) {
- towers.splice(towerIndex, 1);
- break;
- }
- }
- return;
- }
- // Check if fartingDog still exists in towers array before replacing
- var fartingDogExists = false;
- for (var towerIndex = 0; towerIndex < towers.length; towerIndex++) {
- if (towers[towerIndex] === fartingDog) {
- fartingDogExists = true;
- break;
- }
- }
- if (!fartingDogExists) {
- // Farting dog was already destroyed, don't create replacement
- return;
- }
- fartingDog.destroy();
- var normalDog = game.addChild(LK.getAsset('Dog', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fartingDog.x,
- y: fartingDog.y,
- alpha: 1
- }));
- // Copy properties back to normal dog
- normalDog._assetId = 'Dog';
- normalDog.health = fartingDog.health;
- normalDog.maxHealth = fartingDog.maxHealth;
- normalDog.isBeingDamaged = fartingDog.isBeingDamaged;
- normalDog.lastDamageTime = fartingDog.lastDamageTime;
- normalDog.lastFireTime = fartingDog.lastFireTime;
- normalDog.healthBarOutline = fartingDog.healthBarOutline;
- normalDog.healthBar = fartingDog.healthBar;
- normalDog.takeDamage = fartingDog.takeDamage;
- // Check if normal dog should be destroyed immediately after replacement
- if (normalDog.health <= 0) {
- // Remove health bar components
- if (normalDog.healthBarOutline) {
- normalDog.healthBarOutline.destroy();
- }
- if (normalDog.healthBar) {
- normalDog.healthBar.destroy();
- }
- normalDog.destroy();
- // Remove from towers array
- for (var towerIndex = towers.length - 1; towerIndex >= 0; towerIndex--) {
- if (towers[towerIndex] === fartingDog) {
- towers.splice(towerIndex, 1);
- break;
- }
- }
- return;
- }
- // Replace in towers array
- for (var towerIndex = 0; towerIndex < towers.length; towerIndex++) {
- if (towers[towerIndex] === fartingDog) {
- towers[towerIndex] = normalDog;
- break;
- }
- }
- }, 500);
- // Check if enemy is affected by gas (farts don't affect robots, drones, or probe droids)
- var isAffectedByGas = true; // Check enemy asset ID to determine if it's a robot/mechanical enemy
- if (enemy.attachedAssets && enemy.attachedAssets.length > 0) {
- var enemyAssetId = enemy.attachedAssets[0].assetId;
- if (enemyAssetId === 'Robot' || enemyAssetId === 'Drone' || enemyAssetId === 'SpaceDrone' || enemyAssetId === 'Probedroid') {
- isAffectedByGas = false;
- }
- }
- // Only deal damage if enemy is affected by gas
- if (isAffectedByGas) {
- // Deal damage to enemy - reduced damage for UFO boss
- if (enemy._assetId === 'UFO') {
- enemy.takeDamage(1);
- } else {
- enemy.takeDamage(2);
- }
- // Move enemy to random adjacent row on guideline
- var currentLine = enemy.pathLine;
- var availableLines = [];
- // Add adjacent lines (above and below current line)
- if (currentLine > 1) availableLines.push(currentLine - 1);
- if (currentLine < 6) availableLines.push(currentLine + 1);
- // If we have adjacent lines available, move to one randomly
- if (availableLines.length > 0) {
- var randomIndex = Math.floor(Math.random() * availableLines.length);
- var newLine = availableLines[randomIndex];
- enemy.pathLine = newLine;
- // Get the new Y position for the new line
- var newY = pathPositions['line' + newLine];
- // Animate the enemy to the new line position
- tween(enemy, {
- y: newY
- }, {
- duration: 500,
- easing: tween.easeInOut
- });
- }
- // Robot fires back when hit by gas tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(fartingDog);
- }
- // Check if enemy is destroyed
- if (enemy.health <= 0) {
- enemy.destroy();
- enemies.splice(i, 1);
- // Give player money for destroying enemy
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Award 50 points for kill
- playerScore += 50;
- LK.setScore(playerScore);
- if (window.scoreText) {
- window.scoreText.setText('Score: ' + playerScore);
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
- // Track defeated enemies for win condition
- enemiesDefeated++;
- i--; // Adjust index since we removed an enemy
- return; // Exit function for this enemy
- }
- }
- }
- }
- }
- }
- // Check if tower is a bug zapper (electric tower)
- if (tower._assetId === 'Bugzapper') {
- // Initialize zap tracking arrays for this tower
- if (!tower.activeZaps) {
- tower.activeZaps = [];
- tower.zapTargets = [];
- }
- // For UFO boss, check if tower can attack based on UFO's current position and pathLine
- var canAttackUFO = false;
- if (enemy._assetId === 'UFO' && enemy.pathLine && tower.pathLine) {
- // UFO can be attacked by towers on the same line when hovering
- if (Math.abs(enemy.pathLine - tower.pathLine) === 0) {
- canAttackUFO = true;
- }
- }
- // Check if enemy is on the same horizontal line as the tower (within 100 pixels tolerance) OR can attack UFO
- if (Math.abs(enemy.y - tower.y) < 100 || canAttackUFO) {
- // For UFO, check if within range regardless of direction; for others, check right side and range
- var inRange = false;
- if (enemy._assetId === 'UFO') {
- // UFO can be attacked from any direction within range
- var distance = Math.sqrt(Math.pow(enemy.x - tower.x, 2) + Math.pow(enemy.y - tower.y, 2));
- inRange = distance < 800;
- } else {
- // Normal enemies must be to the right and within range
- inRange = enemy.x > tower.x && enemy.x - tower.x < 800;
- }
- if (inRange) {
- // Check if this is a SpaceDrone - SpaceDrones cannot be affected by electric attacks
- if (enemy._assetId === 'SpaceDrone') {
- // SpaceDrones are immune to electric attacks - skip all electric tower processing
- continue; // Skip to next tower
- }
- // Check if this enemy already has a zap effect
- var hasZapEffect = false;
- for (var zapIndex = 0; zapIndex < tower.zapTargets.length; zapIndex++) {
- if (tower.zapTargets[zapIndex] === enemy) {
- hasZapEffect = true;
- break;
- }
- }
- // Create new zap effect for this enemy if it doesn't have one
- if (!hasZapEffect) {
- // Create zap3 visual positioned at enemy's location
- var newZap = game.addChild(LK.getAsset('Zap3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: enemy.x - 400,
- y: enemy.y,
- scaleX: 1.0,
- scaleY: 1.0,
- alpha: 0.9,
- tint: 0x00FFFF
- }));
- // Play electric sound when zap effect is created
- LK.getSound('Electric').play();
- // Store zap effect and target
- tower.activeZaps.push(newZap);
- tower.zapTargets.push(enemy);
- // Start zap animation for this specific effect
- var _animateZap = function animateZap(zapEffect) {
- if (zapEffect && zapEffect.parent) {
- tween(zapEffect, {
- alpha: 0.3
- }, {
- duration: 200,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- if (zapEffect && zapEffect.parent) {
- tween(zapEffect, {
- alpha: 0.9
- }, {
- duration: 200,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- _animateZap(zapEffect);
- }
- });
- }
- }
- });
- }
- };
- _animateZap(newZap);
- // Deal initial damage immediately when zap starts - reduced for UFO boss
- if (enemy._assetId === 'UFO') {
- enemy.takeDamage(5);
- } else {
- enemy.takeDamage(10);
- }
- // Make electric effect visible when hit by electricity
- if (enemy.showElectricEffect) {
- enemy.showElectricEffect();
- }
- // Robot fires back when hit by electric tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(tower);
- }
- }
- // Deal damage every 20 ticks instead of 10 to reduce processing load
- if (hasZapEffect && LK.ticks % Math.max(1, Math.floor(20 / gameSpeed)) === 0) {
- // Deal damage to enemy - reduced damage for UFO boss
- if (enemy._assetId === 'UFO') {
- enemy.takeDamage(2);
- } else {
- enemy.takeDamage(5);
- }
- // Make electric effect visible when hit by electricity
- if (enemy.showElectricEffect) {
- enemy.showElectricEffect();
- }
- // Robot fires back when hit by electric tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(tower);
- }
- // Check if enemy is destroyed
- if (enemy.health <= 0) {
- // Create explosive effect when probedroid is destroyed by bugzapper
- var bugzapperExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: enemy.x,
- y: enemy.y,
- scaleX: 0.3,
- scaleY: 0.3
- }));
- // Play explosion sound
- LK.getSound('Explosion').play();
- // Animate explosion with tween
- tween(bugzapperExplosion, {
- scaleX: 1.2,
- scaleY: 1.2,
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- bugzapperExplosion.destroy();
- }
- });
- // Remove zap effect for this enemy
- for (var zapIndex = tower.activeZaps.length - 1; zapIndex >= 0; zapIndex--) {
- if (tower.zapTargets[zapIndex] === enemy) {
- tower.activeZaps[zapIndex].destroy();
- tower.activeZaps.splice(zapIndex, 1);
- tower.zapTargets.splice(zapIndex, 1);
- break;
- }
- }
- enemy.destroy();
- enemies.splice(i, 1);
- // Give player money for destroying enemy
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Award 50 points for kill
- playerScore += 50;
- LK.setScore(playerScore);
- if (window.scoreText) {
- window.scoreText.setText('Score: ' + playerScore);
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
- // Track defeated enemies for win condition
- enemiesDefeated++;
- i--; // Adjust index since we removed an enemy
- return; // Exit function for this enemy
- }
- }
- } else {
- // Enemy is not in range, remove its zap effect
- for (var zapIndex = tower.activeZaps.length - 1; zapIndex >= 0; zapIndex--) {
- if (tower.zapTargets[zapIndex] === enemy) {
- tower.activeZaps[zapIndex].destroy();
- tower.activeZaps.splice(zapIndex, 1);
- tower.zapTargets.splice(zapIndex, 1);
- break;
- }
- }
- }
- } else {
- // Enemy is not on same line, remove its zap effect
- for (var zapIndex = tower.activeZaps.length - 1; zapIndex >= 0; zapIndex--) {
- if (tower.zapTargets[zapIndex] === enemy) {
- tower.activeZaps[zapIndex].destroy();
- tower.activeZaps.splice(zapIndex, 1);
- tower.zapTargets.splice(zapIndex, 1);
- break;
- }
- }
- }
- }
- // Check if tower is a fire tower (Fireworks asset)
- if (tower._assetId === 'Fireworks') {
- // For UFO boss, check if tower can attack based on UFO's current position and pathLine
- var canAttackUFO = false;
- if (enemy._assetId === 'UFO' && enemy.pathLine && tower.pathLine) {
- // UFO can be attacked by towers on the same line when hovering
- if (Math.abs(enemy.pathLine - tower.pathLine) === 0) {
- canAttackUFO = true;
- }
- }
- // Check if enemy is on the same horizontal line as the tower (within 50 pixels tolerance) OR can attack UFO
- if (Math.abs(enemy.y - tower.y) < 50 || canAttackUFO) {
- // For UFO, check if within range regardless of direction; for others, check right side and range
- var inRange = false;
- if (enemy._assetId === 'UFO') {
- // UFO can be attacked from any direction within range
- var distance = Math.sqrt(Math.pow(enemy.x - tower.x, 2) + Math.pow(enemy.y - tower.y, 2));
- inRange = distance < 1500;
- } else {
- // Normal enemies must be to the right and within range
- inRange = enemy.x > tower.x && enemy.x - tower.x < 1500;
- }
- if (inRange) {
- // Initialize fire rate tracking for this tower
- if (!tower.lastFireTime) {
- tower.lastFireTime = 0;
- }
- // Fire every 60 ticks (1 second at 60fps)
- if (LK.ticks - tower.lastFireTime >= 60 / gameSpeed) {
- // Store fireball properties
- // Add fire animation to fireball
- var animateFireball = function animateFireball(fireball) {
- // Pulsing scale animation
- function startFireballPulse() {
- tween(fireball, {
- scaleX: 0.6,
- scaleY: 0.6,
- alpha: 0.8
- }, {
- duration: 200,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(fireball, {
- scaleX: 0.5,
- scaleY: 0.5,
- alpha: 1.0
- }, {
- duration: 200,
- easing: tween.easeInOut,
- onFinish: startFireballPulse
- });
- }
- });
- }
- // Flickering alpha animation
- function startFireballFlicker() {
- tween(fireball, {
- alpha: 0.7
- }, {
- duration: 150,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(fireball, {
- alpha: 1.0
- }, {
- duration: 100,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- LK.setTimeout(function () {
- if (fireball && fireball.parent) {
- startFireballFlicker();
- }
- }, Math.random() * 300 + 100);
- }
- });
- }
- });
- }
- // Start all fire animations
- startFireballPulse();
- startFireballFlicker();
- }; // Start fire animation for this fireball
- tower.lastFireTime = LK.ticks;
- // Play fireball sound when firing
- LK.getSound('Fireball').play();
- // Create fireball projectile
- var fireball = game.addChild(LK.getAsset('Fireball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: tower.x + 50,
- y: tower.y,
- scaleX: 0.5,
- scaleY: 0.5,
- rotation: 35 * Math.PI / 180 // Rotate 35 degrees to the right
- }));
- fireball.createdTime = LK.ticks; // Track creation time for cleanup
- animateFireball(fireball);
- fireball.targetX = enemy.x;
- fireball.targetY = enemy.y;
- fireball.speed = 8;
- fireball.damage = 10;
- // Calculate direction to enemy
- var deltaX = enemy.x - fireball.x;
- var deltaY = enemy.y - fireball.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- fireball.velocityX = deltaX / distance * fireball.speed;
- fireball.velocityY = deltaY / distance * fireball.speed;
- // Animate fireball movement with reduced frequency
- var fireballInterval = LK.setInterval(function () {
- fireball.x += fireball.velocityX * 2;
- fireball.y += fireball.velocityY * 2;
- // Check if fireball hit any enemy
- for (var enemyIndex = 0; enemyIndex < enemies.length; enemyIndex++) {
- var targetEnemy = enemies[enemyIndex];
- var fireballDistance = Math.sqrt(Math.pow(fireball.x - targetEnemy.x, 2) + Math.pow(fireball.y - targetEnemy.y, 2));
- if (fireballDistance < 80) {
- // Check if this is a SpaceDrone that is currently rotating
- if (targetEnemy._assetId === 'SpaceDrone' && targetEnemy.isRotating) {
- // Deflect fireball back at tower
- var deflectedFireball = game.addChild(LK.getAsset('Fireball', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fireball.x,
- y: fireball.y,
- scaleX: 0.5,
- scaleY: 0.5,
- rotation: fireball.rotation + Math.PI,
- tint: 0x0088FF // Blue tint to show it's deflected
- }));
- // Calculate direction back to tower
- var deltaX = tower.x - deflectedFireball.x;
- var deltaY = tower.y - deflectedFireball.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- deflectedFireball.velocityX = deltaX / distance * fireball.speed;
- deflectedFireball.velocityY = deltaY / distance * fireball.speed;
- deflectedFireball.damage = fireball.damage;
- // Animate deflected fireball movement
- var deflectedInterval = LK.setInterval(function () {
- deflectedFireball.x += deflectedFireball.velocityX;
- deflectedFireball.y += deflectedFireball.velocityY;
- // Check if deflected fireball hit the tower
- var deflectedDistance = Math.sqrt(Math.pow(deflectedFireball.x - tower.x, 2) + Math.pow(deflectedFireball.y - tower.y, 2));
- if (deflectedDistance < 100) {
- // Hit tower - deal damage
- tower.takeDamage(deflectedFireball.damage);
- LK.effects.flashObject(tower, 0xff0000, 300);
- // Remove deflected fireball
- LK.clearInterval(deflectedInterval);
- tween.stop(deflectedFireball);
- deflectedFireball.destroy();
- return;
- }
- // Check if deflected fireball went off screen
- if (deflectedFireball.x > 2048 + 100 || deflectedFireball.x < -100 || deflectedFireball.y > 2732 + 100 || deflectedFireball.y < -100) {
- LK.clearInterval(deflectedInterval);
- tween.stop(deflectedFireball);
- deflectedFireball.destroy();
- }
- }, 16);
- // Remove original fireball from tower's tracking array before clearing interval
- if (tower.fireballs && Array.isArray(tower.fireballs)) {
- for (var fireballIndex = tower.fireballs.length - 1; fireballIndex >= 0; fireballIndex--) {
- var fireballData = tower.fireballs[fireballIndex];
- if (fireballData && (fireballData.fireball === fireball || fireballData.interval === fireballInterval)) {
- tower.fireballs.splice(fireballIndex, 1);
- break;
- }
- }
- }
- // Remove original fireball
- LK.clearInterval(fireballInterval);
- tween.stop(fireball);
- fireball.destroy();
- return;
- }
- // Hit enemy - deal damage, reduced for UFO boss
- if (targetEnemy._assetId === 'UFO') {
- targetEnemy.takeDamage(fireball.damage / 2);
- } else {
- targetEnemy.takeDamage(fireball.damage);
- }
- // Robot fires back when hit by fire tower
- if (targetEnemy.fireBackAtTower) {
- targetEnemy.fireBackAtTower(tower);
- }
- // Create explosion effect
- var explosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: fireball.x,
- y: fireball.y,
- scaleX: 0.3,
- scaleY: 0.3
- }));
- // Play explosion sound
- LK.getSound('Explosion').play();
- // Animate explosion
- tween(explosion, {
- scaleX: 0.8,
- scaleY: 0.8,
- alpha: 0
- }, {
- duration: 500,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- explosion.destroy();
- }
- });
- // Check if enemy is destroyed
- if (targetEnemy.health <= 0) {
- // Check if this is a mechanical enemy that should have explosion effect
- var isMechanicalEnemy = false;
- if (targetEnemy.attachedAssets && targetEnemy.attachedAssets.length > 0) {
- var enemyAssetId = targetEnemy.attachedAssets[0].assetId;
- if (enemyAssetId === 'Robot' || enemyAssetId === 'Drone' || enemyAssetId === 'SpaceDrone' || enemyAssetId === 'Probedroid' || enemyAssetId === 'UFO') {
- isMechanicalEnemy = true;
- }
- }
- // For probe droids (current enemy type), always show explosion
- if (!isMechanicalEnemy) {
- // Check if this is a probe droid by checking the asset used
- var enemyChildren = targetEnemy.children;
- for (var childIndex = 0; childIndex < enemyChildren.length; childIndex++) {
- var child = enemyChildren[childIndex];
- if (child.assetId === 'Probedroid') {
- isMechanicalEnemy = true;
- break;
- }
- }
- }
- // Create explosion effect for mechanical enemies
- if (isMechanicalEnemy) {
- var mechanicalExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: targetEnemy.x,
- y: targetEnemy.y,
- scaleX: 0.2,
- scaleY: 0.2
- }));
- // Play explosion sound
- LK.getSound('Explosion').play();
- // Animate explosion with tween
- tween(mechanicalExplosion, {
- scaleX: 1.0,
- scaleY: 1.0,
- alpha: 0
- }, {
- duration: 800,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- mechanicalExplosion.destroy();
- }
- });
- }
- targetEnemy.destroy();
- enemies.splice(enemyIndex, 1);
- // Give player money for destroying enemy
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Give player additional $10 cash for fire tower kill
- playerCash += 10;
- cashText.setText('Cash: $' + playerCash);
- // Award 50 points for kill
- playerScore += 50;
- LK.setScore(playerScore);
- if (window.scoreText) {
- window.scoreText.setText('Score: ' + playerScore);
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
- // Track defeated enemies for win condition
- enemiesDefeated++;
- }
- // Remove fireball from tower's tracking array before clearing interval
- if (tower.fireballs && Array.isArray(tower.fireballs)) {
- for (var fireballIndex = tower.fireballs.length - 1; fireballIndex >= 0; fireballIndex--) {
- var fireballData = tower.fireballs[fireballIndex];
- if (fireballData && (fireballData.fireball === fireball || fireballData.interval === fireballInterval)) {
- tower.fireballs.splice(fireballIndex, 1);
- break;
- }
- }
- }
- // Remove fireball
- LK.clearInterval(fireballInterval);
- tween.stop(fireball);
- fireball.destroy();
- return;
- }
- }
- // Check if fireball went off screen
- if (fireball.x > 2048 + 100 || fireball.x < -100 || fireball.y > 2732 + 100 || fireball.y < -100) {
- // Remove fireball from tower's tracking array when it goes off-screen
- if (tower.fireballs && Array.isArray(tower.fireballs)) {
- for (var fireballIndex = tower.fireballs.length - 1; fireballIndex >= 0; fireballIndex--) {
- var fireballData = tower.fireballs[fireballIndex];
- if (fireballData && (fireballData.fireball === fireball || fireballData.interval === fireballInterval)) {
- tower.fireballs.splice(fireballIndex, 1);
- break;
- }
- }
- }
- LK.clearInterval(fireballInterval);
- tween.stop(fireball);
- fireball.destroy();
- }
- }, 32); // ~30fps for fireballs to reduce processing load
- // Track fireball and its interval in the fireballs array for this tower
- if (tower.fireballs && Array.isArray(tower.fireballs)) {
- tower.fireballs.push({
- fireball: fireball,
- interval: fireballInterval
- });
- }
- break; // Found an enemy in range, no need to check other towers of this type
- }
- }
- }
- }
- }
- // Check collision with fan blades first (before tower collision)
- for (var k = 0; k < towers.length; k++) {
- var tower = towers[k];
- // Check if this tower has blades (fan tower) and is running (not in cooldown)
- if (tower.blades && tower.isRunning && !tower.cooldownActive) {
- // Initialize blade collision tracking for this enemy-tower pair
- if (!enemy.collidingBlades) {
- enemy.collidingBlades = {};
- }
- // Check if enemy intersects with fan blades
- var enemyWidth = 150; // Half width of probedroid
- var enemyHeight = 183; // Half height of probedroid
- var bladeWidth = 75; // Half width of blades
- var bladeHeight = 75; // Half height of blades
- var isCollidingWithBlades = Math.abs(enemy.x - tower.blades.x) < (enemyWidth + bladeWidth) / 2 && Math.abs(enemy.y - tower.blades.y) < (enemyHeight + bladeHeight) / 2;
- // Track blade collision state transitions
- var wasCollidingWithBlades = enemy.collidingBlades[k] || false;
- // Handle blade collision start
- if (!wasCollidingWithBlades && isCollidingWithBlades) {
- // Collision with blades just started
- enemy.collidingBlades[k] = true;
- // Push enemy back 400 pixels to the right
- var pushbackDistance = 400;
- var targetX = enemy.x + pushbackDistance;
- // Make sure enemy doesn't go off screen
- if (targetX > 2048 - 50) {
- targetX = 2048 - 50;
- }
- // Animate pushback using tween
- tween(enemy, {
- x: targetX
- }, {
- duration: 500,
- easing: tween.easeOut
- });
- // Inflict damage to enemy
- enemy.takeDamage(25);
- // Flash enemy to show damage
- LK.effects.flashObject(enemy, 0x0088ff, 300);
- // Robot fires back when hit by fan tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(tower);
- }
- // Check if enemy is destroyed
- if (enemy.health <= 0) {
- enemy.destroy();
- enemies.splice(i, 1);
- // Give player money for destroying enemy
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Award 50 points for kill
- playerScore += 50;
- LK.setScore(playerScore);
- if (window.scoreText) {
- window.scoreText.setText('Score: ' + playerScore);
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
- // Track defeated enemies for win condition
- enemiesDefeated++;
- i--; // Adjust index since we removed an enemy
- break; // Exit tower loop for this enemy
- }
- } else if (!isCollidingWithBlades && wasCollidingWithBlades) {
- // Collision with blades just ended
- enemy.collidingBlades[k] = false;
- }
- }
- }
- // Check if enemy is colliding with any tower
- for (var k = 0; k < towers.length; k++) {
- var tower = towers[k];
- // Initialize collision tracking for this enemy-tower pair
- if (!enemy.collidingTowers) {
- enemy.collidingTowers = {};
- }
- // Check if enemy intersects with tower (use proper collision detection)
- var enemyWidth = 150; // Half width of probedroid
- var enemyHeight = 183; // Half height of probedroid
- var towerWidth = 100; // Half width of tower
- var towerHeight = 100; // Half height of tower
- var isColliding = Math.abs(enemy.x - tower.x) < (enemyWidth + towerWidth) / 2 && Math.abs(enemy.y - tower.y) < (enemyHeight + towerHeight) / 2;
- // Track collision state transitions
- var wasColliding = enemy.collidingTowers[k] || false;
- // Handle collision start
- if (!wasColliding && isColliding) {
- // Collision just started
- enemy.collidingTowers[k] = true;
- // Stop enemy movement
- enemy.speed = 0;
- // Mark tower as being damaged
- tower.isBeingDamaged = true;
- tower.lastDamageTime = LK.ticks;
- // Flash both objects to show collision
- LK.effects.flashObject(enemy, 0xffff00, 200);
- LK.effects.flashObject(tower, 0xff0000, 200);
- }
- // Handle ongoing collision
- if (isColliding) {
- // Deal damage every 30 ticks (0.5 seconds at 60fps)
- if (tower.isBeingDamaged && LK.ticks - tower.lastDamageTime >= 30 / gameSpeed) {
- // Flash tower red to show damage
- LK.effects.flashObject(tower, 0xff0000, 300);
- // Deal damage to tower
- tower.takeDamage(10);
- tower.lastDamageTime = LK.ticks;
- // Check if tower is destroyed - mark for destruction but don't destroy here
- if (tower.health <= 0) {
- // Resume enemy movement after destroying tower
- enemy.speed = -2;
- // Clear collision tracking for this tower
- delete enemy.collidingTowers[k];
- // Flash enemy green to show it can continue
- LK.effects.flashObject(enemy, 0x00ff00, 500);
- }
- }
- } else {
- // No longer colliding
- if (wasColliding) {
- // Collision just ended
- enemy.collidingTowers[k] = false;
- tower.isBeingDamaged = false;
- // Resume enemy movement if not colliding with any towers
- var stillColliding = false;
- for (var key in enemy.collidingTowers) {
- if (enemy.collidingTowers[key]) {
- stillColliding = true;
- break;
- }
- }
- if (!stillColliding) {
- enemy.speed = -2;
- }
- }
- }
- }
// Update last position for next frame
enemy.lastX = enemy.x;
}
}
-// Display the title - They Came For Our WiFi
+// Display the title
// Import tween plugin
-LK.playMusic('Intro');
var titleImage = game.addChild(LK.getAsset('Title', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 + 1400
}));
+// Add cell asset to title screen
+var cellImage = game.addChild(LK.getAsset('cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2 + 800
+}));
// Add skip intro button to top of title screen
var skipButton = new Text2('SKIP INTRO', {
size: 60,
fill: 0xFFFFFF
@@ -6303,236 +183,8 @@
skipButton.anchor.set(0.5, 0);
skipButton.x = 2048 / 2;
skipButton.y = 150;
game.addChild(skipButton);
-// Function to animate plasma pulsation and flicker
-function animatePlasma(plasma) {
- if (!plasma) return;
- // Create pulsation animation - scale up and down
- function startPulsation() {
- tween(plasma, {
- scaleX: 1.3,
- scaleY: 1.3
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(plasma, {
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: startPulsation
- });
- }
- });
- }
- // Create flicker animation - alpha changes
- function startFlicker() {
- tween(plasma, {
- alpha: 0.5
- }, {
- duration: 300,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(plasma, {
- alpha: 1.0
- }, {
- duration: 400,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Random delay before next flicker
- LK.setTimeout(function () {
- startFlicker();
- }, Math.random() * 1000 + 200);
- }
- });
- }
- });
- }
- // Start both animations
- startPulsation();
- startFlicker();
-}
-// Function to handle plasma tower prolonged attack
-function handlePlasmaAttack(tower) {
- // Check if this tower has plasma (is a plasma tower)
- if (!tower.plasma) return;
- // If tower is destroyed, stop all plasma attacks immediately
- if (tower.health <= 0) {
- if (tower.plasmaAttackActive) {
- tower.plasmaAttackActive = false;
- // Clean up all plasma rays for this destroyed tower
- if (tower.plasmaRays) {
- for (var rayIndex = 0; rayIndex < tower.plasmaRays.length; rayIndex++) {
- if (tower.plasmaRays[rayIndex] && tower.plasmaRays[rayIndex].parent) {
- tower.plasmaRays[rayIndex].destroy();
- }
- }
- tower.plasmaRays = [];
- }
- }
- return;
- }
- // Initialize plasma attack tracking
- if (!tower.plasmaAttackActive) {
- tower.plasmaAttackActive = false;
- tower.plasmaRays = [];
- tower.plasmaAttackStartTime = 0;
- }
- // Check for enemies within 800 pixels radius
- var enemiesInRange = [];
- for (var i = 0; i < enemies.length; i++) {
- var enemy = enemies[i];
- var distance = Math.sqrt(Math.pow(enemy.x - tower.x, 2) + Math.pow(enemy.y - tower.y, 2));
- if (distance <= 800) {
- enemiesInRange.push(enemy);
- }
- }
- // If enemies are in range and attack is not active, start attack
- if (enemiesInRange.length > 0 && !tower.plasmaAttackActive) {
- tower.plasmaAttackActive = true;
- tower.plasmaAttackStartTime = LK.ticks;
- // Create 6 plasma ray assets instead of 10 for better performance
- var _loop2 = function _loop2() {
- angle = j * 60 * Math.PI / 180; // 360 degrees / 6 rays = 60 degrees each
- rayX = tower.x + Math.cos(angle) * 150;
- rayY = tower.y + Math.sin(angle) * 150;
- plasmaRay = game.addChild(LK.getAsset('Plasmaray1', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: rayX,
- y: rayY,
- rotation: angle + Math.PI / 2,
- // Rotate to point outward
- alpha: 0.8,
- scaleX: 0.8,
- scaleY: 0.8
- }));
- plasmaRay.createdTime = LK.ticks; // Track creation time for cleanup
- tower.plasmaRays.push(plasmaRay);
- // Animate plasma ray with pulsing effect
- function animatePlasmaRay(ray) {
- tween(ray, {
- alpha: 0.4,
- scaleX: 1.2,
- scaleY: 1.2
- }, {
- duration: 400,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(ray, {
- alpha: 0.9,
- scaleX: 0.8,
- scaleY: 0.8
- }, {
- duration: 400,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- if (tower.plasmaAttackActive) {
- animatePlasmaRay(ray);
- }
- }
- });
- }
- });
- }
- animatePlasmaRay(plasmaRay);
- },
- angle,
- rayX,
- rayY,
- plasmaRay;
- for (var j = 0; j < 6; j++) {
- _loop2();
- }
- }
- // If attack is active, deal damage to enemies in range
- if (tower.plasmaAttackActive && enemiesInRange.length > 0) {
- // Deal damage every 20 ticks
- if ((LK.ticks - tower.plasmaAttackStartTime) % Math.max(1, Math.floor(20 / gameSpeed)) === 0) {
- for (var i = 0; i < enemiesInRange.length; i++) {
- var enemy = enemiesInRange[i];
- // Reduce damage for UFO boss
- if (enemy._assetId === 'UFO') {
- enemy.takeDamage(3);
- } else {
- enemy.takeDamage(5);
- }
- // Make electric effect visible when hit by plasma
- enemy.showElectricEffect();
- // Robot fires back when hit by plasma tower
- if (enemy.fireBackAtTower) {
- enemy.fireBackAtTower(tower);
- }
- // Check if enemy is destroyed
- if (enemy.health <= 0) {
- // Create explosion effect
- var plasmaExplosion = game.addChild(LK.getAsset('Explosion', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: enemy.x,
- y: enemy.y,
- scaleX: 0.3,
- scaleY: 0.3
- }));
- // Play explosion sound
- LK.getSound('Explosion').play();
- // Animate explosion
- tween(plasmaExplosion, {
- scaleX: 1.2,
- scaleY: 1.2,
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- plasmaExplosion.destroy();
- }
- });
- enemy.destroy();
- for (var k = 0; k < enemies.length; k++) {
- if (enemies[k] === enemy) {
- enemies.splice(k, 1);
- break;
- }
- }
- // Give player money for destroying enemy
- playerCash += 5;
- cashText.setText('Cash: $' + playerCash);
- // Award 50 points for kill
- playerScore += 50;
- LK.setScore(playerScore);
- if (window.scoreText) {
- window.scoreText.setText('Score: ' + playerScore);
- }
- // Track wave completion
- if (currentWave === 1) {
- wave1EnemiesCompleted++;
- } else if (currentWave === 2) {
- wave2EnemiesCompleted++;
- } else if (currentWave === 3) {
- wave3EnemiesCompleted++;
- }
- // Track defeated enemies for win condition
- enemiesDefeated++;
- }
- }
- }
- }
- // If no enemies in range and attack is active, or tower is destroyed, stop attack
- if (enemiesInRange.length === 0 && tower.plasmaAttackActive || tower.health <= 0) {
- tower.plasmaAttackActive = false;
- // Remove all plasma rays
- for (var j = 0; j < tower.plasmaRays.length; j++) {
- if (tower.plasmaRays[j] && tower.plasmaRays[j].parent) {
- tower.plasmaRays[j].destroy();
- }
- }
- tower.plasmaRays = [];
- }
-}
// Function to skip directly to backdrop scene
function skipToBackdrop() {
// Stop all tweens
tween.stop(titleImage);
@@ -6557,19 +209,11 @@
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 800,
alpha: 1,
- scaleX: 0.1,
- scaleY: 0.1
- }));
- // Zoom in flyby to final size
- tween(backdropFlyby, {
scaleX: 0.8,
scaleY: 0.8
- }, {
- duration: 2000,
- easing: tween.easeInOut
- });
+ }));
// Store the original Y position for backdrop flyby
var backdropFlybyOriginalY = backdropFlyby.y;
// Make flyby move off the right side of backdrop scene
tween(backdropFlyby, {
@@ -6577,10 +221,8 @@
}, {
duration: 6000,
easing: tween.linear,
onFinish: function onFinish() {
- // Stop music when flyby leaves backdrop scene
- LK.stopMusic();
// After flyby has left the backdrop scene, fade in wave1 asset
var wave1Asset = game.addChild(LK.getAsset('Wave1', {
anchorX: 0.5,
anchorY: 0.5,
@@ -6594,9 +236,9 @@
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
- // Keep wave1 visible for 2 seconds then fade out
+ // Keep wave1 visible for 3 seconds then fade out
LK.setTimeout(function () {
tween(wave1Asset, {
alpha: 0
}, {
@@ -6607,9 +249,9 @@
// Start first wave of tower defense game
startTowerDefenseWave1();
}
});
- }, 2000);
+ }, 3000);
}
});
}
});
@@ -6617,53 +259,28 @@
var lineSpacing = 2732 / 7;
for (var i = 1; i <= 6; i++) {
var yPosition = lineSpacing * i;
if (i === 1) {
- yPosition += 480 + 50; // Move guideline 1 down by 480 pixels
+ yPosition += 600; // Move guideline 1 down by 600 pixels
} else if (i === 2) {
- yPosition += 320 + 50; // Move guideline 2 down by 320 pixels
+ yPosition += 420; // Move guideline 2 down by 420 pixels
} else if (i === 3) {
- yPosition += 150 + 50; // Move guideline 3 down by 150 pixels
+ yPosition += 250; // Move guideline 3 down by 250 pixels
} else if (i === 4) {
- yPosition += 10 + 50; // Move guideline 4 down by 10 pixels
+ yPosition += 120; // Move guideline 4 down by 120 pixels
} else if (i === 5) {
- yPosition -= 150 - 50; // Move guideline 5 up by 150 pixels
+ yPosition -= 50; // Move guideline 5 up by 50 pixels
} else if (i === 6) {
- yPosition -= 310 - 50; // Move guideline 6 up by 310 pixels
+ yPosition -= 200; // Move guideline 6 up by 200 pixels
}
var guideLine = game.addChild(LK.getAsset('guideLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: yPosition,
- alpha: 0
+ alpha: 0.5
}));
- // Store guideline reference and add click handler
- guidelines.push(guideLine);
- guideLine.lineNumber = i;
- guideLine.down = function (x, y, obj) {
- if (isPlacingTower && towerPreview) {
- // Move tower preview to clicked position on guideline
- // x and y are already in the local coordinate space of the guideline
- towerPreview.x = x;
- towerPreview.y = this.y; // Use the guideline's Y position
- }
- };
}
- // Add vertical guidelines for column placement
- var columnSpacing = 2048 / 9; // Create 8 columns with margins
- for (var i = 1; i <= 8; i++) {
- var xPosition = columnSpacing * i;
- var verticalGuideLine = game.addChild(LK.getAsset('verticalGuideLine', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: xPosition,
- y: 2732 / 2,
- alpha: 0
- }));
- verticalGuidelines.push(verticalGuideLine);
- verticalGuideLine.columnNumber = i;
- }
}
// Add touch event to skip button
skipButton.down = function (x, y, obj) {
skipToBackdrop();
@@ -6728,30 +345,15 @@
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
}));
- // Add wifi asset to intro
- var wifiAsset = game.addChild(LK.getAsset('WiFi', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2 + 200,
- y: 2732 / 2 + 200,
- alpha: 0
- }));
// Tween alpha from 0 to 1 for fade-in effect
tween(introAsset, {
alpha: 1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
- // Also fade in wifi asset
- tween(wifiAsset, {
- alpha: 1
- }, {
- duration: 2000,
- easing: tween.easeInOut
- });
// After intro has faded in, make flyby move from left to right
flybyImage.x = -375; // Reset flyby to left side
flybyImage.y = 2732 / 2; // Center vertically
tween(flybyImage, {
@@ -6766,15 +368,8 @@
}, {
duration: 2000,
easing: tween.easeInOut
});
- // Also fade out wifi asset
- tween(wifiAsset, {
- alpha: 0
- }, {
- duration: 2000,
- easing: tween.easeInOut
- });
// Add backdrop asset to game
var backdropAsset = game.addChild(LK.getAsset('backdrop', {
anchorX: 0.5,
anchorY: 0.5,
@@ -6789,11 +384,11 @@
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 800,
- alpha: 1,
- scaleX: 0.1,
- scaleY: 0.1
+ alpha: 0,
+ scaleX: 0.8,
+ scaleY: 0.8
}));
// Store the original Y position for backdrop flyby
var backdropFlybyOriginalY = backdropFlyby.y;
// Make flyby move off the right side of backdrop scene
@@ -6803,10 +398,8 @@
}, {
duration: 6000,
easing: tween.linear,
onFinish: function onFinish() {
- // Stop music when flyby leaves backdrop scene
- LK.stopMusic();
// After flyby has left the backdrop scene, fade in wave1 asset
var wave1Asset = game.addChild(LK.getAsset('Wave1', {
anchorX: 0.5,
anchorY: 0.5,
@@ -6820,9 +413,9 @@
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
- // Keep wave1 visible for 2 seconds then fade out
+ // Keep wave1 visible for 3 seconds then fade out
LK.setTimeout(function () {
tween(wave1Asset, {
alpha: 0
}, {
@@ -6833,9 +426,9 @@
// Start first wave of tower defense game
startTowerDefenseWave1();
}
});
- }, 2000);
+ }, 3000);
}
});
}
});
@@ -6846,70 +439,44 @@
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
- // Zoom in backdrop flyby
+ // Fade in backdrop flyby
tween(backdropFlyby, {
- scaleX: 0.8,
- scaleY: 0.8
+ alpha: 1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
- // Start flyby movement to right side after zoom in
+ // Start flyby movement to right side after fade in
startBackdropFlybyHover();
}
});
// Add 6 horizontal guide lines after backdrop fades in
var lineSpacing = 2732 / 7; // Divide screen height by 7 to get 6 lines with margins
for (var i = 1; i <= 6; i++) {
var yPosition = lineSpacing * i;
if (i === 1) {
- yPosition += 480 + 50; // Move guideline 1 down by 480 pixels
+ yPosition += 600; // Move guideline 1 down by 600 pixels
} else if (i === 2) {
- yPosition += 320 + 50; // Move guideline 2 down by 320 pixels
+ yPosition += 420; // Move guideline 2 down by 420 pixels
} else if (i === 3) {
- yPosition += 150 + 50; // Move guideline 3 down by 150 pixels
+ yPosition += 250; // Move guideline 3 down by 250 pixels
} else if (i === 4) {
- yPosition += 10 + 50; // Move guideline 4 down by 10 pixels
+ yPosition += 120; // Move guideline 4 down by 120 pixels
} else if (i === 5) {
- yPosition -= 150 - 50; // Move guideline 5 up by 150 pixels
+ yPosition -= 50; // Move guideline 5 up by 50 pixels
} else if (i === 6) {
- yPosition -= 310 - 50; // Move guideline 6 up by 310 pixels
+ yPosition -= 200; // Move guideline 6 up by 200 pixels
}
var guideLine = game.addChild(LK.getAsset('guideLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: yPosition,
- alpha: 0
+ alpha: 0.5
}));
- // Store guideline reference and add click handler
- guidelines.push(guideLine);
- guideLine.lineNumber = i;
- guideLine.down = function (x, y, obj) {
- if (isPlacingTower && towerPreview) {
- // Move tower preview to clicked position on guideline
- // x and y are already in the local coordinate space of the guideline
- towerPreview.x = x;
- towerPreview.y = this.y; // Use the guideline's Y position
- }
- };
}
- // Add vertical guidelines for column placement
- var columnSpacing = 2048 / 9; // Create 8 columns with margins
- for (var i = 1; i <= 8; i++) {
- var xPosition = columnSpacing * i;
- var verticalGuideLine = game.addChild(LK.getAsset('verticalGuideLine', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: xPosition,
- y: 2732 / 2,
- alpha: 0
- }));
- verticalGuidelines.push(verticalGuideLine);
- verticalGuideLine.columnNumber = i;
- }
}
});
}
});
White circle with two eyes, seen from above.. In-Game asset. 2d. High contrast. No shadows
White simple circular enemy seen from above, black outline. Black eyes, with a single shield in-font of it. Black and white only. Blue background.
White circle with black outline. Blue background.. In-Game asset. 2d. High contrast. No shadows
Fire hydrant. In-Game asset. 2d. High contrast. No shadows
Water spraying forward In-Game asset. 2d. High contrast. No shadows
Fart cloud. In-Game asset. 2d. High contrast. No shadows
Fan blades symmetrical. In-Game asset. 2d. High contrast. No shadows
Fireball. In-Game asset. 2d. High contrast. No shadows
Plasma ball. In-Game asset. 2d. High contrast. No shadows
Make picture transparent
Bug zapper on a pole. In-Game asset. 2d. High contrast. No shadows
Probe droid. In-Game asset. 2d. High contrast. No shadows
Space drone. In-Game asset. 2d. High contrast. No shadows
Remove propellers and make them symmetrical
Add more rows to gris
Make this picture with more night sky above the city skyline
Change text to say wave 1
Make button grey and say ??????
Make it say Wave 2
Make it say wave 3
Make it say wave 4
WiFi symbol. In-Game asset. 2d. High contrast. No shadows
explosion effect In-Game asset. 2d. High contrast. No shadows
Make it say wave 5
Remove laser beam
Make button hot pink and say 'Reflect $20'
Make button blue and change text to say 'Water $10' in a retro style font
Make button green and change test to say 'Gas $20'
Make button orange and change test to say 'Fire $40'
Make button very light blue and change test to say 'Air $30'
Make button gold and change text to say 'Electric $50'
Make button purple and change test to say 'Plasma $60'
Make button Teal and change test to say 'Slingshot $100'
Make button silver and change test to say 'WiFi $150'
Remove little kick so it's just a smooth oval shape
Make grid 6x8
Hand should be holding the gun by the Handle
Place laser cannon in both hands holding it like a shotgun
Make it stand still
Remove the words 5g
Make sure spelling in speech bubble is correct "We have found the earthlings weakness"
Fix the spelling of the word Planet
Slingshot. In-Game asset. 2d. High contrast. No shadows
Red button with a 'X' on it. In-Game asset. 2d. High contrast. No shadows
Green button with a tick on it
Fix the spelling of word saw
Canvasser
Sound effect
Alien1
Sound effect
Alien2
Sound effect
Alien3
Sound effect
Intro
Music
Probedroid
Sound effect
Probedroid2
Sound effect
Towerselect
Sound effect
Water
Sound effect
Explosion
Sound effect
Confirm
Sound effect
Fart
Sound effect
Electric
Sound effect
Fireball
Sound effect