/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Background = Container.expand(function () {
	var self = Container.call(this);
	var backgroundGraphics = LK.getAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(backgroundGraphics);
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	// Move the down handler to the Background class
	self.down = function (x, y, obj) {
		var game_position = game.toLocal(obj.global);
		target.x = Math.max(corners[0].x, Math.min(game_position.x, corners[3].x));
		target.y = Math.max(corners[0].y, Math.min(game_position.y, corners[3].y));
	};
});
var Bonus = Container.expand(function (x, y) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	// Create shadow for bonus
	var shadowBonus = LK.getAsset('bonusHealth', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	shadowBonus.alpha = 0.5;
	shadowBonus.tint = 0x000000;
	shadowBonus.x = 10; // Offset shadow position
	shadowBonus.y = 10; // Offset shadow position
	self.addChild(shadowBonus);
	self.active = false;
	var bonusGraphics = LK.getAsset('bonusHealth', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(bonusGraphics);
	self.bonusLight = LK.getAsset('bonusHealthLight', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0x00FF00
	});
	self.addChild(self.bonusLight);
	self.animLight = function () {
		function loopTint() {
			tween(self.bonusLight, {
				tint: 0xFFFFFF
			}, {
				duration: 600,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(self.bonusLight, {
						tint: 0x00FF00
					}, {
						duration: 600,
						easing: tween.easeInOut,
						onFinish: loopTint
					});
				}
			});
		}
		loopTint();
	};
	self.animLight();
	self.animMove = function () {
		function loopMove() {
			tween(self, {
				y: self.y + 10
			}, {
				duration: 500,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(self, {
						y: self.y - 10
					}, {
						duration: 500,
						easing: tween.easeInOut,
						onFinish: loopMove
					});
				}
			});
		}
		loopMove();
	};
	self.throwToCorner = function () {
		// Calculate a random position within range instead of using corners
		var minDistance = 1024;
		var maxDistance = 1480;
		// Generate random angle
		var randomAngle = Math.random() * Math.PI * 2;
		// Calculate random distance within range
		var randomDistance = minDistance + Math.random() * (maxDistance - minDistance);
		// Calculate target position
		var targetX = self.x + Math.cos(randomAngle) * randomDistance;
		var targetY = self.y + Math.sin(randomAngle) * randomDistance;
		// Ensure target is within the playable area (within corners)
		targetX = Math.max(borderOffset, Math.min(2048 - borderOffset, targetX));
		targetY = Math.max(borderOffset, Math.min(2732 - borderOffset, targetY));
		// Calculate control point for parabolic motion
		var controlX = (self.x + targetX) / 2;
		var controlY = Math.min(self.y, targetY) - 500; // Control point above the line for a parabolic effect
		// Initial position
		var startX = self.x;
		var startY = self.y;
		// Create a tween for parabolic motion
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: 1200,
			easing: tween.easeOutQuad,
			onUpdate: function onUpdate() {
				// Calculate parabolic path using quadratic Bezier curve formula
				var t = this.progress;
				self.x = Math.pow(1 - t, 2) * startX + 2 * (1 - t) * t * controlX + Math.pow(t, 2) * targetX;
				self.y = Math.pow(1 - t, 2) * startY + 2 * (1 - t) * t * controlY + Math.pow(t, 2) * targetY;
				// Add rotation for visual effect
				self.rotation = t * Math.PI * 3; // 1.5 full rotations during flight
			},
			onFinish: function onFinish() {
				self.rotation = 0; // Reset rotation
				self.active = true; // Activate bonus after reaching the corner
				self.animMove();
			}
		});
	};
	self.throwToCorner(); // Call the function to start the animation
});
var ButtonPunch = Container.expand(function () {
	var self = Container.call(this);
	var buttonGraphics = LK.getAsset('buttonPunch', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(buttonGraphics);
	// Add click/tap handler
	self.down = function () {
		// Trigger knight attack when button is pressed
		if (!isDied && knight && knight.health >= 0 && !knight.isAttacking) {
			knight.attack();
		}
	};
});
// Import the tween plugin
var Drone = Container.expand(function (level) {
	var self = Container.call(this);
	self.level = level || 0; // Set level to the passed parameter or default to 0
	self.health = (isDebug ? 2 : 4) + self.level * 2; // Add level*2 to drone's health
	var droneWidth = 200;
	// Increase size based on level
	var levelGrowth = self.level * self.level * 80;
	self.droneScanLaser = LK.getAsset('droneScanLaser', {
		anchorX: 0,
		anchorY: 0.5
	});
	self.droneScanLaser.visible = true; // Always visible
	self.droneScanLaser.x = droneWidth / 2;
	self.droneScanLaser.alpha = 0.3; // Set alpha to 0.3
	self.droneScanLaser.width += levelGrowth;
	self.droneScanLaser.height += levelGrowth;
	self.addChild(self.droneScanLaser);
	self.droneScanBar = LK.getAsset('droneScanBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	self.droneScanBar.x = droneWidth / 2;
	self.droneScanBar.blendMode = 3;
	self.droneScanBar.width = self.droneScanLaser.width;
	self.addChild(self.droneScanBar);
	var droneGraphics = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: droneWidth,
		height: droneWidth
	});
	var shadowDrone = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: droneWidth,
		height: droneWidth
	});
	self.shadowOffset = {
		x: -30,
		y: 40
	}; // Define shadow offset property
	shadowDrone.alpha = 0.5;
	shadowDrone.tint = 0x000000;
	shadowDrone.x = -10;
	shadowDrone.y = 40;
	self.addChild(shadowDrone);
	self.addChild(droneGraphics);
	// Add health bar under the drone
	self.healthBar = LK.getAsset('healthBar', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 100,
		height: 10,
		color: 0x00FF00 // Green color for health
	});
	self.healthBar.y = droneWidth / 2 + 20; // Position the health bar under the drone
	self.addChild(self.healthBar);
	function loopScanLaserTint() {
		if (self.state !== 'scanning') {
			return;
		}
		tween(self.droneScanLaser, {
			tint: 0x00FF00
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanLaser, {
					tint: 0x00AA00
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: loopScanLaserTint // Recursively call to loop
				});
			}
		});
	}
	function animateScanBar() {
		if (self.state !== 'scanning') {
			return;
		}
		tween(self.droneScanBar, {
			alpha: 0.3,
			rotation: Math.PI / 6.75
		}, {
			duration: 600 - self.level * 50,
			//{V} // Decrease duration to increase frequency with level
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanBar, {
					alpha: 0.6,
					rotation: -Math.PI / 6.75
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: animateScanBar // Recursively call to loop
				}); // Ensure the tween is started
			}
		}); // Ensure the tween is started
	}
	self.speed = 5;
	self.state = ''; // Possible states: scanning, attacking
	// Add debug text to track drone state
	self.debugText = new Text2(self.state, {
		size: 50,
		fill: 0xFFFFFF
	});
	self.debugText.x = -droneGraphics.width / 2;
	self.debugText.y = -droneGraphics.height / 2 - 50;
	self.debugText.visible = isDebug; // Set visibility based on debug mode
	self.addChild(self.debugText);
	self.fireRange = 300; // Example fire range value
	self.fireDelay = 1200;
	self.currentTargetIndex = -1;
	self.target = {
		x: 0,
		y: 0
	};
	self.lastKnightCheckTime = 0; // Track when we last checked for knight intersection
	self.lastFireTime = 0; // Track when we last fired at the knight
	self.lastRotationTime = 0; // Track the last time we updated rotation
	self.isRotating = false; // Flag to track if we're currently rotating
	self.isMoving = false; // Flag to track if we're currently moving
	self.needsRotation = false; // Flag to track if we need to rotate before moving
	self.justSwitchedFromAttacking = false; // Flag to track if we just switched from attacking mode
	// Function to select a new random target
	self.selectTarget = function () {
		log("selectTarget...:");
		var newTargetIndex;
		do {
			newTargetIndex = Math.floor(Math.random() * corners.length);
		} while (newTargetIndex === self.currentTargetIndex);
		self.currentTargetIndex = newTargetIndex;
		self.target = corners[newTargetIndex];
		log("New target selected at position:", self.target.x, self.target.y);
		// Set a flag to indicate the target is new and needs rotation first
		self.needsRotation = true;
		// Return the new target (not used currently but could be useful)
		return self.target;
	};
	// Function to fire a laser beam
	self.fire = function () {
		log("Drone firing laser beam...");
		LK.getSound('drone-beam').play();
		var laserBeam = new LaserBeam();
		laserBeam.fire(self.x, self.y, self.rotation);
	};
	// Function to handle state transitions
	self.switchState = function (newState) {
		// Don't do anything if the state isn't changing
		if (self.state === newState) {
			return;
		}
		log("Switching drone state from " + self.state + " to " + newState);
		// Stop any existing tweens to ensure clean state transition
		tween.stop(self);
		// Clear scan sound interval if it exists
		if (self.scanSoundInterval) {
			LK.clearInterval(self.scanSoundInterval);
			self.scanSoundInterval = null;
		}
		// Reset movement flags
		self.isRotating = false;
		self.isMoving = false;
		self.justSwitchedFromAttacking = newState === 'scanning' && self.state === 'attacking';
		// Update the state
		self.state = newState;
		self.debugText.setText(self.state); // Update debug text with current state
		// Handle entry actions for new state
		if (newState === 'scanning') {
			// Play drone-scan sound
			self.scanSoundInterval = LK.setInterval(function () {
				LK.getSound('drone-scan').play();
			}, 1000);
			// Entering scanning state
			self.debugText.tint = 0xFFFFFF; // Reset tint to white for other states
			self.droneScanLaser.tint = 0x00FF00; // Reset tint to green for scanning mode
			// Clear current target and set flag to select a new one
			//self.target = null;
			//self.needsRotation = true;
			animateScanBar();
			// Select a new target (this will be handled in updateScanning on next update)
		} else if (newState === 'attacking') {
			// don't fire directly, consider a part of fire delay
			self.lastFireTime = Date.now();
			// Entering attacking state
			self.debugText.tint = 0xFFA500; // Change tint to orange when attacking
			self.droneScanLaser.tint = 0xFFA500; // Change tint to orange when attacking
			// Start following the knight
			self.followKnight();
		}
	};
	self.init = function () {
		log("Drone initialized at position:", self.x, self.y);
		// Reset state flags
		self.isRotating = false;
		self.isMoving = false;
		self.needsRotation = true;
		// Start the animations
		animateScanBar();
		loopScanLaserTint();
		// Switch to scanning state to begin patrol
		self.switchState('scanning');
	};
	self.collectBonus = function collectBonus(bonus) {
		// Increase knight's health by 2
		knight.health += 2;
		// Play knight-bonus sound
		LK.getSound('knight-bonus').play();
		// Destroy the bonus
		bonus.destroy();
	};
	self.update = function () {
		if (self.state === 'scanning') {
			self.updateScanning();
		} else if (self.state === 'attacking') {
			self.updateAttacking();
		}
		// Update health bar width and color regardless of state
		self.healthBar.width = Math.max(0, (self.health + 1) / 4 * 100); // Assuming max health is 4
		// Change health bar color based on health
		var healthPercentage = self.health / 4; // Assuming max health is 4
		var red, green;
		// Transition from green to orange
		if (healthPercentage > 0.5) {
			red = Math.min(255, Math.floor((1 - healthPercentage) * 2 * 255));
			green = 255;
		} else {
			// Transition from orange to red
			red = 255;
			green = Math.min(255, Math.floor(healthPercentage * 2 * 255));
		}
		self.healthBar.tint = red << 16 | green << 8; // Combine red and green to form the color
		// Iterate over all bonuses in the middlegroundContainer
		for (var i = middlegroundContainer.children.length - 1; i >= 0; i--) {
			var child = middlegroundContainer.children[i];
			if (child instanceof Bonus) {
				// Check if knight's boundingBox intersects with bonusLight
				if (child.active && knight.boundingBox.intersects(child.bonusLight)) {
					self.collectBonus(child);
				}
			}
		}
		// Update shadow position
		shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation);
		shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation);
		// Update droneScanBar width based on its rotation
		self.droneScanBar.width = self.droneScanLaser.width * (1 + 0.1 * Math.abs(Math.sin(self.droneScanBar.rotation)));
	};
	// Function to perform a full 360° scan
	self.performFullScan = function (callback) {
		// Calculate duration based on a consistent rotation speed
		var scanRotationSpeed = 1.0; // Radians per second (slower for scanning)
		var fullRotationDuration = Math.PI * 2 / scanRotationSpeed * 1000; // ms
		// Store current rotation
		var startRotation = self.rotation;
		// Mark that we're rotating to prevent updateScanning from starting other rotations
		self.isRotating = true;
		log("Performing 360° scan");
		// Perform a full 360° rotation
		tween(self, {
			rotation: startRotation + Math.PI * 2 // Full 360° rotation
		}, {
			duration: fullRotationDuration,
			easing: tween.linear,
			// Linear easing for constant speed
			onFinish: function onFinish() {
				// Clear rotation flag when done
				self.isRotating = false;
				log("Full scan complete");
				// Call callback if provided
				if (callback) {
					callback();
				}
			}
		});
	};
	// Handle scanning mode behavior
	self.updateScanning = function () {
		// Check for intersection with knight
		if (!isDied && self.droneScanBar.intersects(knight.boundingBox)) {
			self.switchState('attacking');
			log("Drone switched to attacking mode!");
			return;
		}
		// If no target is set, select one
		if (!self.target) {
			log("No target set, selecting a new one");
			// If we just switched from attacking to scanning mode, do a 360° scan first
			if (self.justSwitchedFromAttacking) {
				self.justSwitchedFromAttacking = false;
				self.fire();
				// Perform full scan before selecting a new target
				self.performFullScan(function () {
					// After scan is complete, select a new target
					self.selectTarget();
				});
				return;
			}
			// Otherwise just select a new target
			self.selectTarget();
			return;
		}
		// Calculate direction and distance to target
		var dx = self.target.x - self.x;
		var dy = self.target.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// If very close to target, select a new one
		if (distance < 10) {
			log("Reached target, selecting a new one");
			self.selectTarget();
			return;
		}
		// Calculate target angle
		var targetAngle = Math.atan2(dy, dx);
		// Check if rotation is needed
		var angleDiff = Math.abs(calculateAngleDiff(targetAngle, self.rotation));
		// If rotation is needed (more than 0.1 radians difference or flag is set)
		if (angleDiff > 0.1 || self.needsRotation) {
			// Only start a new rotation if not already rotating
			if (!self.isRotating) {
				log("Rotating to face target");
				self.isRotating = true;
				// Use the updateRotation function with callback to clear isRotating flag
				self.updateRotation(targetAngle, 600, function () {
					self.isRotating = false;
					self.needsRotation = false;
					log("Rotation complete");
				});
			}
		}
		// If rotation is close enough and we're not currently moving, start movement
		else if (!self.isMoving) {
			log("Starting movement to target");
			self.isMoving = true;
			// Calculate duration based on distance
			var moveSpeed = 0.2; // Adjust this value to control drone speed
			var duration = distance / moveSpeed;
			// Start moving toward the target
			tween(self, {
				x: self.target.x,
				y: self.target.y
			}, {
				duration: duration,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					self.isMoving = false;
					log("Movement complete");
					// Don't automatically select a new target, let updateScanning handle it
				}
			});
		}
	};
	// Handle attacking mode behavior
	self.updateAttacking = function () {
		var currentTime = Date.now();
		// Fire using separate counter
		if (currentTime - self.lastFireTime > self.fireDelay) {
			// Fire every 1.2 seconds
			self.lastFireTime = currentTime;
			self.fire();
		}
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var angle = Math.atan2(dy, dx);
		// Drone rotation logic - directly rotate the drone to face the knight
		// Only do smooth rotation tracking when not already moving to a new position
		//self.lastRotationTime = currentTime;
		// Calculate a smoother intermediate angle for natural tracking
		var currentAngle = self.rotation;
		var angleDiff = calculateAngleDiff(angle, currentAngle);
		// Only rotate a portion of the way to the target for smoother tracking
		// This creates a slight lag effect that looks more natural
		var partialAngle = currentAngle + angleDiff * 0.3;
		// Directly set rotation instead of using updateRotation
		self.rotation = partialAngle;
		//self.isRotating = false; // No need for callback since we're setting directly
		// Rotate droneScanBar to point at knight within limits
		var relativeAngle = calculateAngleDiff(angle, self.rotation);
		// Clamp the scan bar rotation to the maximum allowed range
		var maxRotation = Math.PI / 6.5;
		var clampedRotation = Math.max(-maxRotation, Math.min(maxRotation, relativeAngle));
		// Set the scan bar rotation directly
		self.droneScanBar.rotation = clampedRotation;
		self.droneScanBar.alpha = 0.1;
		// First check if knight is still in range - do this every second
		if (currentTime - self.lastKnightCheckTime > 1000) {
			self.lastKnightCheckTime = currentTime;
			// Check if we can still see the knight
			if (!self.droneScanBar.intersects(knight.boundingBox)) {
				log("Knight lost! Returning to scanning mode.");
				self.switchState('scanning');
				return;
			}
			log("Knight still in range at distance: " + distance);
		}
		// Position update logic - if we're not currently moving but need to
		if (isDied) {
			log("Knight is dead, returning to scanning mode.");
			self.switchState('scanning');
			return;
		}
		if (!self.isMoving && distance > 550) {
			log("Knight moved - updating drone position");
			// Move to a better position
			self.followKnight();
			return;
		}
	};
	self.followKnight = function () {
		log("followKnight...");
		// Cancel any existing movement tweens
		tween.stop(self);
		// Calculate direction to knight
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var angle = Math.atan2(dy, dx);
		// Set the movement flag
		self.isMoving = true;
		self.isRotating = true;
		// After rotation is complete, start moving toward knight
		self.moveTowardKnight();
	};
	// Function to calculate distance to knight
	self.distanceToKnight = function () {
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		return Math.sqrt(dx * dx + dy * dy);
	};
	self.moveTowardKnight = function () {
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// If already within the desired distance, stop moving
		if (distance <= 500) {
			return;
		}
		// Calculate target position that's 500 units away from knight
		var ratio = (distance - 500) / distance;
		var targetX = self.x + dx * ratio;
		var targetY = self.y + dy * ratio;
		// Move toward the target
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: distance * 2,
			// Speed based on distance
			easing: tween.linear,
			onUpdate: function onUpdate() {
				// Update rotation to continuously face the knight during movement
				var currentDx = knight.x - self.x;
				var currentDy = knight.y - self.y;
				var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy);
				// Only update rotation if not very close to the target
				if (currentDistance > 10) {
					var currentAngle = Math.atan2(currentDy, currentDx);
					// Calculate target rotation with a smaller adjustment for smoothness using the utility function
					var newRotation = self.rotation + calculateAngleDiff(currentAngle, self.rotation) * 0.1;
					// Create a separate quick tween for the rotation
					tween(self, {
						rotation: newRotation
					}, {
						duration: 600,
						// Very short duration for responsive updates
						easing: tween.linear
					});
				}
			},
			onFinish: function onFinish() {
				// Check if we're still in attacking mode before continuing to follow
				if (self.state === 'attacking') {
					// Check if knight has moved and we need to follow again
					if (self.distanceToKnight() > 500) {
						self.moveTowardKnight();
					}
				}
			}
		});
	};
	self.updateRotation = function (targetAngle, maxDuration, callback) {
		maxDuration = maxDuration || 500; // Default max duration if not specified
		// Cancel any existing rotation tweens to prevent conflicts
		tween.stop(self, 'rotation');
		// Normalize angles to be between -PI and PI for proper comparison
		var normalizedCurrentAngle = self.rotation % (2 * Math.PI);
		if (normalizedCurrentAngle > Math.PI) {
			normalizedCurrentAngle -= 2 * Math.PI;
		}
		if (normalizedCurrentAngle < -Math.PI) {
			normalizedCurrentAngle += 2 * Math.PI;
		}
		// Normalize target angle
		var normalizedTargetAngle = targetAngle % (2 * Math.PI);
		if (normalizedTargetAngle > Math.PI) {
			normalizedTargetAngle -= 2 * Math.PI;
		}
		if (normalizedTargetAngle < -Math.PI) {
			normalizedTargetAngle += 2 * Math.PI;
		}
		// Calculate the angle difference using the normalized angles
		var angleDiff = calculateAngleDiff(normalizedTargetAngle, normalizedCurrentAngle);
		var absDiff = Math.abs(angleDiff);
		// If the angle difference is greater than PI, rotate in the shorter direction
		if (absDiff > Math.PI) {
			if (angleDiff > 0) {
				angleDiff -= 2 * Math.PI;
			} else {
				angleDiff += 2 * Math.PI;
			}
		}
		// Calculate duration based on angle difference to achieve constant rotation speed
		// Use radians per second as the speed unit
		var rotationSpeed = 6; // Radians per second
		var duration = Math.min(absDiff / rotationSpeed * 1000, maxDuration);
		// Ensure a minimum duration for very small rotations
		duration = Math.max(duration, 50);
		// Calculate the target rotation by adding the angle difference to the current rotation
		var targetRotation = self.rotation + angleDiff;
		// Log the rotation parameters for debugging
		log("Rotating: angle diff=" + absDiff + ", duration=" + duration + "ms");
		// Perform the rotation tween
		tween(self, {
			rotation: targetRotation
		}, {
			duration: duration,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				log("Rotation complete");
				if (callback) {
					callback();
				}
			}
		});
	};
	self.takeHit = function (bullet) {
		// Play drone-hit sound
		LK.getSound('drone-hit').play();
		// Flash the drone red to indicate damage
		droneGraphics.tint = 0xff0000; // Red tint
		// After a short delay, restore the original tint
		LK.setTimeout(function () {
			droneGraphics.tint = 0xFFFFFF; // Restore original color
		}, 200);
		// Log hit for debugging
		log("Drone hit by attack!");
		// Reduce health when hit
		self.health -= 1;
		// Check if drone is destroyed
		if (self.health <= 0) {
			log("Drone destroyed!");
			self.explode();
			return;
		}
		// Switch to attacking state immediately if not already attacking
		if (self.state !== 'attacking') {
			self.switchState('attacking');
		}
		// Reset the lastKnightCheckTime to ensure we don't immediately check for knight visibility
		self.lastKnightCheckTime = Date.now();
		// Add knockback effect based on bullet direction
		var knockbackDistance = 50;
		var knockbackAngle = bullet.rotation;
		// Calculate potential new position
		var newX = self.x + Math.cos(knockbackAngle) * knockbackDistance;
		var newY = self.y + Math.sin(knockbackAngle) * knockbackDistance;
		// Check if new position would be too close to a corner
		var tooCloseToCorner = false;
		var cornerSafeDistance = 100; // Distance to stay away from corners
		for (var i = 0; i < corners.length; i++) {
			var dx = newX - corners[i].x;
			var dy = newY - corners[i].y;
			var distToCorner = Math.sqrt(dx * dx + dy * dy);
			if (distToCorner < cornerSafeDistance) {
				tooCloseToCorner = true;
				break;
			}
		}
		// If too close to a corner, adjust the knockback to push away from corner
		if (tooCloseToCorner) {
			// Find the center of the playfield
			var centerX = (corners[0].x + corners[3].x) / 2;
			var centerY = (corners[0].y + corners[3].y) / 2;
			// Calculate direction toward center
			var dxToCenter = centerX - self.x;
			var dyToCenter = centerY - self.y;
			var angleToCenter = Math.atan2(dyToCenter, dxToCenter);
			// Use this angle for knockback instead
			newX = self.x + Math.cos(angleToCenter) * knockbackDistance;
			newY = self.y + Math.sin(angleToCenter) * knockbackDistance;
		}
		// Clamp new position using corners
		newX = Math.max(corners[0].x + cornerSafeDistance, Math.min(newX, corners[3].x - cornerSafeDistance));
		newY = Math.max(corners[0].y + cornerSafeDistance, Math.min(newY, corners[3].y - cornerSafeDistance));
		// Apply knockback using tween
		tween(self, {
			x: newX,
			y: newY
		}, {
			duration: 200,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				// After knockback, immediately rotate the drone toward the knight
				// Calculate angle to knight
				var dx = knight.x - self.x;
				var dy = knight.y - self.y;
				var angleToKnight = Math.atan2(dy, dx);
				// Calculate the angle difference for proper duration
				var normalizedCurrentAngle = self.rotation % (2 * Math.PI);
				if (normalizedCurrentAngle > Math.PI) {
					normalizedCurrentAngle -= 2 * Math.PI;
				}
				if (normalizedCurrentAngle < -Math.PI) {
					normalizedCurrentAngle += 2 * Math.PI;
				}
				var normalizedTargetAngle = angleToKnight % (2 * Math.PI);
				if (normalizedTargetAngle > Math.PI) {
					normalizedTargetAngle -= 2 * Math.PI;
				}
				if (normalizedTargetAngle < -Math.PI) {
					normalizedTargetAngle += 2 * Math.PI;
				}
				var angleDiff = calculateAngleDiff(normalizedTargetAngle, normalizedCurrentAngle);
				if (Math.abs(angleDiff) > Math.PI) {
					if (angleDiff > 0) {
						angleDiff -= 2 * Math.PI;
					} else {
						angleDiff += 2 * Math.PI;
					}
				}
				// Calculate duration based on angle difference
				var rotationSpeed = 6; // Radians per second
				var absDiff = Math.abs(angleDiff);
				var duration = Math.min(absDiff / rotationSpeed * 1000, 500);
				duration = Math.max(duration, 50); // Ensure minimum duration
				// Rotate drone to face knight with calculated duration
				tween(self, {
					rotation: self.rotation + angleDiff
				}, {
					duration: duration,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						// Switch to attacking state if not already attacking
						if (self.state !== 'attacking') {
							self.switchState('attacking');
						}
						// Reset the lastKnightCheckTime to ensure we don't immediately check for knight visibility
						self.lastKnightCheckTime = Date.now();
					}
				});
			}
		});
	};
	self.explode = function () {
		// Simply destroy the drone
		tween.stop(self); // Stop all tweens on the drone
		var explosion = new Explosion();
		explosion.init(self.x, self.y);
		middlegroundContainer.addChild(explosion);
		// Clear scan sound interval if it exists
		if (self.scanSoundInterval) {
			LK.clearInterval(self.scanSoundInterval);
			self.scanSoundInterval = null;
		}
		LK.getSound('drone-explode').play();
		// Spawn a bonus at the drone's position
		var bonus = new Bonus(self.x, self.y);
		middlegroundContainer.addChild(bonus);
		self.destroy();
		droneManager.start();
	};
});
var Explosion = Container.expand(function () {
	var self = Container.call(this);
	for (var i = 0; i < 30; i++) {
		var particle = LK.getAsset('explosionParticle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		var scale = Math.random() * 0.5 + 0.5; // Random scale between 0.5 and 1.0
		particle.scale.set(scale);
		var colors = [0xFF4500, 0xFF6347, 0xFFFFFF, 0xFFFF00, 0x8B0000]; // Array of colors: orange, red, white, yellow, dark red
		particle.tint = colors[Math.floor(Math.random() * colors.length)]; // Randomly choose a color from the array
		var angle = Math.random() * Math.PI * 2; // Random direction
		var speed = Math.random() * 5 + 100; // Random speed between 2 and 7
		particle.vx = Math.cos(angle) * speed;
		particle.vy = Math.sin(angle) * speed;
		particle.rotation = angle; // Rotate particle in the direction of movement
		self.addChild(particle);
	}
	// Initialize explosion properties
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		self.scale.set(0.8); // Start small
		self.alpha = 1.0; // Fully visible
		// Animate the explosion
		var particles = self.children;
		var duration = 2000; // Duration for particles to move and fade out
		particles.forEach(function (particle) {
			tween(particle, {
				x: particle.x + particle.vx * duration / 1000,
				y: particle.y + particle.vy * duration / 1000,
				alpha: 0.0
			}, {
				duration: duration,
				easing: tween.easeOut
			});
		});
		LK.setTimeout(function () {
			self.destroy(); // Remove explosion after animation
		}, duration);
	};
});
var ExplosionKnight = Container.expand(function () {
	var self = Container.call(this);
	for (var i = 0; i < 80; i++) {
		var particle = LK.getAsset('explosionParticle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		var scale = Math.random() * 0.5 + 0.5; // Random scale between 0.5 and 1.0
		particle.scale.set(scale);
		particle.tint = 0x000000; // Set particle color to black
		var speed = 100 + Math.random() * 100; // Random speed between 2 and 7
		particle.vx = 0; // No horizontal movement
		particle.vy = -speed; // Negative vertical movement
		particle.rotation = Math.PI / 2; // Rotate by PI/2
		self.addChild(particle);
	}
	// Initialize explosion properties
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		self.scale.set(0.8); // Start small
		self.alpha = 1.0; // Fully visible
		// Animate the explosion
		var particles = self.children;
		var duration = 2000; // Duration for particles to move and fade out
		particles.forEach(function (particle) {
			particle.x += -40 + Math.random() * 80;
			particle.y += -40 + Math.random() * 80;
			tween(particle, {
				x: particle.x + particle.vx * duration / 500,
				y: particle.y + particle.vy * duration / 500,
				alpha: 0.0,
				scaleY: 0
			}, {
				duration: duration,
				easing: tween.easeOut
			});
		});
		LK.setTimeout(function () {
			self.destroy(); // Remove explosion after animation
		}, duration);
	};
});
var Knight = Container.expand(function () {
	var self = Container.call(this);
	self.health = isDebug ? 10 : 3; // Initialize health property with a value of 3
	// Add boundingBox for collision detection
	self.boundingBox = LK.getAsset('boundingBox', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 80,
		height: 150,
		y: -50
	});
	self.addChild(self.boundingBox);
	self.boundingBox.alpha = isDebug ? 0.5 : 0; // Set to false if you don't want it visible
	var directionMapping = {
		'down-left': 'dir1',
		'left': 'dir2',
		'up-left': 'dir3',
		'up': 'dir4',
		'up-right': 'dir5',
		'right': 'dir6',
		'down-right': 'dir7',
		'down': 'dir8'
	};
	// Pre-create a list of assets for each direction
	var knightAssets = {};
	var shadowAssets = {}; // Shadow assets for the knight
	var knightIdleAssets = {}; // Idle assets for the knight
	var shadowIdleAssets = {}; // Shadow idle assets for the knight
	var knightAttackAssets = {}; // Attack assets for the knight
	var shadowAttackAssets = {}; // Shadow attack assets for the knight
	var color = 0xFFFFFF; // Original blue / 0xff4d4d; // Red / 0x9aff9a; // Green
	// Initialize run animation assets
	for (var dir in directionMapping) {
		knightAssets[dir] = [];
		shadowAssets[dir] = []; // Initialize shadow assets array for each direction
		knightAttackAssets[dir] = []; // Initialize attack assets array for each direction
		shadowAttackAssets[dir] = []; // Initialize shadow attack assets array for each direction
		// Load run animation frames (8 frames)
		for (var i = 1; i <= 8; i++) {
			var frameNumber = i.toString().padStart(3, '0');
			// Create knight sprite
			knightAssets[dir].push(LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5,
				tint: color
			}));
			// Create shadow sprite using the same assets but with modifications
			var shadowSprite = LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Apply shadow properties
			shadowSprite.alpha = 0.5;
			shadowSprite.tint = 0x000000;
			shadowSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (π/12 radians)
			shadowSprite.scale.y = 0.5; // Flatten the shadow vertically
			shadowAssets[dir].push(shadowSprite);
		}
		// Load attack animation frames (15 frames)
		for (var i = 1; i <= 15; i++) {
			var frameNumber = i.toString().padStart(3, '0');
			// Create attack sprite
			knightAttackAssets[dir].push(LK.getAsset('knight-attack-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5,
				tint: color
			}));
			// Create shadow attack sprite using the same assets but with modifications
			var shadowAttackSprite = LK.getAsset('knight-attack-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Apply shadow properties
			shadowAttackSprite.alpha = 0.5;
			shadowAttackSprite.tint = 0x000000;
			shadowAttackSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (π/12 radians)
			shadowAttackSprite.scale.y = 0.5; // Flatten the shadow vertically
			shadowAttackAssets[dir].push(shadowAttackSprite);
		}
		// Initialize idle animation assets (one frame per direction)
		knightIdleAssets[dir] = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5,
			tint: color
		});
		// Create shadow for idle animation
		var shadowIdleSprite = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow properties
		shadowIdleSprite.alpha = 0.5;
		shadowIdleSprite.tint = 0x000000;
		shadowIdleSprite.rotation = Math.PI / 12;
		shadowIdleSprite.scale.y = 0.5;
		shadowIdleAssets[dir] = shadowIdleSprite;
	}
	var currentFrame = 0;
	var animationSpeed = 0.2; // Controls how fast the animation plays
	var frameCounter = 0;
	var knightGraphics = knightIdleAssets['down']; // Initialize with the 'down' direction idle asset
	var shadowGraphics = shadowIdleAssets['down']; // Initialize shadow with the 'down' direction idle asset
	// Add health bar under the knight
	self.healthBar = LK.getAsset('healthBar', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 100,
		height: 10,
		color: 0x00FF00 // Green color for health
	});
	self.healthBar.y = 60; // Position the health bar under the knight
	self.addChild(self.healthBar);
	// Add shadow first (so it appears behind the knight)
	self.addChild(shadowGraphics);
	// Then add the knight
	self.addChild(knightGraphics);
	knightGraphics.anchor.set(0.5, 0.5);
	knightGraphics.visible = true;
	shadowGraphics.visible = true;
	// Position the shadow slightly offset from the knight
	var shadowOffsetX = -5;
	var shadowOffsetY = 20;
	shadowGraphics.x = shadowOffsetX;
	shadowGraphics.y = shadowOffsetY;
	self.lastDirection = 'down'; // Initialize lastDirection to track previous direction
	self.isMoving = false; // Track if the knight is currently moving
	self.isAttacking = false; // Track if the knight is currently attacking
	self.speed = 9;
	var distanceThreshold = 8; // Define a threshold to avoid small movements
	var directionThreshold = 5; // Define a threshold for direction changes to avoid shaking
	self.update = function () {
		// Update health bar width based on knight's health
		self.healthBar.width = Math.max(0, (self.health + 1) / 4 * 100); // Assuming max health is 3
		// Change health bar color based on health
		var healthPercentage = self.health / 3; // Assuming max health is 3
		var red, green;
		// Transition from green to orange
		if (healthPercentage > 0.5) {
			red = Math.min(255, Math.floor((1 - healthPercentage) * 2 * 255));
			green = 255;
		} else {
			// Transition from orange to red
			red = 255;
			green = Math.min(255, Math.floor(healthPercentage * 2 * 255));
		}
		self.healthBar.tint = red << 16 | green << 8; // Combine red and green to form the color
		// Don't process movement if attacking
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		var dx = target.x - self.x;
		var dy = target.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance > distanceThreshold) {
			// Set knight to moving state if not already moving
			if (!self.isMoving) {
				self.isMoving = true;
				self.switchAsset(self.lastDirection || 'down'); // Update asset to running animation
			}
			// Determine the primary direction based on the larger component (dx or dy)
			if (Math.abs(dx) > Math.abs(dy) + directionThreshold) {
				// Horizontal movement dominates
				if (dx > 0) {
					if (dy > directionThreshold) {
						self.moveToDirection('down-right');
					} else if (dy < -directionThreshold) {
						self.moveToDirection('up-right');
					} else {
						self.moveToDirection('right');
					}
				} else {
					if (dy > directionThreshold) {
						self.moveToDirection('down-left');
					} else if (dy < -directionThreshold) {
						self.moveToDirection('up-left');
					} else {
						self.moveToDirection('left');
					}
				}
			} else if (Math.abs(dy) > Math.abs(dx) + directionThreshold) {
				// Vertical movement dominates
				if (dy > 0) {
					if (dx > directionThreshold) {
						self.moveToDirection('down-right');
					} else if (dx < -directionThreshold) {
						self.moveToDirection('down-left');
					} else {
						self.moveToDirection('down');
					}
				} else {
					if (dx > directionThreshold) {
						self.moveToDirection('up-right');
					} else if (dx < -directionThreshold) {
						self.moveToDirection('up-left');
					} else {
						self.moveToDirection('up');
					}
				}
			} else {
				// The difference between dx and dy is small, use diagonal movement
				if (dx > 0 && dy > 0) {
					self.moveToDirection('down-right');
				} else if (dx > 0 && dy < 0) {
					self.moveToDirection('up-right');
				} else if (dx < 0 && dy > 0) {
					self.moveToDirection('down-left');
				} else if (dx < 0 && dy < 0) {
					self.moveToDirection('up-left');
				}
			}
		} else {
			// Check if knight is not moving and distance to drone is less than 400
			if (!self.isMoving) {
				if (droneManager && droneManager.drones.length > 0) {
					var drone = droneManager.drones[0]; // Assuming single drone for simplicity
					var dx = drone.x - self.x;
					var dy = drone.y - self.y;
					var distanceToDrone = Math.sqrt(dx * dx + dy * dy);
				}
				if (distanceToDrone < 400) {
					// Calculate angle to orient knight towards drone
					var angleToDrone = Math.atan2(dy, dx);
					var directionToDrone;
					if (angleToDrone >= -Math.PI / 8 && angleToDrone < Math.PI / 8) {
						directionToDrone = 'right';
					} else if (angleToDrone >= Math.PI / 8 && angleToDrone < 3 * Math.PI / 8) {
						directionToDrone = 'down-right';
					} else if (angleToDrone >= 3 * Math.PI / 8 && angleToDrone < 5 * Math.PI / 8) {
						directionToDrone = 'down';
					} else if (angleToDrone >= 5 * Math.PI / 8 && angleToDrone < 7 * Math.PI / 8) {
						directionToDrone = 'down-left';
					} else if (angleToDrone >= 7 * Math.PI / 8 || angleToDrone < -7 * Math.PI / 8) {
						directionToDrone = 'left';
					} else if (angleToDrone >= -7 * Math.PI / 8 && angleToDrone < -5 * Math.PI / 8) {
						directionToDrone = 'up-left';
					} else if (angleToDrone >= -5 * Math.PI / 8 && angleToDrone < -3 * Math.PI / 8) {
						directionToDrone = 'up';
					} else if (angleToDrone >= -3 * Math.PI / 8 && angleToDrone < -Math.PI / 8) {
						directionToDrone = 'up-right';
					}
					if (directionToDrone) {
						self.switchAsset(directionToDrone);
					}
				}
			}
			// Set knight to idle state if currently moving
			if (self.isMoving) {
				self.isMoving = false;
				self.switchAsset(self.lastDirection || 'down'); // Update asset to idle animation
			}
		}
		// Update knight animation
		self.updateAnimation();
	};
	self.switchAsset = function (direction) {
		if (!knightGraphics) {
			return;
		}
		// If currently attacking, don't switch assets
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		// Detach current assets
		// Hide current assets
		knightGraphics.visible = false;
		shadowGraphics.visible = false;
		// Switch to new assets based on direction and movement state
		if (self.isMoving) {
			// Use running animation
			knightGraphics = knightAssets[direction][currentFrame];
			shadowGraphics = shadowAssets[direction][currentFrame];
		} else {
			// Use idle animation
			knightGraphics = knightIdleAssets[direction];
			shadowGraphics = shadowIdleAssets[direction];
		}
		self.addChild(shadowGraphics);
		self.addChild(knightGraphics);
		// Show new assets
		knightGraphics.visible = true;
		shadowGraphics.visible = true;
		// Position the shadow slightly offset from the knight
		shadowGraphics.x = shadowOffsetX;
		shadowGraphics.y = shadowOffsetY;
		// Update last direction
		self.lastDirection = direction;
	};
	self.updateAnimation = function () {
		// If currently attacking, don't switch assets
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		if (self.isMoving) {
			// Only update animation if moving
			frameCounter += animationSpeed;
			if (frameCounter >= 1) {
				frameCounter = 0;
				currentFrame = (currentFrame + 1) % 8; // Cycle through 8 frames
				if (self.lastDirection) {
					self.switchAsset(self.lastDirection);
				}
			}
		} else if (self.lastDirection) {
			// Make sure we're showing the idle animation when not moving
			self.switchAsset(self.lastDirection);
		}
	};
	self.moveToDirection = function (direction) {
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		if (self.lastDirection !== direction) {
			self.switchAsset(direction);
			self.lastDirection = direction;
		}
		switch (direction) {
			case 'up':
				self.y -= self.speed;
				break;
			case 'down':
				self.y += self.speed;
				break;
			case 'left':
				self.x -= self.speed;
				break;
			case 'right':
				self.x += self.speed;
				break;
			case 'up-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'up-right':
				self.x += self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'down-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
			case 'down-right':
				self.x += self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
		}
	};
	self.takeHit = function (bullet) {
		if (isDied) {
			return;
		}
		// Flash the knight red to indicate damage
		self.tint = 0xff0000; // Red tint
		// After a short delay, restore the original tint
		LK.setTimeout(function () {
			self.tint = color; // Restore original color
		}, 200);
		// Optional: Add knockback effect based on bullet direction
		var knockbackDistance = 30;
		var knockbackAngle = bullet.rotation;
		// Apply knockback
		self.x += Math.cos(knockbackAngle) * knockbackDistance;
		self.y += Math.sin(knockbackAngle) * knockbackDistance;
		self.health--;
		if (self.health < 0) {
			self.dieAnim();
		} else {
			// Play knight-hit sound
			LK.getSound('knight-hit').play();
		}
		// Log hit for debugging
		log("Knight hit by laser beam!");
	};
	self.dieAnim = function () {
		// Animate knight tint to black
		LK.getSound('knight-die').play();
		punchButton.visible = false; // Hide attackButton when the knight is dead
		if (isDied) {
			return;
		}
		isDied = true;
		tween(self, {
			tint: 0x000000
		}, {
			duration: 1000,
			// 1 second duration
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				var explosion = new ExplosionKnight();
				explosion.init(self.x, self.y - 50);
				middlegroundContainer.addChild(explosion);
				LK.getSound('knight-killed').play();
				self.destroy(); // Destroy knight after animation
				LK.setTimeout(function () {
					LK.showGameOver();
				}, 3000); // Call game over after 2 seconds
			}
		});
	};
	self.attack = function () {
		// Check if already attacking
		if (isDied || self.isAttacking) {
			return;
		}
		// Play knight-attack sound
		LK.getSound('knight-attack').play();
		self.isAttacking = true;
		log("Knight attacking!");
		// Store current direction
		var direction = self.lastDirection || 'down';
		// Get attack animation frames for current direction
		var attackFrames = knightAttackAssets[direction];
		var shadowAttackFrames = shadowAttackAssets[direction];
		// Hide current graphics
		// knightGraphics.visible = false;
		// shadowGraphics.visible = false;
		// Add all frames but make them invisible initially
		for (var i = 0; i < attackFrames.length; i++) {
			self.addChild(shadowAttackFrames[i]);
			self.addChild(attackFrames[i]);
			shadowAttackFrames[i].visible = false;
			attackFrames[i].visible = false;
		}
		// Create attack animation
		var currentFrame = 0;
		var attackInterval = LK.setInterval(function () {
			if (self.isDied) {
				return;
			}
			// Hide previous frame if it exists
			if (currentFrame > 0) {
				attackFrames[currentFrame - 1].visible = false;
				shadowAttackFrames[currentFrame - 1].visible = false;
			}
			// Hide current graphics
			knightGraphics.visible = false;
			shadowGraphics.visible = false;
			// Show current frame
			shadowAttackFrames[currentFrame].visible = true;
			attackFrames[currentFrame].visible = true;
			// Check for collision with drones (middle of the attack animation)
			if (currentFrame === Math.floor(attackFrames.length / 2)) {
				// Calculate attack range and direction
				var attackRange = 100; // Range of the knight's attack
				var attackDirection = direction;
				var attackAngle;
				// Determine attack angle based on direction
				if (attackDirection === 'right') {
					attackAngle = 0;
				} else if (attackDirection === 'down-right') {
					attackAngle = Math.PI / 4;
				} else if (attackDirection === 'down') {
					attackAngle = Math.PI / 2;
				} else if (attackDirection === 'down-left') {
					attackAngle = 3 * Math.PI / 4;
				} else if (attackDirection === 'left') {
					attackAngle = Math.PI;
				} else if (attackDirection === 'up-left') {
					attackAngle = 5 * Math.PI / 4;
				} else if (attackDirection === 'up') {
					attackAngle = 3 * Math.PI / 2;
				} else if (attackDirection === 'up-right') {
					attackAngle = 7 * Math.PI / 4;
				}
				// Calculate attack point in front of the knight
				var attackX = self.x + Math.cos(attackAngle) * attackRange;
				var attackY = self.y + Math.sin(attackAngle) * attackRange;
				// Check if any drone is within attack range
				for (var i = 0; i < droneManager.drones.length; i++) {
					var drone = droneManager.drones[i];
					var dx = drone.x - attackX;
					var dy = drone.y - attackY;
					var distance = Math.sqrt(dx * dx + dy * dy);
					// If drone is within attack range, call its takeHit method
					if (distance < 120) {
						// Adjust hit radius as needed
						drone.takeHit({
							rotation: attackAngle // Pass attack angle for knockback direction
						});
					}
				}
			}
			// Move to next frame
			currentFrame++;
			// Check if animation is complete
			if (currentFrame >= attackFrames.length) {
				// Clear interval
				LK.clearInterval(attackInterval);
				// Hide all attack frames
				for (var i = 0; i < attackFrames.length; i++) {
					attackFrames[i].visible = false;
					shadowAttackFrames[i].visible = false;
				}
				// Show regular graphics again
				knightGraphics.visible = true;
				shadowGraphics.visible = true;
				// Reset attacking flag
				self.isAttacking = false;
				// Reset the global target position to knight's current position
				target.x = self.x;
				target.y = self.y;
			}
		}, 50); // 50ms per frame for a fast attack animation
	};
});
var LaserBeam = Container.expand(function () {
	var self = Container.call(this);
	var laserBeamGraphics = LK.getAsset('droneLaserBeam', {
		anchorX: 0.5,
		anchorY: 0.5,
		blendMode: 1
	});
	self.addChild(laserBeamGraphics);
	self.speed = 1500; // Speed of the laser beam in pixels per second
	self.fire = function (x, y, rotation) {
		self.x = x;
		self.y = y;
		self.rotation = rotation;
		middlegroundContainer.addChild(self);
		// Calculate the distance the laser beam will travel
		var distance = 3000;
		// Calculate the duration based on speed
		var duration = distance / self.speed * 1000; // Convert to milliseconds
		// Tween the laser beam to move forward
		tween(self, {
			x: self.x + Math.cos(self.rotation) * distance,
			y: self.y + Math.sin(self.rotation) * distance
		}, {
			duration: duration,
			easing: tween.linear,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	self.update = function () {
		if (self.intersects(knight.boundingBox)) {
			knight.takeHit(self);
			self.destroy();
		}
	};
});
var Room = Container.expand(function () {
	var self = Container.call(this);
	var background = LK.getAsset('backgroundWalls', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(background);
	self.x = 2048 / 2;
	self.y = 2732 / 2;
});
var Target = Container.expand(function () {
	var self = Container.call(this);
	self.x = 0;
	self.y = 0;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 //Init game with black background 
});
/**** 
* Game Code
****/ 
// Utility function to calculate the angle difference
function calculateAngleDiff(targetAngle, currentAngle) {
	var angleDiff = targetAngle - currentAngle;
	// Normalize angle difference to [-PI, PI]
	while (angleDiff > Math.PI) {
		angleDiff -= 2 * Math.PI;
	}
	while (angleDiff < -Math.PI) {
		angleDiff += 2 * Math.PI;
	}
	return angleDiff;
}
//<Write entity 'classes' with empty functions for important behavior here>
//<Write imports for supported plugins here>
//<Assets used in the game will automatically appear here>
//<Write game logic code here, including initializing arrays and variables>
var DroneManager = function DroneManager() {
	var self = this;
	self.droneCounter = 0; // Initialize droneCounter to track the number of drones
	self.drones = [];
	self.start = function () {
		// Clear previous drones from the scene and the drones array
		self.drones.forEach(function (drone) {
			drone.destroy();
		});
		self.drones = [];
		// Create the drone
		var drone = new Drone(self.droneCounter); // Pass the current level to the Drone constructor
		// Increment counter after drone creation so first drone is level 0
		self.droneCounter++;
		// Check win condition after incrementing counter
		if (self.droneCounter > 3) {
			LK.getSound('knight-win').play(); // Play knight-win sound
			LK.setTimeout(function () {
				LK.showYouWin(); // Show win screen after 2000ms delay
			}, 2000);
			return;
		}
		// Explicitly set position before adding to the scene
		drone.x = Math.random() < 0.5 ? -1024 : 3072;
		drone.y = 1366;
		// Store the current target index
		//drone.currentTargetIndex = currentTargetIndex;
		// Set the initial target to the current corner position
		drone.target = {
			x: 1024,
			y: 1366
		};
		// Add to container and array
		middlegroundContainer.addChild(drone);
		self.drones.push(drone);
		// This ensures all properties are set before tweening begins
		LK.setTimeout(function () {
			drone.init();
		}, 100);
	};
};
/**** 
* Global variables
****/ 
var isDebug = false;
var isDied = false; // Global flag to track if the knight has died
var gameStarted = false;
var droneManager = new DroneManager();
var backgroundContainer;
var middlegroundContainer;
var foregroundContainer;
var knight;
var background; // Declare a global variable for the background
var target;
var punchButton;
var runSoundInterval;
var borderOffset = 380;
var corners = [{
	x: borderOffset,
	y: borderOffset
}, {
	x: 2048 - borderOffset,
	y: borderOffset
}, {
	x: borderOffset,
	y: 2732 - borderOffset
}, {
	x: 2048 - borderOffset,
	y: 2732 - borderOffset
}];
function log() {
	if (isDebug) {
		console.log.apply(console, arguments);
	}
}
function initializeGame() {
	// Create containers
	backgroundContainer = new Container();
	middlegroundContainer = new Container();
	foregroundContainer = new Container();
	// Add containers to game
	game.addChild(backgroundContainer);
	game.addChild(middlegroundContainer);
	game.addChild(foregroundContainer);
	// Initialize background
	background = new Background(); // Use Background class instead of LK.getAsset
	backgroundContainer.addChild(background);
	// Initialize room
	var room = new Room();
	backgroundContainer.addChild(room);
	// Initialize knight
	knight = new Knight();
	knight.x = 2048 / 2;
	knight.y = 2732 / 2;
	middlegroundContainer.addChild(knight);
	// Initialize target
	target = new Target();
	target.x = knight.x;
	target.y = knight.y;
	foregroundContainer.addChild(target);
	// Initialize punch button
	punchButton = new ButtonPunch();
	punchButton.x = 2048 - 220;
	punchButton.y = 220;
	foregroundContainer.addChild(punchButton);
	// Initialize sound
	runSoundInterval = LK.setInterval(playRunSound, 350);
	droneManager = new DroneManager();
	LK.setTimeout(function () {
		gameStarted = true;
		droneManager.start();
	}, 1000);
}
function playRunSound() {
	if (knight.isMoving) {
		LK.getSound('knight-run').play();
	}
}
initializeGame(); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Background = Container.expand(function () {
	var self = Container.call(this);
	var backgroundGraphics = LK.getAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(backgroundGraphics);
	self.x = 2048 / 2;
	self.y = 2732 / 2;
	// Move the down handler to the Background class
	self.down = function (x, y, obj) {
		var game_position = game.toLocal(obj.global);
		target.x = Math.max(corners[0].x, Math.min(game_position.x, corners[3].x));
		target.y = Math.max(corners[0].y, Math.min(game_position.y, corners[3].y));
	};
});
var Bonus = Container.expand(function (x, y) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	// Create shadow for bonus
	var shadowBonus = LK.getAsset('bonusHealth', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	shadowBonus.alpha = 0.5;
	shadowBonus.tint = 0x000000;
	shadowBonus.x = 10; // Offset shadow position
	shadowBonus.y = 10; // Offset shadow position
	self.addChild(shadowBonus);
	self.active = false;
	var bonusGraphics = LK.getAsset('bonusHealth', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(bonusGraphics);
	self.bonusLight = LK.getAsset('bonusHealthLight', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0x00FF00
	});
	self.addChild(self.bonusLight);
	self.animLight = function () {
		function loopTint() {
			tween(self.bonusLight, {
				tint: 0xFFFFFF
			}, {
				duration: 600,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(self.bonusLight, {
						tint: 0x00FF00
					}, {
						duration: 600,
						easing: tween.easeInOut,
						onFinish: loopTint
					});
				}
			});
		}
		loopTint();
	};
	self.animLight();
	self.animMove = function () {
		function loopMove() {
			tween(self, {
				y: self.y + 10
			}, {
				duration: 500,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(self, {
						y: self.y - 10
					}, {
						duration: 500,
						easing: tween.easeInOut,
						onFinish: loopMove
					});
				}
			});
		}
		loopMove();
	};
	self.throwToCorner = function () {
		// Calculate a random position within range instead of using corners
		var minDistance = 1024;
		var maxDistance = 1480;
		// Generate random angle
		var randomAngle = Math.random() * Math.PI * 2;
		// Calculate random distance within range
		var randomDistance = minDistance + Math.random() * (maxDistance - minDistance);
		// Calculate target position
		var targetX = self.x + Math.cos(randomAngle) * randomDistance;
		var targetY = self.y + Math.sin(randomAngle) * randomDistance;
		// Ensure target is within the playable area (within corners)
		targetX = Math.max(borderOffset, Math.min(2048 - borderOffset, targetX));
		targetY = Math.max(borderOffset, Math.min(2732 - borderOffset, targetY));
		// Calculate control point for parabolic motion
		var controlX = (self.x + targetX) / 2;
		var controlY = Math.min(self.y, targetY) - 500; // Control point above the line for a parabolic effect
		// Initial position
		var startX = self.x;
		var startY = self.y;
		// Create a tween for parabolic motion
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: 1200,
			easing: tween.easeOutQuad,
			onUpdate: function onUpdate() {
				// Calculate parabolic path using quadratic Bezier curve formula
				var t = this.progress;
				self.x = Math.pow(1 - t, 2) * startX + 2 * (1 - t) * t * controlX + Math.pow(t, 2) * targetX;
				self.y = Math.pow(1 - t, 2) * startY + 2 * (1 - t) * t * controlY + Math.pow(t, 2) * targetY;
				// Add rotation for visual effect
				self.rotation = t * Math.PI * 3; // 1.5 full rotations during flight
			},
			onFinish: function onFinish() {
				self.rotation = 0; // Reset rotation
				self.active = true; // Activate bonus after reaching the corner
				self.animMove();
			}
		});
	};
	self.throwToCorner(); // Call the function to start the animation
});
var ButtonPunch = Container.expand(function () {
	var self = Container.call(this);
	var buttonGraphics = LK.getAsset('buttonPunch', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(buttonGraphics);
	// Add click/tap handler
	self.down = function () {
		// Trigger knight attack when button is pressed
		if (!isDied && knight && knight.health >= 0 && !knight.isAttacking) {
			knight.attack();
		}
	};
});
// Import the tween plugin
var Drone = Container.expand(function (level) {
	var self = Container.call(this);
	self.level = level || 0; // Set level to the passed parameter or default to 0
	self.health = (isDebug ? 2 : 4) + self.level * 2; // Add level*2 to drone's health
	var droneWidth = 200;
	// Increase size based on level
	var levelGrowth = self.level * self.level * 80;
	self.droneScanLaser = LK.getAsset('droneScanLaser', {
		anchorX: 0,
		anchorY: 0.5
	});
	self.droneScanLaser.visible = true; // Always visible
	self.droneScanLaser.x = droneWidth / 2;
	self.droneScanLaser.alpha = 0.3; // Set alpha to 0.3
	self.droneScanLaser.width += levelGrowth;
	self.droneScanLaser.height += levelGrowth;
	self.addChild(self.droneScanLaser);
	self.droneScanBar = LK.getAsset('droneScanBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	self.droneScanBar.x = droneWidth / 2;
	self.droneScanBar.blendMode = 3;
	self.droneScanBar.width = self.droneScanLaser.width;
	self.addChild(self.droneScanBar);
	var droneGraphics = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: droneWidth,
		height: droneWidth
	});
	var shadowDrone = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: droneWidth,
		height: droneWidth
	});
	self.shadowOffset = {
		x: -30,
		y: 40
	}; // Define shadow offset property
	shadowDrone.alpha = 0.5;
	shadowDrone.tint = 0x000000;
	shadowDrone.x = -10;
	shadowDrone.y = 40;
	self.addChild(shadowDrone);
	self.addChild(droneGraphics);
	// Add health bar under the drone
	self.healthBar = LK.getAsset('healthBar', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 100,
		height: 10,
		color: 0x00FF00 // Green color for health
	});
	self.healthBar.y = droneWidth / 2 + 20; // Position the health bar under the drone
	self.addChild(self.healthBar);
	function loopScanLaserTint() {
		if (self.state !== 'scanning') {
			return;
		}
		tween(self.droneScanLaser, {
			tint: 0x00FF00
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanLaser, {
					tint: 0x00AA00
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: loopScanLaserTint // Recursively call to loop
				});
			}
		});
	}
	function animateScanBar() {
		if (self.state !== 'scanning') {
			return;
		}
		tween(self.droneScanBar, {
			alpha: 0.3,
			rotation: Math.PI / 6.75
		}, {
			duration: 600 - self.level * 50,
			//{V} // Decrease duration to increase frequency with level
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanBar, {
					alpha: 0.6,
					rotation: -Math.PI / 6.75
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: animateScanBar // Recursively call to loop
				}); // Ensure the tween is started
			}
		}); // Ensure the tween is started
	}
	self.speed = 5;
	self.state = ''; // Possible states: scanning, attacking
	// Add debug text to track drone state
	self.debugText = new Text2(self.state, {
		size: 50,
		fill: 0xFFFFFF
	});
	self.debugText.x = -droneGraphics.width / 2;
	self.debugText.y = -droneGraphics.height / 2 - 50;
	self.debugText.visible = isDebug; // Set visibility based on debug mode
	self.addChild(self.debugText);
	self.fireRange = 300; // Example fire range value
	self.fireDelay = 1200;
	self.currentTargetIndex = -1;
	self.target = {
		x: 0,
		y: 0
	};
	self.lastKnightCheckTime = 0; // Track when we last checked for knight intersection
	self.lastFireTime = 0; // Track when we last fired at the knight
	self.lastRotationTime = 0; // Track the last time we updated rotation
	self.isRotating = false; // Flag to track if we're currently rotating
	self.isMoving = false; // Flag to track if we're currently moving
	self.needsRotation = false; // Flag to track if we need to rotate before moving
	self.justSwitchedFromAttacking = false; // Flag to track if we just switched from attacking mode
	// Function to select a new random target
	self.selectTarget = function () {
		log("selectTarget...:");
		var newTargetIndex;
		do {
			newTargetIndex = Math.floor(Math.random() * corners.length);
		} while (newTargetIndex === self.currentTargetIndex);
		self.currentTargetIndex = newTargetIndex;
		self.target = corners[newTargetIndex];
		log("New target selected at position:", self.target.x, self.target.y);
		// Set a flag to indicate the target is new and needs rotation first
		self.needsRotation = true;
		// Return the new target (not used currently but could be useful)
		return self.target;
	};
	// Function to fire a laser beam
	self.fire = function () {
		log("Drone firing laser beam...");
		LK.getSound('drone-beam').play();
		var laserBeam = new LaserBeam();
		laserBeam.fire(self.x, self.y, self.rotation);
	};
	// Function to handle state transitions
	self.switchState = function (newState) {
		// Don't do anything if the state isn't changing
		if (self.state === newState) {
			return;
		}
		log("Switching drone state from " + self.state + " to " + newState);
		// Stop any existing tweens to ensure clean state transition
		tween.stop(self);
		// Clear scan sound interval if it exists
		if (self.scanSoundInterval) {
			LK.clearInterval(self.scanSoundInterval);
			self.scanSoundInterval = null;
		}
		// Reset movement flags
		self.isRotating = false;
		self.isMoving = false;
		self.justSwitchedFromAttacking = newState === 'scanning' && self.state === 'attacking';
		// Update the state
		self.state = newState;
		self.debugText.setText(self.state); // Update debug text with current state
		// Handle entry actions for new state
		if (newState === 'scanning') {
			// Play drone-scan sound
			self.scanSoundInterval = LK.setInterval(function () {
				LK.getSound('drone-scan').play();
			}, 1000);
			// Entering scanning state
			self.debugText.tint = 0xFFFFFF; // Reset tint to white for other states
			self.droneScanLaser.tint = 0x00FF00; // Reset tint to green for scanning mode
			// Clear current target and set flag to select a new one
			//self.target = null;
			//self.needsRotation = true;
			animateScanBar();
			// Select a new target (this will be handled in updateScanning on next update)
		} else if (newState === 'attacking') {
			// don't fire directly, consider a part of fire delay
			self.lastFireTime = Date.now();
			// Entering attacking state
			self.debugText.tint = 0xFFA500; // Change tint to orange when attacking
			self.droneScanLaser.tint = 0xFFA500; // Change tint to orange when attacking
			// Start following the knight
			self.followKnight();
		}
	};
	self.init = function () {
		log("Drone initialized at position:", self.x, self.y);
		// Reset state flags
		self.isRotating = false;
		self.isMoving = false;
		self.needsRotation = true;
		// Start the animations
		animateScanBar();
		loopScanLaserTint();
		// Switch to scanning state to begin patrol
		self.switchState('scanning');
	};
	self.collectBonus = function collectBonus(bonus) {
		// Increase knight's health by 2
		knight.health += 2;
		// Play knight-bonus sound
		LK.getSound('knight-bonus').play();
		// Destroy the bonus
		bonus.destroy();
	};
	self.update = function () {
		if (self.state === 'scanning') {
			self.updateScanning();
		} else if (self.state === 'attacking') {
			self.updateAttacking();
		}
		// Update health bar width and color regardless of state
		self.healthBar.width = Math.max(0, (self.health + 1) / 4 * 100); // Assuming max health is 4
		// Change health bar color based on health
		var healthPercentage = self.health / 4; // Assuming max health is 4
		var red, green;
		// Transition from green to orange
		if (healthPercentage > 0.5) {
			red = Math.min(255, Math.floor((1 - healthPercentage) * 2 * 255));
			green = 255;
		} else {
			// Transition from orange to red
			red = 255;
			green = Math.min(255, Math.floor(healthPercentage * 2 * 255));
		}
		self.healthBar.tint = red << 16 | green << 8; // Combine red and green to form the color
		// Iterate over all bonuses in the middlegroundContainer
		for (var i = middlegroundContainer.children.length - 1; i >= 0; i--) {
			var child = middlegroundContainer.children[i];
			if (child instanceof Bonus) {
				// Check if knight's boundingBox intersects with bonusLight
				if (child.active && knight.boundingBox.intersects(child.bonusLight)) {
					self.collectBonus(child);
				}
			}
		}
		// Update shadow position
		shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation);
		shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation);
		// Update droneScanBar width based on its rotation
		self.droneScanBar.width = self.droneScanLaser.width * (1 + 0.1 * Math.abs(Math.sin(self.droneScanBar.rotation)));
	};
	// Function to perform a full 360° scan
	self.performFullScan = function (callback) {
		// Calculate duration based on a consistent rotation speed
		var scanRotationSpeed = 1.0; // Radians per second (slower for scanning)
		var fullRotationDuration = Math.PI * 2 / scanRotationSpeed * 1000; // ms
		// Store current rotation
		var startRotation = self.rotation;
		// Mark that we're rotating to prevent updateScanning from starting other rotations
		self.isRotating = true;
		log("Performing 360° scan");
		// Perform a full 360° rotation
		tween(self, {
			rotation: startRotation + Math.PI * 2 // Full 360° rotation
		}, {
			duration: fullRotationDuration,
			easing: tween.linear,
			// Linear easing for constant speed
			onFinish: function onFinish() {
				// Clear rotation flag when done
				self.isRotating = false;
				log("Full scan complete");
				// Call callback if provided
				if (callback) {
					callback();
				}
			}
		});
	};
	// Handle scanning mode behavior
	self.updateScanning = function () {
		// Check for intersection with knight
		if (!isDied && self.droneScanBar.intersects(knight.boundingBox)) {
			self.switchState('attacking');
			log("Drone switched to attacking mode!");
			return;
		}
		// If no target is set, select one
		if (!self.target) {
			log("No target set, selecting a new one");
			// If we just switched from attacking to scanning mode, do a 360° scan first
			if (self.justSwitchedFromAttacking) {
				self.justSwitchedFromAttacking = false;
				self.fire();
				// Perform full scan before selecting a new target
				self.performFullScan(function () {
					// After scan is complete, select a new target
					self.selectTarget();
				});
				return;
			}
			// Otherwise just select a new target
			self.selectTarget();
			return;
		}
		// Calculate direction and distance to target
		var dx = self.target.x - self.x;
		var dy = self.target.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// If very close to target, select a new one
		if (distance < 10) {
			log("Reached target, selecting a new one");
			self.selectTarget();
			return;
		}
		// Calculate target angle
		var targetAngle = Math.atan2(dy, dx);
		// Check if rotation is needed
		var angleDiff = Math.abs(calculateAngleDiff(targetAngle, self.rotation));
		// If rotation is needed (more than 0.1 radians difference or flag is set)
		if (angleDiff > 0.1 || self.needsRotation) {
			// Only start a new rotation if not already rotating
			if (!self.isRotating) {
				log("Rotating to face target");
				self.isRotating = true;
				// Use the updateRotation function with callback to clear isRotating flag
				self.updateRotation(targetAngle, 600, function () {
					self.isRotating = false;
					self.needsRotation = false;
					log("Rotation complete");
				});
			}
		}
		// If rotation is close enough and we're not currently moving, start movement
		else if (!self.isMoving) {
			log("Starting movement to target");
			self.isMoving = true;
			// Calculate duration based on distance
			var moveSpeed = 0.2; // Adjust this value to control drone speed
			var duration = distance / moveSpeed;
			// Start moving toward the target
			tween(self, {
				x: self.target.x,
				y: self.target.y
			}, {
				duration: duration,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					self.isMoving = false;
					log("Movement complete");
					// Don't automatically select a new target, let updateScanning handle it
				}
			});
		}
	};
	// Handle attacking mode behavior
	self.updateAttacking = function () {
		var currentTime = Date.now();
		// Fire using separate counter
		if (currentTime - self.lastFireTime > self.fireDelay) {
			// Fire every 1.2 seconds
			self.lastFireTime = currentTime;
			self.fire();
		}
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var angle = Math.atan2(dy, dx);
		// Drone rotation logic - directly rotate the drone to face the knight
		// Only do smooth rotation tracking when not already moving to a new position
		//self.lastRotationTime = currentTime;
		// Calculate a smoother intermediate angle for natural tracking
		var currentAngle = self.rotation;
		var angleDiff = calculateAngleDiff(angle, currentAngle);
		// Only rotate a portion of the way to the target for smoother tracking
		// This creates a slight lag effect that looks more natural
		var partialAngle = currentAngle + angleDiff * 0.3;
		// Directly set rotation instead of using updateRotation
		self.rotation = partialAngle;
		//self.isRotating = false; // No need for callback since we're setting directly
		// Rotate droneScanBar to point at knight within limits
		var relativeAngle = calculateAngleDiff(angle, self.rotation);
		// Clamp the scan bar rotation to the maximum allowed range
		var maxRotation = Math.PI / 6.5;
		var clampedRotation = Math.max(-maxRotation, Math.min(maxRotation, relativeAngle));
		// Set the scan bar rotation directly
		self.droneScanBar.rotation = clampedRotation;
		self.droneScanBar.alpha = 0.1;
		// First check if knight is still in range - do this every second
		if (currentTime - self.lastKnightCheckTime > 1000) {
			self.lastKnightCheckTime = currentTime;
			// Check if we can still see the knight
			if (!self.droneScanBar.intersects(knight.boundingBox)) {
				log("Knight lost! Returning to scanning mode.");
				self.switchState('scanning');
				return;
			}
			log("Knight still in range at distance: " + distance);
		}
		// Position update logic - if we're not currently moving but need to
		if (isDied) {
			log("Knight is dead, returning to scanning mode.");
			self.switchState('scanning');
			return;
		}
		if (!self.isMoving && distance > 550) {
			log("Knight moved - updating drone position");
			// Move to a better position
			self.followKnight();
			return;
		}
	};
	self.followKnight = function () {
		log("followKnight...");
		// Cancel any existing movement tweens
		tween.stop(self);
		// Calculate direction to knight
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var angle = Math.atan2(dy, dx);
		// Set the movement flag
		self.isMoving = true;
		self.isRotating = true;
		// After rotation is complete, start moving toward knight
		self.moveTowardKnight();
	};
	// Function to calculate distance to knight
	self.distanceToKnight = function () {
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		return Math.sqrt(dx * dx + dy * dy);
	};
	self.moveTowardKnight = function () {
		var dx = knight.x - self.x;
		var dy = knight.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// If already within the desired distance, stop moving
		if (distance <= 500) {
			return;
		}
		// Calculate target position that's 500 units away from knight
		var ratio = (distance - 500) / distance;
		var targetX = self.x + dx * ratio;
		var targetY = self.y + dy * ratio;
		// Move toward the target
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: distance * 2,
			// Speed based on distance
			easing: tween.linear,
			onUpdate: function onUpdate() {
				// Update rotation to continuously face the knight during movement
				var currentDx = knight.x - self.x;
				var currentDy = knight.y - self.y;
				var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy);
				// Only update rotation if not very close to the target
				if (currentDistance > 10) {
					var currentAngle = Math.atan2(currentDy, currentDx);
					// Calculate target rotation with a smaller adjustment for smoothness using the utility function
					var newRotation = self.rotation + calculateAngleDiff(currentAngle, self.rotation) * 0.1;
					// Create a separate quick tween for the rotation
					tween(self, {
						rotation: newRotation
					}, {
						duration: 600,
						// Very short duration for responsive updates
						easing: tween.linear
					});
				}
			},
			onFinish: function onFinish() {
				// Check if we're still in attacking mode before continuing to follow
				if (self.state === 'attacking') {
					// Check if knight has moved and we need to follow again
					if (self.distanceToKnight() > 500) {
						self.moveTowardKnight();
					}
				}
			}
		});
	};
	self.updateRotation = function (targetAngle, maxDuration, callback) {
		maxDuration = maxDuration || 500; // Default max duration if not specified
		// Cancel any existing rotation tweens to prevent conflicts
		tween.stop(self, 'rotation');
		// Normalize angles to be between -PI and PI for proper comparison
		var normalizedCurrentAngle = self.rotation % (2 * Math.PI);
		if (normalizedCurrentAngle > Math.PI) {
			normalizedCurrentAngle -= 2 * Math.PI;
		}
		if (normalizedCurrentAngle < -Math.PI) {
			normalizedCurrentAngle += 2 * Math.PI;
		}
		// Normalize target angle
		var normalizedTargetAngle = targetAngle % (2 * Math.PI);
		if (normalizedTargetAngle > Math.PI) {
			normalizedTargetAngle -= 2 * Math.PI;
		}
		if (normalizedTargetAngle < -Math.PI) {
			normalizedTargetAngle += 2 * Math.PI;
		}
		// Calculate the angle difference using the normalized angles
		var angleDiff = calculateAngleDiff(normalizedTargetAngle, normalizedCurrentAngle);
		var absDiff = Math.abs(angleDiff);
		// If the angle difference is greater than PI, rotate in the shorter direction
		if (absDiff > Math.PI) {
			if (angleDiff > 0) {
				angleDiff -= 2 * Math.PI;
			} else {
				angleDiff += 2 * Math.PI;
			}
		}
		// Calculate duration based on angle difference to achieve constant rotation speed
		// Use radians per second as the speed unit
		var rotationSpeed = 6; // Radians per second
		var duration = Math.min(absDiff / rotationSpeed * 1000, maxDuration);
		// Ensure a minimum duration for very small rotations
		duration = Math.max(duration, 50);
		// Calculate the target rotation by adding the angle difference to the current rotation
		var targetRotation = self.rotation + angleDiff;
		// Log the rotation parameters for debugging
		log("Rotating: angle diff=" + absDiff + ", duration=" + duration + "ms");
		// Perform the rotation tween
		tween(self, {
			rotation: targetRotation
		}, {
			duration: duration,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				log("Rotation complete");
				if (callback) {
					callback();
				}
			}
		});
	};
	self.takeHit = function (bullet) {
		// Play drone-hit sound
		LK.getSound('drone-hit').play();
		// Flash the drone red to indicate damage
		droneGraphics.tint = 0xff0000; // Red tint
		// After a short delay, restore the original tint
		LK.setTimeout(function () {
			droneGraphics.tint = 0xFFFFFF; // Restore original color
		}, 200);
		// Log hit for debugging
		log("Drone hit by attack!");
		// Reduce health when hit
		self.health -= 1;
		// Check if drone is destroyed
		if (self.health <= 0) {
			log("Drone destroyed!");
			self.explode();
			return;
		}
		// Switch to attacking state immediately if not already attacking
		if (self.state !== 'attacking') {
			self.switchState('attacking');
		}
		// Reset the lastKnightCheckTime to ensure we don't immediately check for knight visibility
		self.lastKnightCheckTime = Date.now();
		// Add knockback effect based on bullet direction
		var knockbackDistance = 50;
		var knockbackAngle = bullet.rotation;
		// Calculate potential new position
		var newX = self.x + Math.cos(knockbackAngle) * knockbackDistance;
		var newY = self.y + Math.sin(knockbackAngle) * knockbackDistance;
		// Check if new position would be too close to a corner
		var tooCloseToCorner = false;
		var cornerSafeDistance = 100; // Distance to stay away from corners
		for (var i = 0; i < corners.length; i++) {
			var dx = newX - corners[i].x;
			var dy = newY - corners[i].y;
			var distToCorner = Math.sqrt(dx * dx + dy * dy);
			if (distToCorner < cornerSafeDistance) {
				tooCloseToCorner = true;
				break;
			}
		}
		// If too close to a corner, adjust the knockback to push away from corner
		if (tooCloseToCorner) {
			// Find the center of the playfield
			var centerX = (corners[0].x + corners[3].x) / 2;
			var centerY = (corners[0].y + corners[3].y) / 2;
			// Calculate direction toward center
			var dxToCenter = centerX - self.x;
			var dyToCenter = centerY - self.y;
			var angleToCenter = Math.atan2(dyToCenter, dxToCenter);
			// Use this angle for knockback instead
			newX = self.x + Math.cos(angleToCenter) * knockbackDistance;
			newY = self.y + Math.sin(angleToCenter) * knockbackDistance;
		}
		// Clamp new position using corners
		newX = Math.max(corners[0].x + cornerSafeDistance, Math.min(newX, corners[3].x - cornerSafeDistance));
		newY = Math.max(corners[0].y + cornerSafeDistance, Math.min(newY, corners[3].y - cornerSafeDistance));
		// Apply knockback using tween
		tween(self, {
			x: newX,
			y: newY
		}, {
			duration: 200,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				// After knockback, immediately rotate the drone toward the knight
				// Calculate angle to knight
				var dx = knight.x - self.x;
				var dy = knight.y - self.y;
				var angleToKnight = Math.atan2(dy, dx);
				// Calculate the angle difference for proper duration
				var normalizedCurrentAngle = self.rotation % (2 * Math.PI);
				if (normalizedCurrentAngle > Math.PI) {
					normalizedCurrentAngle -= 2 * Math.PI;
				}
				if (normalizedCurrentAngle < -Math.PI) {
					normalizedCurrentAngle += 2 * Math.PI;
				}
				var normalizedTargetAngle = angleToKnight % (2 * Math.PI);
				if (normalizedTargetAngle > Math.PI) {
					normalizedTargetAngle -= 2 * Math.PI;
				}
				if (normalizedTargetAngle < -Math.PI) {
					normalizedTargetAngle += 2 * Math.PI;
				}
				var angleDiff = calculateAngleDiff(normalizedTargetAngle, normalizedCurrentAngle);
				if (Math.abs(angleDiff) > Math.PI) {
					if (angleDiff > 0) {
						angleDiff -= 2 * Math.PI;
					} else {
						angleDiff += 2 * Math.PI;
					}
				}
				// Calculate duration based on angle difference
				var rotationSpeed = 6; // Radians per second
				var absDiff = Math.abs(angleDiff);
				var duration = Math.min(absDiff / rotationSpeed * 1000, 500);
				duration = Math.max(duration, 50); // Ensure minimum duration
				// Rotate drone to face knight with calculated duration
				tween(self, {
					rotation: self.rotation + angleDiff
				}, {
					duration: duration,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						// Switch to attacking state if not already attacking
						if (self.state !== 'attacking') {
							self.switchState('attacking');
						}
						// Reset the lastKnightCheckTime to ensure we don't immediately check for knight visibility
						self.lastKnightCheckTime = Date.now();
					}
				});
			}
		});
	};
	self.explode = function () {
		// Simply destroy the drone
		tween.stop(self); // Stop all tweens on the drone
		var explosion = new Explosion();
		explosion.init(self.x, self.y);
		middlegroundContainer.addChild(explosion);
		// Clear scan sound interval if it exists
		if (self.scanSoundInterval) {
			LK.clearInterval(self.scanSoundInterval);
			self.scanSoundInterval = null;
		}
		LK.getSound('drone-explode').play();
		// Spawn a bonus at the drone's position
		var bonus = new Bonus(self.x, self.y);
		middlegroundContainer.addChild(bonus);
		self.destroy();
		droneManager.start();
	};
});
var Explosion = Container.expand(function () {
	var self = Container.call(this);
	for (var i = 0; i < 30; i++) {
		var particle = LK.getAsset('explosionParticle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		var scale = Math.random() * 0.5 + 0.5; // Random scale between 0.5 and 1.0
		particle.scale.set(scale);
		var colors = [0xFF4500, 0xFF6347, 0xFFFFFF, 0xFFFF00, 0x8B0000]; // Array of colors: orange, red, white, yellow, dark red
		particle.tint = colors[Math.floor(Math.random() * colors.length)]; // Randomly choose a color from the array
		var angle = Math.random() * Math.PI * 2; // Random direction
		var speed = Math.random() * 5 + 100; // Random speed between 2 and 7
		particle.vx = Math.cos(angle) * speed;
		particle.vy = Math.sin(angle) * speed;
		particle.rotation = angle; // Rotate particle in the direction of movement
		self.addChild(particle);
	}
	// Initialize explosion properties
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		self.scale.set(0.8); // Start small
		self.alpha = 1.0; // Fully visible
		// Animate the explosion
		var particles = self.children;
		var duration = 2000; // Duration for particles to move and fade out
		particles.forEach(function (particle) {
			tween(particle, {
				x: particle.x + particle.vx * duration / 1000,
				y: particle.y + particle.vy * duration / 1000,
				alpha: 0.0
			}, {
				duration: duration,
				easing: tween.easeOut
			});
		});
		LK.setTimeout(function () {
			self.destroy(); // Remove explosion after animation
		}, duration);
	};
});
var ExplosionKnight = Container.expand(function () {
	var self = Container.call(this);
	for (var i = 0; i < 80; i++) {
		var particle = LK.getAsset('explosionParticle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		var scale = Math.random() * 0.5 + 0.5; // Random scale between 0.5 and 1.0
		particle.scale.set(scale);
		particle.tint = 0x000000; // Set particle color to black
		var speed = 100 + Math.random() * 100; // Random speed between 2 and 7
		particle.vx = 0; // No horizontal movement
		particle.vy = -speed; // Negative vertical movement
		particle.rotation = Math.PI / 2; // Rotate by PI/2
		self.addChild(particle);
	}
	// Initialize explosion properties
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		self.scale.set(0.8); // Start small
		self.alpha = 1.0; // Fully visible
		// Animate the explosion
		var particles = self.children;
		var duration = 2000; // Duration for particles to move and fade out
		particles.forEach(function (particle) {
			particle.x += -40 + Math.random() * 80;
			particle.y += -40 + Math.random() * 80;
			tween(particle, {
				x: particle.x + particle.vx * duration / 500,
				y: particle.y + particle.vy * duration / 500,
				alpha: 0.0,
				scaleY: 0
			}, {
				duration: duration,
				easing: tween.easeOut
			});
		});
		LK.setTimeout(function () {
			self.destroy(); // Remove explosion after animation
		}, duration);
	};
});
var Knight = Container.expand(function () {
	var self = Container.call(this);
	self.health = isDebug ? 10 : 3; // Initialize health property with a value of 3
	// Add boundingBox for collision detection
	self.boundingBox = LK.getAsset('boundingBox', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 80,
		height: 150,
		y: -50
	});
	self.addChild(self.boundingBox);
	self.boundingBox.alpha = isDebug ? 0.5 : 0; // Set to false if you don't want it visible
	var directionMapping = {
		'down-left': 'dir1',
		'left': 'dir2',
		'up-left': 'dir3',
		'up': 'dir4',
		'up-right': 'dir5',
		'right': 'dir6',
		'down-right': 'dir7',
		'down': 'dir8'
	};
	// Pre-create a list of assets for each direction
	var knightAssets = {};
	var shadowAssets = {}; // Shadow assets for the knight
	var knightIdleAssets = {}; // Idle assets for the knight
	var shadowIdleAssets = {}; // Shadow idle assets for the knight
	var knightAttackAssets = {}; // Attack assets for the knight
	var shadowAttackAssets = {}; // Shadow attack assets for the knight
	var color = 0xFFFFFF; // Original blue / 0xff4d4d; // Red / 0x9aff9a; // Green
	// Initialize run animation assets
	for (var dir in directionMapping) {
		knightAssets[dir] = [];
		shadowAssets[dir] = []; // Initialize shadow assets array for each direction
		knightAttackAssets[dir] = []; // Initialize attack assets array for each direction
		shadowAttackAssets[dir] = []; // Initialize shadow attack assets array for each direction
		// Load run animation frames (8 frames)
		for (var i = 1; i <= 8; i++) {
			var frameNumber = i.toString().padStart(3, '0');
			// Create knight sprite
			knightAssets[dir].push(LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5,
				tint: color
			}));
			// Create shadow sprite using the same assets but with modifications
			var shadowSprite = LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Apply shadow properties
			shadowSprite.alpha = 0.5;
			shadowSprite.tint = 0x000000;
			shadowSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (π/12 radians)
			shadowSprite.scale.y = 0.5; // Flatten the shadow vertically
			shadowAssets[dir].push(shadowSprite);
		}
		// Load attack animation frames (15 frames)
		for (var i = 1; i <= 15; i++) {
			var frameNumber = i.toString().padStart(3, '0');
			// Create attack sprite
			knightAttackAssets[dir].push(LK.getAsset('knight-attack-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5,
				tint: color
			}));
			// Create shadow attack sprite using the same assets but with modifications
			var shadowAttackSprite = LK.getAsset('knight-attack-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Apply shadow properties
			shadowAttackSprite.alpha = 0.5;
			shadowAttackSprite.tint = 0x000000;
			shadowAttackSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (π/12 radians)
			shadowAttackSprite.scale.y = 0.5; // Flatten the shadow vertically
			shadowAttackAssets[dir].push(shadowAttackSprite);
		}
		// Initialize idle animation assets (one frame per direction)
		knightIdleAssets[dir] = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5,
			tint: color
		});
		// Create shadow for idle animation
		var shadowIdleSprite = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow properties
		shadowIdleSprite.alpha = 0.5;
		shadowIdleSprite.tint = 0x000000;
		shadowIdleSprite.rotation = Math.PI / 12;
		shadowIdleSprite.scale.y = 0.5;
		shadowIdleAssets[dir] = shadowIdleSprite;
	}
	var currentFrame = 0;
	var animationSpeed = 0.2; // Controls how fast the animation plays
	var frameCounter = 0;
	var knightGraphics = knightIdleAssets['down']; // Initialize with the 'down' direction idle asset
	var shadowGraphics = shadowIdleAssets['down']; // Initialize shadow with the 'down' direction idle asset
	// Add health bar under the knight
	self.healthBar = LK.getAsset('healthBar', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 100,
		height: 10,
		color: 0x00FF00 // Green color for health
	});
	self.healthBar.y = 60; // Position the health bar under the knight
	self.addChild(self.healthBar);
	// Add shadow first (so it appears behind the knight)
	self.addChild(shadowGraphics);
	// Then add the knight
	self.addChild(knightGraphics);
	knightGraphics.anchor.set(0.5, 0.5);
	knightGraphics.visible = true;
	shadowGraphics.visible = true;
	// Position the shadow slightly offset from the knight
	var shadowOffsetX = -5;
	var shadowOffsetY = 20;
	shadowGraphics.x = shadowOffsetX;
	shadowGraphics.y = shadowOffsetY;
	self.lastDirection = 'down'; // Initialize lastDirection to track previous direction
	self.isMoving = false; // Track if the knight is currently moving
	self.isAttacking = false; // Track if the knight is currently attacking
	self.speed = 9;
	var distanceThreshold = 8; // Define a threshold to avoid small movements
	var directionThreshold = 5; // Define a threshold for direction changes to avoid shaking
	self.update = function () {
		// Update health bar width based on knight's health
		self.healthBar.width = Math.max(0, (self.health + 1) / 4 * 100); // Assuming max health is 3
		// Change health bar color based on health
		var healthPercentage = self.health / 3; // Assuming max health is 3
		var red, green;
		// Transition from green to orange
		if (healthPercentage > 0.5) {
			red = Math.min(255, Math.floor((1 - healthPercentage) * 2 * 255));
			green = 255;
		} else {
			// Transition from orange to red
			red = 255;
			green = Math.min(255, Math.floor(healthPercentage * 2 * 255));
		}
		self.healthBar.tint = red << 16 | green << 8; // Combine red and green to form the color
		// Don't process movement if attacking
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		var dx = target.x - self.x;
		var dy = target.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance > distanceThreshold) {
			// Set knight to moving state if not already moving
			if (!self.isMoving) {
				self.isMoving = true;
				self.switchAsset(self.lastDirection || 'down'); // Update asset to running animation
			}
			// Determine the primary direction based on the larger component (dx or dy)
			if (Math.abs(dx) > Math.abs(dy) + directionThreshold) {
				// Horizontal movement dominates
				if (dx > 0) {
					if (dy > directionThreshold) {
						self.moveToDirection('down-right');
					} else if (dy < -directionThreshold) {
						self.moveToDirection('up-right');
					} else {
						self.moveToDirection('right');
					}
				} else {
					if (dy > directionThreshold) {
						self.moveToDirection('down-left');
					} else if (dy < -directionThreshold) {
						self.moveToDirection('up-left');
					} else {
						self.moveToDirection('left');
					}
				}
			} else if (Math.abs(dy) > Math.abs(dx) + directionThreshold) {
				// Vertical movement dominates
				if (dy > 0) {
					if (dx > directionThreshold) {
						self.moveToDirection('down-right');
					} else if (dx < -directionThreshold) {
						self.moveToDirection('down-left');
					} else {
						self.moveToDirection('down');
					}
				} else {
					if (dx > directionThreshold) {
						self.moveToDirection('up-right');
					} else if (dx < -directionThreshold) {
						self.moveToDirection('up-left');
					} else {
						self.moveToDirection('up');
					}
				}
			} else {
				// The difference between dx and dy is small, use diagonal movement
				if (dx > 0 && dy > 0) {
					self.moveToDirection('down-right');
				} else if (dx > 0 && dy < 0) {
					self.moveToDirection('up-right');
				} else if (dx < 0 && dy > 0) {
					self.moveToDirection('down-left');
				} else if (dx < 0 && dy < 0) {
					self.moveToDirection('up-left');
				}
			}
		} else {
			// Check if knight is not moving and distance to drone is less than 400
			if (!self.isMoving) {
				if (droneManager && droneManager.drones.length > 0) {
					var drone = droneManager.drones[0]; // Assuming single drone for simplicity
					var dx = drone.x - self.x;
					var dy = drone.y - self.y;
					var distanceToDrone = Math.sqrt(dx * dx + dy * dy);
				}
				if (distanceToDrone < 400) {
					// Calculate angle to orient knight towards drone
					var angleToDrone = Math.atan2(dy, dx);
					var directionToDrone;
					if (angleToDrone >= -Math.PI / 8 && angleToDrone < Math.PI / 8) {
						directionToDrone = 'right';
					} else if (angleToDrone >= Math.PI / 8 && angleToDrone < 3 * Math.PI / 8) {
						directionToDrone = 'down-right';
					} else if (angleToDrone >= 3 * Math.PI / 8 && angleToDrone < 5 * Math.PI / 8) {
						directionToDrone = 'down';
					} else if (angleToDrone >= 5 * Math.PI / 8 && angleToDrone < 7 * Math.PI / 8) {
						directionToDrone = 'down-left';
					} else if (angleToDrone >= 7 * Math.PI / 8 || angleToDrone < -7 * Math.PI / 8) {
						directionToDrone = 'left';
					} else if (angleToDrone >= -7 * Math.PI / 8 && angleToDrone < -5 * Math.PI / 8) {
						directionToDrone = 'up-left';
					} else if (angleToDrone >= -5 * Math.PI / 8 && angleToDrone < -3 * Math.PI / 8) {
						directionToDrone = 'up';
					} else if (angleToDrone >= -3 * Math.PI / 8 && angleToDrone < -Math.PI / 8) {
						directionToDrone = 'up-right';
					}
					if (directionToDrone) {
						self.switchAsset(directionToDrone);
					}
				}
			}
			// Set knight to idle state if currently moving
			if (self.isMoving) {
				self.isMoving = false;
				self.switchAsset(self.lastDirection || 'down'); // Update asset to idle animation
			}
		}
		// Update knight animation
		self.updateAnimation();
	};
	self.switchAsset = function (direction) {
		if (!knightGraphics) {
			return;
		}
		// If currently attacking, don't switch assets
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		// Detach current assets
		// Hide current assets
		knightGraphics.visible = false;
		shadowGraphics.visible = false;
		// Switch to new assets based on direction and movement state
		if (self.isMoving) {
			// Use running animation
			knightGraphics = knightAssets[direction][currentFrame];
			shadowGraphics = shadowAssets[direction][currentFrame];
		} else {
			// Use idle animation
			knightGraphics = knightIdleAssets[direction];
			shadowGraphics = shadowIdleAssets[direction];
		}
		self.addChild(shadowGraphics);
		self.addChild(knightGraphics);
		// Show new assets
		knightGraphics.visible = true;
		shadowGraphics.visible = true;
		// Position the shadow slightly offset from the knight
		shadowGraphics.x = shadowOffsetX;
		shadowGraphics.y = shadowOffsetY;
		// Update last direction
		self.lastDirection = direction;
	};
	self.updateAnimation = function () {
		// If currently attacking, don't switch assets
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		if (self.isMoving) {
			// Only update animation if moving
			frameCounter += animationSpeed;
			if (frameCounter >= 1) {
				frameCounter = 0;
				currentFrame = (currentFrame + 1) % 8; // Cycle through 8 frames
				if (self.lastDirection) {
					self.switchAsset(self.lastDirection);
				}
			}
		} else if (self.lastDirection) {
			// Make sure we're showing the idle animation when not moving
			self.switchAsset(self.lastDirection);
		}
	};
	self.moveToDirection = function (direction) {
		if (isDied || self.health < 0 || self.isAttacking) {
			return;
		}
		if (self.lastDirection !== direction) {
			self.switchAsset(direction);
			self.lastDirection = direction;
		}
		switch (direction) {
			case 'up':
				self.y -= self.speed;
				break;
			case 'down':
				self.y += self.speed;
				break;
			case 'left':
				self.x -= self.speed;
				break;
			case 'right':
				self.x += self.speed;
				break;
			case 'up-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'up-right':
				self.x += self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'down-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
			case 'down-right':
				self.x += self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
		}
	};
	self.takeHit = function (bullet) {
		if (isDied) {
			return;
		}
		// Flash the knight red to indicate damage
		self.tint = 0xff0000; // Red tint
		// After a short delay, restore the original tint
		LK.setTimeout(function () {
			self.tint = color; // Restore original color
		}, 200);
		// Optional: Add knockback effect based on bullet direction
		var knockbackDistance = 30;
		var knockbackAngle = bullet.rotation;
		// Apply knockback
		self.x += Math.cos(knockbackAngle) * knockbackDistance;
		self.y += Math.sin(knockbackAngle) * knockbackDistance;
		self.health--;
		if (self.health < 0) {
			self.dieAnim();
		} else {
			// Play knight-hit sound
			LK.getSound('knight-hit').play();
		}
		// Log hit for debugging
		log("Knight hit by laser beam!");
	};
	self.dieAnim = function () {
		// Animate knight tint to black
		LK.getSound('knight-die').play();
		punchButton.visible = false; // Hide attackButton when the knight is dead
		if (isDied) {
			return;
		}
		isDied = true;
		tween(self, {
			tint: 0x000000
		}, {
			duration: 1000,
			// 1 second duration
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				var explosion = new ExplosionKnight();
				explosion.init(self.x, self.y - 50);
				middlegroundContainer.addChild(explosion);
				LK.getSound('knight-killed').play();
				self.destroy(); // Destroy knight after animation
				LK.setTimeout(function () {
					LK.showGameOver();
				}, 3000); // Call game over after 2 seconds
			}
		});
	};
	self.attack = function () {
		// Check if already attacking
		if (isDied || self.isAttacking) {
			return;
		}
		// Play knight-attack sound
		LK.getSound('knight-attack').play();
		self.isAttacking = true;
		log("Knight attacking!");
		// Store current direction
		var direction = self.lastDirection || 'down';
		// Get attack animation frames for current direction
		var attackFrames = knightAttackAssets[direction];
		var shadowAttackFrames = shadowAttackAssets[direction];
		// Hide current graphics
		// knightGraphics.visible = false;
		// shadowGraphics.visible = false;
		// Add all frames but make them invisible initially
		for (var i = 0; i < attackFrames.length; i++) {
			self.addChild(shadowAttackFrames[i]);
			self.addChild(attackFrames[i]);
			shadowAttackFrames[i].visible = false;
			attackFrames[i].visible = false;
		}
		// Create attack animation
		var currentFrame = 0;
		var attackInterval = LK.setInterval(function () {
			if (self.isDied) {
				return;
			}
			// Hide previous frame if it exists
			if (currentFrame > 0) {
				attackFrames[currentFrame - 1].visible = false;
				shadowAttackFrames[currentFrame - 1].visible = false;
			}
			// Hide current graphics
			knightGraphics.visible = false;
			shadowGraphics.visible = false;
			// Show current frame
			shadowAttackFrames[currentFrame].visible = true;
			attackFrames[currentFrame].visible = true;
			// Check for collision with drones (middle of the attack animation)
			if (currentFrame === Math.floor(attackFrames.length / 2)) {
				// Calculate attack range and direction
				var attackRange = 100; // Range of the knight's attack
				var attackDirection = direction;
				var attackAngle;
				// Determine attack angle based on direction
				if (attackDirection === 'right') {
					attackAngle = 0;
				} else if (attackDirection === 'down-right') {
					attackAngle = Math.PI / 4;
				} else if (attackDirection === 'down') {
					attackAngle = Math.PI / 2;
				} else if (attackDirection === 'down-left') {
					attackAngle = 3 * Math.PI / 4;
				} else if (attackDirection === 'left') {
					attackAngle = Math.PI;
				} else if (attackDirection === 'up-left') {
					attackAngle = 5 * Math.PI / 4;
				} else if (attackDirection === 'up') {
					attackAngle = 3 * Math.PI / 2;
				} else if (attackDirection === 'up-right') {
					attackAngle = 7 * Math.PI / 4;
				}
				// Calculate attack point in front of the knight
				var attackX = self.x + Math.cos(attackAngle) * attackRange;
				var attackY = self.y + Math.sin(attackAngle) * attackRange;
				// Check if any drone is within attack range
				for (var i = 0; i < droneManager.drones.length; i++) {
					var drone = droneManager.drones[i];
					var dx = drone.x - attackX;
					var dy = drone.y - attackY;
					var distance = Math.sqrt(dx * dx + dy * dy);
					// If drone is within attack range, call its takeHit method
					if (distance < 120) {
						// Adjust hit radius as needed
						drone.takeHit({
							rotation: attackAngle // Pass attack angle for knockback direction
						});
					}
				}
			}
			// Move to next frame
			currentFrame++;
			// Check if animation is complete
			if (currentFrame >= attackFrames.length) {
				// Clear interval
				LK.clearInterval(attackInterval);
				// Hide all attack frames
				for (var i = 0; i < attackFrames.length; i++) {
					attackFrames[i].visible = false;
					shadowAttackFrames[i].visible = false;
				}
				// Show regular graphics again
				knightGraphics.visible = true;
				shadowGraphics.visible = true;
				// Reset attacking flag
				self.isAttacking = false;
				// Reset the global target position to knight's current position
				target.x = self.x;
				target.y = self.y;
			}
		}, 50); // 50ms per frame for a fast attack animation
	};
});
var LaserBeam = Container.expand(function () {
	var self = Container.call(this);
	var laserBeamGraphics = LK.getAsset('droneLaserBeam', {
		anchorX: 0.5,
		anchorY: 0.5,
		blendMode: 1
	});
	self.addChild(laserBeamGraphics);
	self.speed = 1500; // Speed of the laser beam in pixels per second
	self.fire = function (x, y, rotation) {
		self.x = x;
		self.y = y;
		self.rotation = rotation;
		middlegroundContainer.addChild(self);
		// Calculate the distance the laser beam will travel
		var distance = 3000;
		// Calculate the duration based on speed
		var duration = distance / self.speed * 1000; // Convert to milliseconds
		// Tween the laser beam to move forward
		tween(self, {
			x: self.x + Math.cos(self.rotation) * distance,
			y: self.y + Math.sin(self.rotation) * distance
		}, {
			duration: duration,
			easing: tween.linear,
			onFinish: function onFinish() {
				self.destroy();
			}
		});
	};
	self.update = function () {
		if (self.intersects(knight.boundingBox)) {
			knight.takeHit(self);
			self.destroy();
		}
	};
});
var Room = Container.expand(function () {
	var self = Container.call(this);
	var background = LK.getAsset('backgroundWalls', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(background);
	self.x = 2048 / 2;
	self.y = 2732 / 2;
});
var Target = Container.expand(function () {
	var self = Container.call(this);
	self.x = 0;
	self.y = 0;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 //Init game with black background 
});
/**** 
* Game Code
****/ 
// Utility function to calculate the angle difference
function calculateAngleDiff(targetAngle, currentAngle) {
	var angleDiff = targetAngle - currentAngle;
	// Normalize angle difference to [-PI, PI]
	while (angleDiff > Math.PI) {
		angleDiff -= 2 * Math.PI;
	}
	while (angleDiff < -Math.PI) {
		angleDiff += 2 * Math.PI;
	}
	return angleDiff;
}
//<Write entity 'classes' with empty functions for important behavior here>
//<Write imports for supported plugins here>
//<Assets used in the game will automatically appear here>
//<Write game logic code here, including initializing arrays and variables>
var DroneManager = function DroneManager() {
	var self = this;
	self.droneCounter = 0; // Initialize droneCounter to track the number of drones
	self.drones = [];
	self.start = function () {
		// Clear previous drones from the scene and the drones array
		self.drones.forEach(function (drone) {
			drone.destroy();
		});
		self.drones = [];
		// Create the drone
		var drone = new Drone(self.droneCounter); // Pass the current level to the Drone constructor
		// Increment counter after drone creation so first drone is level 0
		self.droneCounter++;
		// Check win condition after incrementing counter
		if (self.droneCounter > 3) {
			LK.getSound('knight-win').play(); // Play knight-win sound
			LK.setTimeout(function () {
				LK.showYouWin(); // Show win screen after 2000ms delay
			}, 2000);
			return;
		}
		// Explicitly set position before adding to the scene
		drone.x = Math.random() < 0.5 ? -1024 : 3072;
		drone.y = 1366;
		// Store the current target index
		//drone.currentTargetIndex = currentTargetIndex;
		// Set the initial target to the current corner position
		drone.target = {
			x: 1024,
			y: 1366
		};
		// Add to container and array
		middlegroundContainer.addChild(drone);
		self.drones.push(drone);
		// This ensures all properties are set before tweening begins
		LK.setTimeout(function () {
			drone.init();
		}, 100);
	};
};
/**** 
* Global variables
****/ 
var isDebug = false;
var isDied = false; // Global flag to track if the knight has died
var gameStarted = false;
var droneManager = new DroneManager();
var backgroundContainer;
var middlegroundContainer;
var foregroundContainer;
var knight;
var background; // Declare a global variable for the background
var target;
var punchButton;
var runSoundInterval;
var borderOffset = 380;
var corners = [{
	x: borderOffset,
	y: borderOffset
}, {
	x: 2048 - borderOffset,
	y: borderOffset
}, {
	x: borderOffset,
	y: 2732 - borderOffset
}, {
	x: 2048 - borderOffset,
	y: 2732 - borderOffset
}];
function log() {
	if (isDebug) {
		console.log.apply(console, arguments);
	}
}
function initializeGame() {
	// Create containers
	backgroundContainer = new Container();
	middlegroundContainer = new Container();
	foregroundContainer = new Container();
	// Add containers to game
	game.addChild(backgroundContainer);
	game.addChild(middlegroundContainer);
	game.addChild(foregroundContainer);
	// Initialize background
	background = new Background(); // Use Background class instead of LK.getAsset
	backgroundContainer.addChild(background);
	// Initialize room
	var room = new Room();
	backgroundContainer.addChild(room);
	// Initialize knight
	knight = new Knight();
	knight.x = 2048 / 2;
	knight.y = 2732 / 2;
	middlegroundContainer.addChild(knight);
	// Initialize target
	target = new Target();
	target.x = knight.x;
	target.y = knight.y;
	foregroundContainer.addChild(target);
	// Initialize punch button
	punchButton = new ButtonPunch();
	punchButton.x = 2048 - 220;
	punchButton.y = 220;
	foregroundContainer.addChild(punchButton);
	// Initialize sound
	runSoundInterval = LK.setInterval(playRunSound, 350);
	droneManager = new DroneManager();
	LK.setTimeout(function () {
		gameStarted = true;
		droneManager.start();
	}, 1000);
}
function playRunSound() {
	if (knight.isMoving) {
		LK.getSound('knight-run').play();
	}
}
initializeGame();