/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
/** 
	* Represents an Angel of Light ally that stuns enemies and deals high damage to dark enemies.
	*/ 
var AngelOfLight = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the angel graphic asset (reusing viking_ally for simplicity)
	// Will need a dedicated asset for the Angel of Light if available.
	var graphics = self.attachAsset('angel_of_light_asset', {
		// Placeholder asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.tint = 0xFFFF00; // Yellow tint for Angel of Light
	self.attackRange = 600; // Moderate attack range
	self.attackDamage = 5; // Base damage
	self.attackInterval = 480; // Attack every 8 seconds (480 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.stunDuration = 5 * 60; // Stun duration in ticks (5 seconds)
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and using light ability.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy within range
			var closestEnemy = null;
			var closestDistance = self.attackRange;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, use light ability
			if (closestEnemy) {
				// Apply stun and damage to the target
				if (closestEnemy.tag !== 'Dragon') {
					// Dragons are immune to stuns (slowdown effect)
					closestEnemy.slowTimer = Math.max(closestEnemy.slowTimer, self.stunDuration); // Apply stun (reusing slowTimer)
					closestEnemy.currentSlowAmount = 0.0; // 100% slowdown (stun)
				}
				var damageToDeal = self.attackDamage;
				if (closestEnemy.tag === 'Black') {
					damageToDeal *= 3; // Triple damage against Black enemies
				}
				closestEnemy.takeDamage(damageToDeal, self); // Deal damage
				// Optional: Add visual/sound effect for light ability here later
				LK.effects.flashObject(closestEnemy, 0xFFFFFF, 300); // Flash white for stun/damage
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents an allied archer that shoots arrows independently.
*/ 
var ArcherAlly = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the archer graphic asset
	var graphics = self.attachAsset('Archer', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No rotation needed for 'Archer' asset as it's already upright and flipped
	self.fireTimer = 0; // Timer for shooting
	self.fireInterval = 180; // Shoot every 3 seconds (3 * 60 ticks)
	/** 
	* Update method called each game tick by the LK engine.
	* Handles firing logic.
	*/ 
	self.update = function () {
		self.fireTimer++;
		var effectiveFireInterval = Math.max(60, self.fireInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.fireTimer >= effectiveFireInterval) {
			self.fireTimer = 0; // Reset timer
			// Find the closest enemy to shoot at
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Calculate distance to the enemy
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, fire an arrow
			if (closestEnemy) {
				// Calculate angle towards the closest enemy
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				// Create a new arrow instance
				var newArrow = new Arrow(angle);
				// Apply multi-shot to allies if the upgrade is enabled for the player
				if (multiShotEnabled) {
					var angle2 = angle + Math.PI / 12; // Offset by 15 degrees
					var newArrow2 = new Arrow(angle2);
					newArrow2.x = self.x;
					newArrow2.y = self.y;
					newArrow2.lastY = newArrow2.y;
					newArrow2.lastX = newArrow2.x;
					game.addChild(newArrow2);
					arrows.push(newArrow2);
					var angle3 = angle - Math.PI / 12; // Offset by -15 degrees
					var newArrow3 = new Arrow(angle3);
					newArrow3.x = self.x;
					newArrow3.y = self.y;
					newArrow3.lastY = newArrow3.y;
					newArrow3.lastX = newArrow3.x;
					game.addChild(newArrow3);
					arrows.push(newArrow3);
				}
				newArrow.x = self.x;
				newArrow.y = self.y;
				// Ally arrows do not count towards the player's reload counter
				// The Arrow class handles piercing level based on player upgrade, but the ally doesn't benefit from player reload.
				// For simplicity, we'll let the ally benefit from player's piercing upgrade.
				newArrow.lastY = newArrow.y;
				newArrow.lastX = newArrow.x;
				// Add the arrow to the game scene and the tracking array.
				game.addChild(newArrow);
				arrows.push(newArrow); // Add to the same arrows array for collision detection
				// Ally doesn't play the 'shoot' sound
			}
		}
	};
	return self; // Return self for potential inheritance
});
// Sound when an enemy reaches the bastion
// No plugins needed for this version of the game.
/** 
* Represents an Arrow fired by the player.
* @param {number} angle - The angle in radians at which the arrow is fired.
*/ 
var Arrow = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the arrow graphic asset
	var graphics = self.attachAsset('arrow', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align arrow graphic with direction
	self.speed = 30; // Speed of the arrow in pixels per tick
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	self.pierceLeft = arrowPierceLevel; // How many more enemies this arrow can pierce
	self.damage = arrowDamage; // Damage dealt by this arrow
	self.isPoison = poisonShotsEnabled; // Flag if this arrow applies poison
	self.targetEnemy = null; // Potential target for aimbot
	self.seekSpeed = 0.1; // How quickly the arrow adjusts its direction to seek
	if (aimbotEnabled) {
		// Find the closest enemy to seek if aimbot is enabled
		var closestEnemy = null;
		var closestDistance = Infinity;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < closestDistance) {
				closestDistance = distance;
				closestEnemy = enemy;
			}
		}
		if (closestEnemy) {
			self.targetEnemy = closestEnemy;
		}
	}
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the arrow based on its velocity.
	*/ 
	self.update = function () {
		if (aimbotEnabled && self.targetEnemy && self.targetEnemy.parent) {
			// If aimbot is enabled, a target exists and is still in the game, seek it
			var targetAngle = Math.atan2(self.targetEnemy.x - self.x, -(self.targetEnemy.y - self.y));
			// Smoothly adjust the arrow's angle towards the target angle
			var angleDiff = targetAngle - (self.rotation - Math.PI / 2); // Difference considering graphic rotation
			// Normalize angle difference to be between -PI and PI
			if (angleDiff > Math.PI) {
				angleDiff -= 2 * Math.PI;
			}
			if (angleDiff < -Math.PI) {
				angleDiff += 2 * Math.PI;
			}
			// Interpolate angle
			var newAngle = self.rotation - Math.PI / 2 + angleDiff * self.seekSpeed;
			self.rotation = newAngle + Math.PI / 2;
			self.vx = Math.sin(newAngle) * self.speed;
			self.vy = -Math.cos(newAngle) * self.speed;
		} else if (aimbotEnabled && (!self.targetEnemy || !self.targetEnemy.parent)) {
			// If aimbot is enabled but current target is gone, find a new target
			self.targetEnemy = null; // Clear old target
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			if (closestEnemy) {
				self.targetEnemy = closestEnemy;
			}
		}
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Baby Dragon enemy with rage mode when no other dragons are present.
*/ 
var BabyDragon = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the baby dragon graphic asset
	var graphics = self.attachAsset('baby_dragon_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No base tint - only apply pink tint when raging
	self.type = 'baby_dragon';
	self.speed = 3; // Base speed (will be set from spawn)
	self.health = 50; // Base health (will be set from spawn)
	self.maxHealth = 50;
	self.dodgeChance = 0.25; // 25% dodge chance (less than adult dragon)
	self.tag = 'Dragon'; // Dragon-tagged enemy
	self.isRaging = false;
	self.rageSpeedMultiplier = 2.0; // Double speed when raging
	self.baseSpeed = self.speed;
	self.poisonStacks = 0;
	self.poisonTimer = 0;
	self.poisonDamagePerTick = 0.05;
	self.slowTimer = 0;
	self.currentSlowAmount = 1.0;
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the baby dragon and checks for rage mode.
	*/ 
	self.update = function () {
		// Check for rage mode (no other dragons on screen)
		var otherDragonsExist = false;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			if (enemy !== self && enemy.tag === 'Dragon') {
				otherDragonsExist = true;
				break;
			}
		}
		// Apply or remove rage mode
		if (!otherDragonsExist && !self.isRaging) {
			// Enter rage mode
			self.isRaging = true;
			self.speed = self.baseSpeed * self.rageSpeedMultiplier;
			// Apply pink tint with tween animation
			tween(graphics, {
				tint: 0xFF69B4
			}, {
				duration: 300
			}); // Pink tint when raging
			LK.effects.flashObject(self, 0xFF69B4, 500); // Flash effect with pink
		} else if (otherDragonsExist && self.isRaging) {
			// Exit rage mode
			self.isRaging = false;
			self.speed = self.baseSpeed;
			// Remove tint with tween animation
			tween(graphics, {
				tint: 0xFFFFFF
			}, {
				duration: 300
			}); // Return to normal color
		}
		// Normal movement (dragons are immune to slowdown)
		self.y += self.speed;
		// Apply poison damage
		if (self.poisonStacks > 0) {
			self.poisonTimer++;
			if (self.poisonTimer >= 30) {
				self.poisonTimer = 0;
				var poisonDmg = self.poisonStacks * self.poisonDamagePerTick * 30;
				self.health -= poisonDmg;
			}
			if (self.health <= 0 && self.parent) {
				LK.setScore(LK.getScore() + 1);
				scoreTxt.setText(LK.getScore());
				self.destroy();
				return;
			}
		}
		// Visual feedback based on health
		var healthRatio = self.maxHealth > 0 ? self.health / self.maxHealth : 0;
		graphics.alpha = 0.4 + healthRatio * 0.6;
	};
	/** 
	* Method called when the baby dragon takes damage.
	*/ 
	self.takeDamage = function (damage, source) {
		// Check for dodge
		if (self.dodgeChance > 0 && Math.random() < self.dodgeChance) {
			return false;
		}
		// Dragons are not immune to arrows/cannonballs
		self.health -= damage;
		// Apply poison if applicable
		if (source && source.isPoison) {
			self.poisonStacks++;
			self.poisonTimer = 0;
		}
		// Dragons are immune to slowdown effects
		return self.health <= 0;
	};
	return self;
});
/** 
* Represents a Bomb projectile thrown by a Bomber ally.
* @param {number} targetX - The target X coordinate.
* @param {number} targetY - The target Y coordinate.
*/ 
var Bomb = Container.expand(function (targetX, targetY) {
	var self = Container.call(this);
	// Create and attach the bomb graphic asset
	var graphics = self.attachAsset('bomb_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.targetX = targetX;
	self.targetY = targetY;
	self.startX = self.x;
	self.startY = self.y;
	self.damage = 15; // Area damage
	self.explosionRadius = 200; // Explosion radius
	self.arcHeight = 300; // Height of bomb arc
	self.flightTime = 60; // 1 second flight time
	self.flightTimer = 0;
	self.hasExploded = false;
	/** 
	* Update method called each game tick by the LK engine.
	* Handles arc movement and explosion.
	*/ 
	self.update = function () {
		if (self.hasExploded) {
			return;
		}
		self.flightTimer++;
		var progress = self.flightTimer / self.flightTime;
		if (progress >= 1) {
			// Bomb has reached target, explode
			self.explode();
			return;
		}
		// Calculate arc position
		var baseX = self.startX + (self.targetX - self.startX) * progress;
		var baseY = self.startY + (self.targetY - self.startY) * progress;
		// Add arc height (parabola)
		var arcOffset = -4 * self.arcHeight * progress * (progress - 1);
		self.x = baseX;
		self.y = baseY - arcOffset;
		// Rotate bomb as it flies
		graphics.rotation += 0.2;
	};
	self.explode = function () {
		if (self.hasExploded) {
			return;
		}
		self.hasExploded = true;
		// Create explosion visual effect
		LK.effects.flashScreen(0xFFAA00, 200); // Orange flash
		// Deal area damage to all enemies within radius
		for (var i = enemies.length - 1; i >= 0; i--) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance <= self.explosionRadius) {
				// Calculate damage falloff (full damage at center, less at edges)
				var damageFalloff = 1 - distance / self.explosionRadius * 0.5;
				var damageToApply = self.damage * damageFalloff;
				var enemyDefeated = enemy.takeDamage(damageToApply, self);
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1);
					scoreTxt.setText(LK.getScore());
					enemy.destroy();
					enemies.splice(i, 1);
				}
				// Apply visual effect to hit enemies
				LK.effects.flashObject(enemy, 0xFFAA00, 300);
			}
		}
		self.destroy();
	};
	return self;
});
/** 
* Represents a Bomber ally that throws bombs for area damage.
*/ 
var Bomber = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the bomber graphic asset
	var graphics = self.attachAsset('bomber_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range like other allies
	self.attackInterval = 240; // Attack every 4 seconds
	self.attackTimer = 0;
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and throwing bombs.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier);
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0;
			// Find a suitable target (not Dragon-tagged)
			var bestTarget = null;
			var bestScore = -1;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Skip Dragon-tagged enemies
				if (enemy.tag === 'Dragon') {
					continue;
				}
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance <= self.attackRange) {
					// Prioritize groups of enemies (check nearby enemy count)
					var nearbyCount = 0;
					for (var j = 0; j < enemies.length; j++) {
						if (i !== j) {
							var ex = enemies[j].x - enemy.x;
							var ey = enemies[j].y - enemy.y;
							if (Math.sqrt(ex * ex + ey * ey) <= 200) {
								nearbyCount++;
							}
						}
					}
					var score = nearbyCount * 10 + (self.attackRange - distance) / 100;
					if (score > bestScore) {
						bestScore = score;
						bestTarget = enemy;
					}
				}
			}
			if (bestTarget) {
				// Create and throw bomb
				var bomb = new Bomb(bestTarget.x, bestTarget.y);
				bomb.startX = self.x;
				bomb.startY = self.y;
				bomb.x = self.x;
				bomb.y = self.y;
				game.addChild(bomb);
				bombs.push(bomb);
			}
		}
	};
	return self;
});
/** 
* Represents a Bouncy Ball that bounces around the screen dealing damage to enemies.
*/ 
var BouncyBall = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the bouncy ball graphic asset (reusing cannonball for now)
	var graphics = self.attachAsset('cannonball', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.5,
		scaleY: 1.5
	});
	graphics.tint = 0xFF00FF; // Magenta tint for bouncy ball
	self.speed = 15; // Base speed
	self.damage = 20; // Massive damage
	self.vx = (Math.random() - 0.5) * self.speed * 2; // Random initial horizontal velocity
	self.vy = -Math.abs((Math.random() - 0.5) * self.speed * 2); // Initial upward velocity
	self.lifetime = 600; // 10 seconds lifetime (600 ticks)
	self.lifetimeTimer = 0;
	self.bounceCount = 0; // Track number of bounces
	self.maxBounces = 20; // Maximum bounces before disappearing
	/** 
	* Update method called each game tick by the LK engine.
	* Handles movement, bouncing, and lifetime.
	*/ 
	self.update = function () {
		self.lifetimeTimer++;
		// Check lifetime
		if (self.lifetimeTimer >= self.lifetime || self.bounceCount >= self.maxBounces) {
			self.destroy();
			return;
		}
		// Move
		self.x += self.vx;
		self.y += self.vy;
		// Bounce off walls
		if (self.x <= graphics.width / 2 || self.x >= GAME_WIDTH - graphics.width / 2) {
			self.vx = -self.vx; // Reverse horizontal direction
			self.x = Math.max(graphics.width / 2, Math.min(GAME_WIDTH - graphics.width / 2, self.x));
			self.bounceCount++;
			// Flash on bounce
			LK.effects.flashObject(self, 0xFFFFFF, 200);
		}
		// Bounce off top and bottom
		if (self.y <= graphics.height / 2 || self.y >= BASTION_Y - graphics.height / 2) {
			self.vy = -self.vy; // Reverse vertical direction
			self.y = Math.max(graphics.height / 2, Math.min(BASTION_Y - graphics.height / 2, self.y));
			self.bounceCount++;
			// Flash on bounce
			LK.effects.flashObject(self, 0xFFFFFF, 200);
		}
	};
	return self;
});
/** 
	* Represents a Cannon ally that targets the strongest enemy.
	*/ 
var Cannon = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the cannon graphic asset (need to add a new asset for this)
	// Use dragon slayer cannon asset if mode is enabled, otherwise use regular cannon asset
	var assetId = self.dragonSlayerMode ? 'dragon_slayer_cannon_asset' : 'cannon_asset';
	var graphics = self.attachAsset(assetId, {
		// Use actual cannon asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = 800; // Long attack range
	self.attackDamage = 10; // High damage
	self.attackInterval = 300; // Attack every 5 seconds (300 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.rotation = 0; // For aiming visual if implemented later
	self.dragonSlayerMode = false; // Flag to indicate if this cannon is a dragon slayer cannon
	/** 
	* Update method called each game tick by the LK engine.
	* Handles attacking the strongest enemy.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			var targetEnemy = null;
			if (self.dragonSlayerMode) {
				// In dragon slayer mode, prioritize dragons
				var closestDragon = null;
				var closestDragonDistance = Infinity;
				var strongestNonDragon = null;
				var maxNonDragonHealth = -1;
				for (var i = 0; i < enemies.length; i++) {
					var enemy = enemies[i];
					if (enemy.tag === 'Dragon') {
						// Check distance for dragons
						var dx = enemy.x - self.x;
						var dy = enemy.y - self.y;
						var distance = Math.sqrt(dx * dx + dy * dy);
						if (distance < closestDragonDistance) {
							closestDragonDistance = distance;
							closestDragon = enemy;
						}
					} else {
						// Track strongest non-dragon as fallback
						if (enemy.health > maxNonDragonHealth) {
							maxNonDragonHealth = enemy.health;
							strongestNonDragon = enemy;
						}
					}
				}
				// Prioritize dragon if found, otherwise target strongest non-dragon
				targetEnemy = closestDragon || strongestNonDragon;
			} else {
				// Normal mode: find the strongest enemy (highest health)
				var maxHealth = -1;
				for (var i = 0; i < enemies.length; i++) {
					var enemy = enemies[i];
					if (enemy.health > maxHealth) {
						maxHealth = enemy.health;
						targetEnemy = enemy;
					}
				}
			}
			// If a target enemy is found within range, attack it
			if (targetEnemy) {
				// Calculate angle towards the target enemy
				var angle = Math.atan2(targetEnemy.x - self.x, -(targetEnemy.y - self.y));
				// Create a new cannonball instance, passing the dragon slayer mode status
				var newCannonball = new Cannonball(angle);
				newCannonball.dragonSlayerMode = self.dragonSlayerMode; // Pass the mode status
				// Position the cannonball at the cannon's location
				newCannonball.x = self.x;
				newCannonball.y = self.y;
				newCannonball.lastY = newCannonball.y; // Initialize lastY for state tracking
				newCannonball.lastX = newCannonball.x; // Initialize lastX for state tracking
				// If dragon slayer mode and targeting a dragon, apply damage bonus
				if (self.dragonSlayerMode && targetEnemy.tag === 'Dragon') {
					newCannonball.dragonDamageMultiplier = 25; // 25x damage to dragons
					// The Cannonball class will handle the asset and tint based on the mode.
				}
				// Add the cannonball to the game scene and the tracking array.
				game.addChild(newCannonball);
				cannonballs.push(newCannonball); // Add to the new cannonballs array
				// Optional: Add a visual/sound effect for cannon shot here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
	* Represents a Cannonball fired by a Cannon.
	* @param {number} angle - The angle in radians at which the cannonball is fired.
	*/ 
var Cannonball = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the graphic asset (rocket if dragon slayer mode, otherwise cannonball)
	var assetId = self.dragonSlayerMode ? 'rocket_asset' : 'cannonball';
	var graphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align graphic with direction
	// Apply red tint for rocket if in dragon slayer mode
	if (self.dragonSlayerMode) {
		graphics.tint = 0xFF0000; // Red tint for dragon slayer rockets
	}
	self.dragonSlayerMode = false; // Flag to indicate if this is a dragon slayer rocket
	self.dragonDamageMultiplier = 1; // Default damage multiplier
	self.speed = 20; // Base speed of the cannonball
	self.damage = 10; // Base damage dealt by this cannonball
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
		self.damage += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the cannonball based on its velocity.
	*/ 
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Dart projectile fired by a Dart Ally.
* @param {number} angle - The angle in radians at which the dart is fired.
*/ 
var Dart = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the dart graphic asset (reusing arrow for simplicity)
	// Will need a dedicated asset for the Dart if available.
	var graphics = self.attachAsset('dart_asset', {
		// Placeholder asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.tint = 0x9933CC; // Purple tint for darts
	graphics.rotation = angle + Math.PI / 2; // Align dart graphic with direction
	self.speed = 40; // Fast speed
	self.damage = 0.5; // Base damage dealt by this dart
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
		self.damage += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the dart based on its velocity.
	*/ 
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Dart Ally that shoots fast darts.
*/ 
var DartAlly = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the dart ally graphic asset (reusing archer asset for simplicity)
	// Will need a dedicated asset for the Dart Ally if available.
	var graphics = self.attachAsset('disguised_swordsman', {
		// Placeholder asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range
	self.attackDamage = 0.5; // Low damage per dart
	self.attackInterval = 30; // Attack every 0.5 seconds (30 ticks) - very fast
	self.attackTimer = 0; // Timer for attacks
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and shooting darts.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(10, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade, min 0.16s
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy to shoot at
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Calculate distance to the enemy
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, shoot a dart
			if (closestEnemy) {
				// Calculate angle towards the closest enemy
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				// Create a new dart instance
				var newDart = new Dart(angle);
				newDart.x = self.x;
				newDart.y = self.y;
				newDart.lastY = newDart.y;
				newDart.lastX = newDart.x;
				// Add the dart to the game scene and the tracking array.
				game.addChild(newDart);
				darts.push(newDart); // Add to the new darts array
				// Optional: Add throwing sound effect here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
	* Represents an Enemy attacker moving towards the bastion.
	* @param {string} type - The type of enemy ('swordsman', 'knight', 'thief', 'boss', 'shield', 'wizard', 'elite_knight').
* @param {number} speed - The final calculated speed of the enemy.
* @param {number} health - The initial and maximum health of the enemy.
* @param {number} dodgeChance - The chance (0 to 1) for the enemy to dodge an attack.
*/ 
var Enemy = Container.expand(function (type, speed, health, dodgeChance) {
	var self = Container.call(this);
	// Set asset based on type
	var assetId = 'enemy'; // Default swordsman asset
	if (type === 'knight') {
		assetId = 'knight';
	} else if (type === 'elite_knight') {
		assetId = 'elite_knight_asset'; // Use specific asset for elite knight
	} else if (type === 'thief') {
		assetId = 'thief';
	} else if (type === 'boss') {
		assetId = 'boss';
	} else if (type === 'shield') {
		assetId = 'shield_enemy'; // Use specific asset for shield
	} else if (type === 'wizard') {
		assetId = 'wizard_enemy'; // Use specific asset for wizard
	} else if (type === 'spearman') {
		assetId = 'spearman'; // Use specific asset for spearman
	} else if (type === 'war_elephant') {
		assetId = 'war_elephant'; // Use specific asset for war elephant
	} else if (type === 'elite_shield') {
		assetId = 'elite_shield_asset'; // Use specific asset for elite shield
	} else if (type === 'shaman') {
		assetId = 'shaman_enemy'; // Use specific asset for shaman
	} else if (type === 'hot_air_balloon') {
		assetId = 'hot_air_balloon_asset'; // Use specific asset for hot air balloon
	} else if (type === 'dark_bowman') {
		assetId = 'dark_bowman_asset'; // Use specific asset for dark bowman
	} else if (type === 'jester') {
		assetId = 'jester_asset'; // Use specific asset for jester
	} else if (type === 'dark_war_elephant') {
		assetId = 'dark_war_elephant_asset'; // Use specific asset for dark war elephant
	} else if (type === 'dark_spearman') {
		assetId = 'dark_spearman_asset'; // Use specific asset for dark spearman
	} else if (type === 'dragon') {
		assetId = 'dragon_asset'; // Use specific asset for dragon
	} else if (type === 'flag_bearer') {
		assetId = 'flag_bearer_asset'; // Use specific asset for flag bearer
	} else if (type === 'baby_dragon') {
		assetId = 'baby_dragon_asset'; // Use specific baby dragon asset
	}
	var graphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.type = type; // 'swordsman', 'knight', 'thief', 'boss', 'shield', 'wizard', 'elite_knight', 'shaman', etc.
	self.speed = speed; // Final calculated speed
	self.health = health;
	self.maxHealth = health; // Store max health for visual feedback
	self.dodgeChance = dodgeChance || 0; // Default to 0 if undefined
	self.reflectChance = type === 'jester' ? 0.20 : 0; // 20% reflect chance, added in Enemy class
	self.poisonStacks = 0; // Number of poison stacks
	self.poisonTimer = 0; // Timer for poison damage
	self.poisonDamagePerTick = 0.05; // Damage per tick per stack
	self.slowTimer = 0; // Timer for slowdown effect
	self.currentSlowAmount = 1.0; // Multiplier for current slowdown effect (1.0 means no slow)
	// Initialize shaman-specific properties
	if (type === 'shaman') {
		self.shamanTimer = 0;
	}
	// Set tag property based on type
	self.tag = null; // Default tag is null
	if (self.type === 'wizard' || self.type === 'spearman' || self.type === 'war_elephant' || self.type === 'shaman') {
		self.tag = 'Green';
	} else if (self.type === 'dark_bowman' || self.type === 'dark_war_elephant' || self.type === 'dark_spearman') {
		self.tag = 'Black'; // Black-tagged enemies are immune to arrows and cannonballs
	}
	// Wizard-specific properties
	if (self.type === 'wizard') {
		self.teleportTimer = 0;
		self.teleportInterval = 180; // 3 seconds * 60 FPS
	}
	// --- Public Methods (defined before use) ---
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the enemy downwards (or teleports for wizard) and updates visual feedback.
	*/ 
	self.update = function () {
		if (self.type === 'wizard') {
			self.teleportTimer = (self.teleportTimer || 0) + 1; // Initialize timer if needed
			if (self.teleportTimer >= self.teleportInterval) {
				self.teleportTimer = 0;
				// Teleport logic: Random X, slightly advanced Y
				var oldY = self.y;
				var teleportPadding = graphics.width / 2 + 20; // Use actual graphic width
				var newX = teleportPadding + Math.random() * (GAME_WIDTH - 2 * teleportPadding);
				// Advance Y slightly, but don't teleport past bastion
				var newY = Math.min(BASTION_Y - graphics.height, self.y + 100 + Math.random() * 100); // Advance 100-200px
				// Ensure not teleporting backwards significantly or offscreen top
				newY = Math.max(graphics.height / 2, newY);
				self.x = newX;
				self.y = newY;
				self.lastY = oldY; // Set lastY to pre-teleport position to avoid false bastion triggers
				// Add a visual effect for teleport
				LK.effects.flashObject(self, 0xAA00FF, 300); // Purple flash
			} else {
				// Move normally if not teleporting this frame
				self.y += self.speed;
			}
		} else {
			// Normal movement for other enemy types
			var effectiveSpeed = self.speed * self.currentSlowAmount;
			// Apply global slowdown relic if enabled and not a Dragon
			if (playerRelics.slowdown.enabled && self.tag !== 'Dragon') {
				effectiveSpeed *= 1 - playerRelics.slowdown.level * 0.02; // Apply global slow
			}
			// Apply Green Relic slowdown if enabled and enemy is Green-tagged and not a Dragon
			if (playerRelics.green.enabled && self.tag === 'Green' && self.tag !== 'Dragon') {
				effectiveSpeed *= 1 - playerRelics.green.level * 0.02; // Apply Green Relic slow
			}
			self.y += effectiveSpeed; // Apply slowdown to movement
		}
		// Decrease slowdown timer and reset slow amount if timer runs out
		if (self.slowTimer > 0) {
			self.slowTimer--;
			if (self.slowTimer <= 0) {
				self.currentSlowAmount = 1.0; // Reset speed multiplier when slowdown ends
				// Optional: Remove visual feedback for slowdown here later
			}
		}
		// Apply poison damage if stacks exist
		if (self.poisonStacks > 0) {
			self.poisonTimer++;
			if (self.poisonTimer >= 30) {
				// Apply poison damage every 0.5 seconds (30 ticks)
				self.poisonTimer = 0;
				var poisonDmg = self.poisonStacks * self.poisonDamagePerTick * 30; // Damage per 0.5s
				self.health -= poisonDmg;
				// Optional: Add visual feedback for poison damage here later
			}
			// Check if health dropped to zero or below due to poison
			if (self.health <= 0 && self.parent) {
				// Ensure enemy is still in the game
				// Enemy defeated by poison
				LK.setScore(LK.getScore() + 1); // Increment score.
				scoreTxt.setText(LK.getScore()); // Update score display.
				// Destroy the enemy
				self.destroy();
				// The main game update loop needs to handle removing the enemy from the `enemies` array
				return; // Stop updating this destroyed instance
			}
		}
		// Visual feedback based on health - alpha fade (applies to all types)
		var healthRatio = self.maxHealth > 0 ? self.health / self.maxHealth : 0;
		graphics.alpha = 0.4 + healthRatio * 0.6; // Fade from 1.0 down to 0.4
		// Shaman ability: reduce player ammo periodically
		if (self.type === 'shaman') {
			if (self.shamanTimer === undefined) {
				self.shamanTimer = 0;
			}
			self.shamanTimer += 1;
			var shamanAbilityInterval = 300; // 5 seconds * 60 FPS
			if (self.shamanTimer >= shamanAbilityInterval) {
				self.shamanTimer = 0;
				// Reduce player ammo, but not below 0
				arrowsFired = Math.min(maxArrowsBeforeCooldown, arrowsFired + 1); // Make it require one more shot for reload
				ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired));
				// Optional: Add a visual/sound effect for shaman ability
			}
		}
	}; //{N} // Adjusted line identifier
	/** 
	* Method called when the enemy is hit by an arrow.
	* Handles dodging and health reduction.
	* @param {number} damage - The amount of damage the arrow deals.
	* @returns {boolean} - True if the enemy is defeated, false otherwise.
	*/ 
	self.takeDamage = function (damage) {
		var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
		// Add source parameter, default to null
		// Check for dodge first (only if dodgeChance is positive)
		if (self.dodgeChance > 0 && Math.random() < self.dodgeChance) {
			// Optional: Add a visual effect for dodge here later
			// console.log(self.type + " dodged!");
			return false; // Dodged, so not defeated by this hit
		}
		// Check for reflection (only for Jester and non-cannonball projectiles)
		if (self.type === 'jester' && self.reflectChance > 0 && Math.random() < self.reflectChance && !(source instanceof Cannonball)) {
			// Optional: Add a visual effect for reflection here later
			// console.log(self.type + " reflected!");
			// Projectile is destroyed, enemy takes no damage
			if (source && source.destroy) {
				source.destroy();
				// Need to remove from the source array in the main game loop
			}
			return false; // Reflected, so not defeated by this hit
		}
		// Check if enemy is Black-tagged and source is an Arrow or Cannonball
		if (self.tag === 'Black' && (source instanceof Arrow || source instanceof Cannonball)) {
			// Black-tagged enemies are immune to arrow and cannonball projectiles
			// Unless Dark Relic is enabled
			if (!playerRelics.dark.enabled) {
				return false; // Not defeated, projectile has no effect
			}
		}
		var finalDamage = damage;
		// Apply damage relic bonus if enabled
		if (playerRelics.damage.enabled) {
			finalDamage += playerRelics.damage.level;
		}
		// Apply Green Relic damage bonus if enabled and enemy is Green-tagged
		if (playerRelics.green.enabled && self.tag === 'Green') {
			finalDamage *= 1 + playerRelics.green.level * 0.2;
		}
		// Apply Dark Relic damage bonus if enabled and enemy is Black-tagged
		if (playerRelics.dark.enabled && self.tag === 'Black' && (source instanceof Arrow || source instanceof Cannonball)) {
			finalDamage *= 1 + playerRelics.dark.level * 0.05;
		}
		self.health -= finalDamage;
		// Check if the damage source was a poison arrow and apply poison stacks
		if (source && source.isPoison) {
			// Use the 'source' parameter
			self.poisonStacks++; // Increase poison stacks
			self.poisonTimer = 0; // Reset timer to apply damage immediately
		}
		// Check if the damage source was a Magic Ball and apply slowdown
		if (source && source instanceof MagicBall) {
			if (self.tag !== 'Dragon') {
				// Dragons are immune to slowdowns
				self.slowTimer = source.slowDuration; // Apply slowdown duration
				self.currentSlowAmount = source.slowAmount; // Apply slowdown amount
				// Optional: Add visual feedback for slowdown here later
			}
		}
		// Check if the damage source was an Arrow and apply Dragon relic stun
		if (playerRelics.dragon.enabled && source instanceof Arrow && self.tag === 'Dragon') {
			// Apply stun (reusing slowTimer for duration, 0.0 for 100% slow)
			var stunDuration = 0.25 * 60 + playerRelics.dragon.level * 0.05 * 60; // Base 0.25s + 0.05s per level
			self.slowTimer = Math.max(self.slowTimer, stunDuration);
			self.currentSlowAmount = 0.0; // 100% slow (stun)
		}
		// Check if the damage source should apply Green Slowdown
		if (greenSlowdownEnabled && self.tag === 'Green' && self.slowTimer <= 0 && self.tag !== 'Dragon') {
			// Dragons are immune to slowdowns
			// Apply Green Slowdown only if the upgrade is active, enemy is Green, not already slowed, and not a Dragon
			self.slowTimer = 10 * 60; // 10 seconds * 60 ticks/sec
			self.currentSlowAmount = 0.9; // 10% slowdown
			// Optional: Add visual feedback for green slowdown
		}
		// Check if enemy was defeated by this damage
		var defeated = self.health <= 0;
		if (defeated && self.type === 'war_elephant') {
			// If War Elephant is defeated, spawn 5 spearmen
			for (var i = 0; i < 5; i++) {
				var spawnPadding = 100; // Padding from edge
				var spawnX = self.x + (Math.random() * 200 - 100); // Spawn around elephant's x
				var spawnY = self.y + (Math.random() * 100 - 50); // Spawn around elephant's y, slightly forward
				// Ensure spawns are within game bounds
				spawnX = Math.max(spawnPadding, Math.min(GAME_WIDTH - spawnPadding, spawnX));
				spawnY = Math.max(spawnPadding, Math.min(BASTION_Y - 50, spawnY)); // Don't spawn too close to bastion
				var newSpearman = new Enemy('spearman', currentEnemySpeed * enemySpeedMultiplier, 2, 0); // Base spearman stats
				newSpearman.x = spawnX;
				newSpearman.y = spawnY;
				newSpearman.lastY = newSpearman.y;
				game.addChild(newSpearman);
				enemies.push(newSpearman);
			}
		} else if (defeated && self.type === 'dark_war_elephant') {
			// If Dark War Elephant is defeated, spawn 5 Dark Bowmen
			for (var i = 0; i < 5; i++) {
				var spawnPadding = 100; // Padding from edge
				var spawnX = self.x + (Math.random() * 200 - 100); // Spawn around elephant's x
				var spawnY = self.y + (Math.random() * 100 - 50); // Spawn around elephant's y, slightly forward
				// Ensure spawns are within game bounds
				spawnX = Math.max(spawnPadding, Math.min(GAME_WIDTH - spawnPadding, spawnX));
				spawnY = Math.max(spawnPadding, Math.min(BASTION_Y - 50, spawnY)); // Don't spawn too close to bastion
				var newDarkBowman = new Enemy('dark_bowman', currentEnemySpeed * enemySpeedMultiplier, 5, 0); // Base dark bowman stats
				newDarkBowman.x = spawnX;
				newDarkBowman.y = spawnY;
				newDarkBowman.lastY = newDarkBowman.y;
				game.addChild(newDarkBowman);
				enemies.push(newDarkBowman);
			}
		} else if (defeated && self.type === 'hot_air_balloon') {
			// If Hot Air Balloon is defeated, spawn 5 random non-green enemies
			var possibleTypes = ['swordsman', 'knight', 'thief', 'shield', 'elite_knight', 'elite_shield', 'dark_bowman'];
			for (var i = 0; i < 5; i++) {
				// Choose random enemy type that is not green-tagged
				var randomType = possibleTypes[Math.floor(Math.random() * possibleTypes.length)];
				var randomHP = 1 + Math.floor(Math.random() * 5); // Random HP between 1-5
				var randomSpeed = currentEnemySpeed * 0.7 * enemySpeedMultiplier; // Slower than average
				var newEnemy = new Enemy(randomType, randomSpeed, randomHP, 0);
				// Spawn in a staggered pattern below the balloon
				var spawnPadding = 100;
				var spawnX = self.x + (Math.random() * 300 - 150); // Wider spread than elephant
				var spawnY = self.y + Math.random() * 200; // Always below the balloon
				// Ensure spawns are within game bounds
				spawnX = Math.max(spawnPadding, Math.min(GAME_WIDTH - spawnPadding, spawnX));
				spawnY = Math.min(BASTION_Y - 50, spawnY); // Don't spawn too close to bastion
				newEnemy.x = spawnX;
				newEnemy.y = spawnY;
				newEnemy.lastY = newEnemy.y;
				game.addChild(newEnemy);
				enemies.push(newEnemy);
			}
		}
		// No need to update alpha here, self.update handles it
		return defeated; // Return true if health is 0 or less
	}; //{O} // Adjusted line identifier
	// --- Initialization ---
	// Apply visual distinctions based on type
	graphics.tint = 0xFFFFFF; // Reset tint
	graphics.scale.set(1.0); // Reset scale
	if (self.type === 'knight') {
		graphics.tint = 0xCCCCCC; // Grey tint for Knights
		graphics.scale.set(1.1);
	} else if (self.type === 'elite_knight') {
		graphics.tint = 0xFFD700; // Gold tint for Elite Knights
		graphics.scale.set(1.2); // Slightly larger than normal knight
	} else if (self.type === 'thief') {
		graphics.tint = 0xCCFFCC; // Pale Green tint for Thieves
		graphics.scale.set(0.9);
	} else if (self.type === 'boss') {
		graphics.tint = 0xFFCCCC; // Pale Red tint for Bosses
		graphics.scale.set(1.4); // Make bosses quite large
	} else if (self.type === 'shield') {
		graphics.tint = 0xADD8E6; // Light Blue tint for Shield
		graphics.scale.set(1.2); // Make shield enemies bulky
	} else if (self.type === 'wizard') {
		graphics.tint = 0xE0B0FF; // Light Purple tint for Wizard
		graphics.scale.set(1.0);
	} else if (self.type === 'elite_shield') {
		graphics.tint = 0x8A2BE2; // Blue Violet tint for Elite Shield
		graphics.scale.set(1.3); // Slightly larger than normal shield
	} else if (self.type === 'jester') {
		graphics.tint = 0xFFB6C1; // Light Pink tint for Jester
		graphics.scale.set(1.0);
	} else if (self.type === 'dark_war_elephant') {
		graphics.tint = 0x333333; // Dark Grey tint for Dark War Elephant
		graphics.scale.set(1.4); // Same size as regular elephant
	} else if (self.type === 'dark_spearman') {
		graphics.scale.set(1.05); // Slightly larger than regular spearman
	} else if (self.type === 'dragon') {
		graphics.scale.set(1.6); // Dragons are large
	} //{11} // Modified original line identifier location
	return self; // Return self for potential inheritance
});
/** 
	* Represents a Flag Bearer enemy that provides a speed boost aura to nearby enemies.
	*/ 
var FlagBearer = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the flag bearer graphic asset
	var graphics = self.attachAsset('flag_bearer_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No tint applied to flag bearer
	self.type = 'flag_bearer';
	self.speed = 3; // Base speed (will be set from spawn)
	self.health = 5; // Base health (will be set from spawn)
	self.maxHealth = 5;
	self.dodgeChance = 0;
	self.tag = 'Green'; // Green-tagged enemy
	self.auraRadius = 300; // Radius of speed boost aura
	self.auraBoost = 1.5; // 50% speed boost to enemies in aura
	self.poisonStacks = 0;
	self.poisonTimer = 0;
	self.poisonDamagePerTick = 0.05;
	self.slowTimer = 0;
	self.currentSlowAmount = 1.0;
	// Create aura visual effect
	self.auraCircle = self.attachAsset('light_effect_asset', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.auraRadius * 2,
		height: self.auraRadius * 2,
		tint: 0x00FF00,
		alpha: 0.2
	});
	// Position aura behind the flag bearer
	self.setChildIndex(self.auraCircle, 0);
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the flag bearer and applies aura effects.
	*/ 
	self.update = function () {
		// Normal movement
		self.y += self.speed * self.currentSlowAmount;
		// Apply aura effect to nearby enemies
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			if (enemy === self) {
				continue;
			} // Skip self
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance <= self.auraRadius) {
				// Enemy is within aura range
				if (!enemy.hasAuraBoost) {
					enemy.hasAuraBoost = true;
					enemy.baseSpeed = enemy.speed;
					enemy.speed = enemy.baseSpeed * self.auraBoost;
				}
			} else if (enemy.hasAuraBoost) {
				// Enemy left aura range
				enemy.hasAuraBoost = false;
				enemy.speed = enemy.baseSpeed || enemy.speed;
			}
		}
		// Handle slowdown timer
		if (self.slowTimer > 0) {
			self.slowTimer--;
			if (self.slowTimer <= 0) {
				self.currentSlowAmount = 1.0;
			}
		}
		// Apply poison damage
		if (self.poisonStacks > 0) {
			self.poisonTimer++;
			if (self.poisonTimer >= 30) {
				self.poisonTimer = 0;
				var poisonDmg = self.poisonStacks * self.poisonDamagePerTick * 30;
				self.health -= poisonDmg;
			}
			if (self.health <= 0 && self.parent) {
				LK.setScore(LK.getScore() + 1);
				scoreTxt.setText(LK.getScore());
				self.destroy();
				return;
			}
		}
		// Visual feedback based on health
		var healthRatio = self.maxHealth > 0 ? self.health / self.maxHealth : 0;
		graphics.alpha = 0.4 + healthRatio * 0.6;
		// Update aura visual effect
		if (self.auraCircle) {
			self.auraCircle.x = self.x;
			self.auraCircle.y = self.y;
			// Pulse effect
			self.auraPulseTimer = (self.auraPulseTimer || 0) + 0.05;
			var pulseScale = 1.0 + Math.sin(self.auraPulseTimer) * 0.1;
			self.auraCircle.scale.set(pulseScale);
			self.auraCircle.alpha = 0.15 + Math.sin(self.auraPulseTimer * 2) * 0.05;
		}
	};
	/** 
	* Method called when the flag bearer takes damage.
	*/ 
	self.takeDamage = function (damage, source) {
		// Check for dodge
		if (self.dodgeChance > 0 && Math.random() < self.dodgeChance) {
			return false;
		}
		// Check if source is Arrow or Cannonball (Green enemies are not immune)
		self.health -= damage;
		// Apply poison if applicable
		if (source && source.isPoison) {
			self.poisonStacks++;
			self.poisonTimer = 0;
		}
		// Apply slowdown from Magic Ball
		if (source && source instanceof MagicBall) {
			self.slowTimer = source.slowDuration;
			self.currentSlowAmount = source.slowAmount;
		}
		// Apply Green Slowdown
		if (greenSlowdownEnabled && self.tag === 'Green' && self.slowTimer <= 0) {
			self.slowTimer = 10 * 60;
			self.currentSlowAmount = 0.9;
		}
		return self.health <= 0;
	};
	// Clean up aura effects when destroyed
	var originalDestroy = self.destroy;
	self.destroy = function () {
		// Remove aura effects from all enemies
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			if (enemy.hasAuraBoost) {
				enemy.hasAuraBoost = false;
				enemy.speed = enemy.baseSpeed || enemy.speed;
			}
		}
		// Clean up aura visual
		if (self.auraCircle) {
			self.auraCircle.destroy();
			self.auraCircle = null;
		}
		originalDestroy.call(self);
	};
	return self;
});
/** 
	* Represents a Magic Ball projectile fired by a Wizard Tower.
	* @param {number} angle - The angle in radians at which the magic ball is fired.
	*/ 
var MagicBall = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the magic ball graphic asset
	var graphics = self.attachAsset('magic_ball_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align magic ball graphic with direction
	self.speed = 15; // Base speed of the magic ball
	self.damage = 2; // Base damage dealt by this magic ball
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
		self.damage += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	self.slowDuration = 0; // Duration of slowdown applied on hit
	self.slowAmount = 0; // Multiplier for enemy speed on hit
	self.targetEnemy = null; // Track the specific enemy the magic ball is seeking
	self.seekSpeed = 0.05; // How quickly the magic ball adjusts its direction to seek
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the magic ball based on its velocity and seeks target if Aimbot is enabled.
	*/ 
	self.update = function () {
		if (aimbotEnabled && self.targetEnemy && self.targetEnemy.parent) {
			// If aimbot is enabled, a target exists and is still in the game, seek it
			var targetAngle = Math.atan2(self.targetEnemy.x - self.x, -(self.targetEnemy.y - self.y));
			// Smoothly adjust the magic ball's angle towards the target angle
			var angleDiff = targetAngle - (self.rotation - Math.PI / 2); // Difference considering graphic rotation
			// Normalize angle difference to be between -PI and PI
			if (angleDiff > Math.PI) {
				angleDiff -= 2 * Math.PI;
			}
			if (angleDiff < -Math.PI) {
				angleDiff += 2 * Math.PI;
			}
			// Interpolate angle
			var newAngle = self.rotation - Math.PI / 2 + angleDiff * self.seekSpeed;
			self.rotation = newAngle + Math.PI / 2;
			self.vx = Math.sin(newAngle) * self.speed;
			self.vy = -Math.cos(newAngle) * self.speed;
		} else if (aimbotEnabled && (!self.targetEnemy || !self.targetEnemy.parent)) {
			// If aimbot is enabled but current target is gone, find a new target
			self.targetEnemy = null; // Clear old target
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			if (closestEnemy) {
				self.targetEnemy = closestEnemy;
			}
		}
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Swordsman ally that attacks enemies in melee range.
*/ 
var Swordsman = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the swordsman graphic asset (reusing enemy asset for simplicity)
	var graphics = self.attachAsset('swordsmanAlly', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No tint needed as ally asset has unique colors
	graphics.scale.set(1.0); // Use the asset's intended scale
	self.attackRange = 150; // Melee attack range
	self.attackDamage = 1; // Damage per hit
	self.attackInterval = 60; // Attack every 1 second (60 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.lifetime = 10 * 60; // Lifetime in ticks (10 seconds * 60 ticks/sec)
	self.lifetimeTimer = 0; // Timer for lifetime
	/** 
	* Update method called each game tick by the LK engine.
	* Handles attacking and lifetime.
	*/ 
	self.update = function () {
		self.attackTimer++;
		self.lifetimeTimer++;
		// Check for lifetime
		var effectiveAttackInterval = Math.max(30, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade, min 0.5s
		if (self.lifetimeTimer >= self.lifetime) {
			self.destroy();
			// Remove from the swordsmen array in the main game loop
			return; // Stop updating this instance
		}
		// Find the closest enemy to chase or attack
		var closestEnemy = null;
		var closestDistance = Infinity;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			// Calculate distance to the enemy
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < closestDistance) {
				closestDistance = distance;
				closestEnemy = enemy;
			}
		}
		// If an enemy exists, chase it or attack if within range
		if (closestEnemy) {
			// Movement speed toward enemies
			var moveSpeed = 5;
			// If not within attack range, move toward the enemy
			if (closestDistance > self.attackRange) {
				// Calculate direction vector to enemy
				var dirX = closestEnemy.x - self.x;
				var dirY = closestEnemy.y - self.y;
				// Normalize the direction vector
				var length = Math.sqrt(dirX * dirX + dirY * dirY);
				dirX = dirX / length;
				dirY = dirY / length;
				// Move toward the enemy
				self.x += dirX * moveSpeed;
				self.y += dirY * moveSpeed;
			}
			// If within attack range and attack timer is ready, attack
			else if (self.attackTimer >= effectiveAttackInterval) {
				self.attackTimer = 0; // Reset timer
				// Apply damage to the enemy and check if it was defeated
				var finalSwordsmanDamage = self.attackDamage;
				// Apply damage relic bonus if enabled
				if (playerRelics.damage.enabled) {
					finalSwordsmanDamage += playerRelics.damage.level;
				}
				var enemyDefeated = closestEnemy.takeDamage(finalSwordsmanDamage, self); // Pass the swordsman as source
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score when enemy is defeated by swordsman.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					closestEnemy.destroy();
					// Remove from the enemies array in the main game loop
				}
				// Optional: Add a visual/sound effect for attack here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Viking ally that throws piercing axes.
*/ 
var VikingAlly = Container.expand(function () {
	var self = Container.call(this);
	var graphics = self.attachAsset('viking_ally', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range
	self.attackInterval = 150; // Attack every 2.5 seconds (150 ticks)
	self.attackTimer = 0; // Timer for attacks
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and throwing axes.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy within range
			var closestEnemy = null;
			var closestDistance = self.attackRange;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, throw an axe
			if (closestEnemy) {
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				var newAxe = new VikingAxe(angle);
				newAxe.x = self.x;
				newAxe.y = self.y;
				newAxe.lastY = newAxe.y;
				newAxe.lastX = newAxe.x;
				game.addChild(newAxe);
				vikingAxes.push(newAxe); // Add to the vikingAxes array
				// Optional: Add throwing sound effect here later
			}
		}
	};
	return self;
});
/** 
* Represents an Axe thrown by a Viking Ally.
* @param {number} angle - The angle in radians at which the axe is thrown.
*/ 
var VikingAxe = Container.expand(function (angle) {
	var self = Container.call(this);
	var graphics = self.attachAsset('viking_axe', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align axe graphic with direction
	self.speed = 25; // Speed of the axe
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	self.damage = 3; // Base damage dealt by this axe
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.damage += 5;
	}
	self.pierceLeft = 3; // Can pierce through 3 enemies
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the axe based on its velocity and handles rotation.
	*/ 
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
		graphics.rotation += 0.2; // Add spinning effect
	};
	return self;
});
/** 
	* Represents a Wizard Tower ally that shoots magic balls.
	*/ 
var WizardTower = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the wizard tower graphic asset
	var graphics = self.attachAsset('wizard_tower_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range
	self.attackDamage = 0.5; // Low damage, primary effect is slowdown
	self.attackInterval = 120; // Attack every 2 seconds (120 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.slowDuration = 180; // Duration of slowdown effect in ticks (3 seconds)
	self.slowAmount = 0.5; // Multiplier for enemy speed (0.5 means 50% slower)
	/** 
	* Update method called each game tick by the LK engine.
	* Handles attacking enemies.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy within range to shoot at
			var closestEnemy = null;
			var closestDistance = self.attackRange; // Limit to attack range
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Calculate distance to the enemy
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, fire a magic ball
			if (closestEnemy) {
				// Calculate angle towards the closest enemy
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				// Create a new magic ball instance
				var newMagicBall = new MagicBall(angle);
				// Position the magic ball at the tower's location
				newMagicBall.x = self.x;
				newMagicBall.y = self.y;
				newMagicBall.lastY = newMagicBall.y; // Initialize lastY for state tracking
				newMagicBall.lastX = newMagicBall.x; // Initialize lastX for state tracking
				newMagicBall.slowDuration = self.slowDuration; // Pass slow duration to the magic ball
				newMagicBall.slowAmount = self.slowAmount; // Pass slow amount to the magic ball
				// Add the magic ball to the game scene and the tracking array.
				game.addChild(newMagicBall);
				magicBalls.push(newMagicBall); // Add to the magicBalls array
				// Optional: Add a visual/sound effect for magic ball shot here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents an XBOW (crossbow) ally that rapidly shoots arrows.
*/ 
var XBOW = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the XBOW graphic asset
	var graphics = self.attachAsset('xbow_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.fireInterval = 20; // Very rapid fire (every 0.33 seconds)
	self.fireTimer = 0;
	self.targetingMode = 'closest_to_bastion'; // Default targeting mode
	self.smartTargetingEnabled = false; // Flag for smart targeting upgrade
	self.tintApplied = false; // Track if tint has been applied
	/** 
	* Update method called each game tick by the LK engine.
	* Handles rapid firing logic.
	*/ 
	self.update = function () {
		self.fireTimer++;
		var baseInterval = self.smartTargetingEnabled ? 15.36 : self.fireInterval; // 0.256 seconds when smart targeting enabled
		var effectiveFireInterval = Math.max(10, baseInterval * allyAttackSpeedMultiplier);
		if (self.fireTimer >= effectiveFireInterval) {
			self.fireTimer = 0;
			// Find target based on targeting mode
			var target = null;
			if (self.smartTargetingEnabled) {
				// Apply green tint when smart targeting is enabled
				if (!self.tintApplied) {
					graphics.tint = 0x00FF00; // Green tint
					self.tintApplied = true;
				}
				if (self.targetingMode === 'closest_to_bastion') {
					// Find enemy closest to bastion
					var closestDistance = Infinity;
					for (var i = 0; i < enemies.length; i++) {
						var enemy = enemies[i];
						var distanceToBastion = BASTION_Y - enemy.y;
						if (distanceToBastion > 0 && distanceToBastion < closestDistance) {
							closestDistance = distanceToBastion;
							target = enemy;
						}
					}
				} else if (self.targetingMode === 'strongest') {
					// Find enemy with highest health
					var maxHealth = -1;
					for (var i = 0; i < enemies.length; i++) {
						var enemy = enemies[i];
						if (enemy.health > maxHealth) {
							maxHealth = enemy.health;
							target = enemy;
						}
					}
				}
			}
			// Default behavior: shoot at center of screen
			var angle;
			if (target) {
				// Calculate angle towards target
				angle = Math.atan2(target.x - self.x, -(target.y - self.y));
			} else {
				// No target or smart targeting disabled - shoot straight up towards center
				angle = 0; // 0 radians = straight up
			}
			// Create arrow
			var newArrow = new Arrow(angle);
			newArrow.x = self.x;
			newArrow.y = self.y;
			newArrow.lastY = newArrow.y;
			newArrow.lastX = newArrow.x;
			// XBOW arrows are faster
			newArrow.speed *= 1.5;
			newArrow.vx = Math.sin(angle) * newArrow.speed;
			newArrow.vy = -Math.cos(angle) * newArrow.speed;
			// Disable aimbot for XBOW arrows
			newArrow.targetEnemy = null;
			game.addChild(newArrow);
			arrows.push(newArrow);
			// Apply multi-shot if enabled
			if (multiShotEnabled) {
				// Fire a second arrow with a slight angle offset
				var angle2 = angle + Math.PI / 12; // Offset by 15 degrees
				var newArrow2 = new Arrow(angle2);
				newArrow2.x = self.x;
				newArrow2.y = self.y;
				newArrow2.lastY = newArrow2.y;
				newArrow2.lastX = newArrow2.x;
				// XBOW arrows are faster
				newArrow2.speed *= 1.5;
				newArrow2.vx = Math.sin(angle2) * newArrow2.speed;
				newArrow2.vy = -Math.cos(angle2) * newArrow2.speed;
				// Disable aimbot for XBOW arrows
				newArrow2.targetEnemy = null;
				game.addChild(newArrow2);
				arrows.push(newArrow2);
				// Fire a third arrow with the opposite angle offset
				var angle3 = angle - Math.PI / 12; // Offset by -15 degrees
				var newArrow3 = new Arrow(angle3);
				newArrow3.x = self.x;
				newArrow3.y = self.y;
				newArrow3.lastY = newArrow3.y;
				newArrow3.lastX = newArrow3.x;
				// XBOW arrows are faster
				newArrow3.speed *= 1.5;
				newArrow3.vx = Math.sin(angle3) * newArrow3.speed;
				newArrow3.vy = -Math.cos(angle3) * newArrow3.speed;
				// Disable aimbot for XBOW arrows
				newArrow3.targetEnemy = null;
				game.addChild(newArrow3);
				arrows.push(newArrow3);
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
// Create the main game instance with a dark background color.
var game = new LK.Game({
	backgroundColor: 0x101030 // Dark blue/purple background
});
/**** 
* Game Code
****/ 
// Use actual war elephant asset
// Use actual spearman asset
// Placeholder ID, adjust size slightly, reuse flipX
// Placeholder ID
// Placeholder ID, adjust size slightly
// Constants defining game dimensions and key vertical positions.
//var facekit = LK.import('@upit/facekit.v1');
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
//var storage = LK.import('@upit/storage.v1');
//Storage library which should be used for persistent game data
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
//Only include the plugins you need to create the game.
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BASTION_Y = GAME_HEIGHT - 250; // Y-coordinate representing the defense line. Enemies crossing this trigger game over.
var FIRING_POS_Y = GAME_HEIGHT - 150; // Y-coordinate from where arrows are fired.
var FIRING_POS_X = GAME_WIDTH / 2; // X-coordinate from where arrows are fired (center).
// Arrays to keep track of active arrows and enemies.
var arrows = [];
var enemies = [];
// Variables for game state and difficulty scaling.
var scoreTxt; // Text2 object for displaying the score.
var ammoTxt; // Text2 object for displaying the current ammo count.
var dragStartX = null; // Starting X coordinate of a touch/mouse drag.
var dragStartY = null; // Starting Y coordinate of a touch/mouse drag.
var enemySpawnInterval = 120; // Initial ticks between enemy spawns (2 seconds at 60 FPS).
var arrowsFired = 0; // Counter for arrows fired since the last cooldown.
var cooldownTimer = 0; // Timer in ticks for the cooldown period.
var cooldownDuration = 6 * 60; // Cooldown duration in ticks (6 seconds * 60 ticks/sec). Min duration enforced in upgrade.
var baseMaxArrowsBeforeCooldown = 15; // Base max arrows before reload (Quiver upgrade)
var maxArrowsBeforeCooldown = baseMaxArrowsBeforeCooldown; // Max arrows before reload
var ammoRelicTimer = 0; // Timer for ammo relic regeneration
var arrowPierceLevel = 1; // How many enemies an arrow can pierce (Piercing Shots upgrade)
var arrowDamage = 1; // Base damage for arrows (Heat-tipped arrows upgrade)
var enemySpeedMultiplier = 1.0; // Multiplier for enemy speed (Sabotage upgrade) Min multiplier enforced in upgrade.
var minEnemySpawnInterval = 30; // Minimum ticks between enemy spawns (0.5 seconds).
var enemySpawnRateDecrease = 0.08; // Amount to decrease spawn interval each time an enemy spawns.
var currentEnemySpeed = 3; // Initial base speed of enemies.
var maxEnemySpeed = 12; // Maximum base speed enemies can reach.
var enemySpeedIncrease = 0.015; // Amount to increase enemy base speed each time an enemy spawns.
var archerAllies = []; // Array to hold ArcherAlly instances
var swordsmen = []; // Array to hold Swordsman instances
var cannonballs = []; // Array to hold Cannonball instances
var multiShotEnabled = false; // Flag for More Shots upgrade
var poisonShotsEnabled = false; // Flag for Poison Shots upgrade
var cannons = []; // Array to hold Cannon instances
var allyAttackSpeedMultiplier = 1.0; // Multiplier for ally attack speed
var wizardTowers = []; // Array to hold WizardTower instances
var magicBalls = []; // Array to hold MagicBall instances
var aimbotEnabled = false; // Flag for Aimbot upgrade
var greenKillerEnabled = false; // Flag for Green Killer upgrade
var refinedProjectilesEnabled = false; // Flag for Refined Projectiles upgrade
var greenSlowdownEnabled = false; // Flag for Green Slowdown upgrade
var vikingAllies = []; // Array to hold VikingAlly instances
var vikingAxes = []; // Array to hold VikingAxe instances
var darts = []; // Array to hold Dart instances
var angelOfLights = []; // Array to hold AngelOfLight instances
var bouncyBalls = []; // Array to hold BouncyBall instances
var bombs = []; // Array to hold Bomb instances
var bombers = []; // Array to hold Bomber instances
var xbows = []; // Array to hold XBOW instances
var xbowSmartTargetingEnabled = false; // Flag for XBOW Smart Targeting upgrade
var battleHornEnabled = false; // Flag for Battle Horn upgrade
var dragonSlayerCannonsModeEnabled = false; // Flag for Dragon Slayer Cannons upgrade
// --- Relics and Gold System ---
var playerGold = storage.playerGold || 0; // Load gold from storage, default to 0
// Load relics from storage using flat format
var storedRelicsData = storage.playerRelicsData || {};
var playerRelics = {
	damage: {
		level: storedRelicsData.damage_level || 0,
		enabled: storedRelicsData.damage_enabled || false
	},
	slowdown: {
		level: storedRelicsData.slowdown_level || 0,
		enabled: storedRelicsData.slowdown_enabled || false
	},
	green: {
		level: storedRelicsData.green_level || 0,
		enabled: storedRelicsData.green_enabled || false
	},
	dark: {
		level: storedRelicsData.dark_level || 0,
		enabled: storedRelicsData.dark_enabled || false
	},
	dragon: {
		level: storedRelicsData.dragon_level || 0,
		enabled: storedRelicsData.dragon_enabled || false
	},
	reload: {
		level: storedRelicsData.reload_level || 0,
		enabled: storedRelicsData.reload_enabled || false
	},
	ammo: {
		level: storedRelicsData.ammo_level || 0,
		enabled: storedRelicsData.ammo_enabled || false
	},
	swordsman: {
		level: storedRelicsData.swordsman_level || 0,
		enabled: storedRelicsData.swordsman_enabled || false
	}
};
var RELIC_MAX_LEVEL = 10;
var RELIC_COST_PER_LEVEL = 5; // 5 gold per level
// --- Upgrade System ---
var lastUpgradeScore = -1; // Score at which the last upgrade was offered
var isUpgradePopupActive = false; // Flag indicating if the upgrade choice popup is visible
var upgradePopup = null; // Container for the upgrade UI elements
var currentMusicPlaying = 'Gamemusic'; // Track which music is currently playing
var musicFadeInProgress = false; // Flag to track if a music fade transition is in progress
// Helper function to apply Sabotage effect to existing enemies
function applySabotage() {
	for (var i = 0; i < enemies.length; i++) {
		// We assume Enemy class will use enemySpeedMultiplier when calculating effective speed
		// If Enemy.speed stores base speed, we might need an effectiveSpeed method or update speed directly.
		// For simplicity, let's assume Enemy.update uses the global multiplier.
		// If direct modification is needed: enemies[i].speed = baseSpeed * enemySpeedMultiplier;
	}
	// Also update the current base speed calculation baseline if necessary, though modifying the multiplier should suffice.
}
// Helper function placeholder for adding Archer Ally
function addArcherAlly() {
	// Implementation requires ArcherAlly class definition
	console.log("Archer Ally upgrade chosen!");
	var ally = new ArcherAlly();
	// Position the ally next to the player's firing position, slightly offset.
	ally.x = FIRING_POS_X + 150; // Position to the right of the player
	ally.y = FIRING_POS_Y;
	game.addChild(ally);
	archerAllies.push(ally); // Add to the new archerAllies array
}
// Helper function to add a Cannon ally
function addCannon() {
	console.log("Cannon upgrade chosen!");
	var newCannon = new Cannon();
	// Position the cannon near the bastion line
	newCannon.x = GAME_WIDTH / 2 - 300; // Example position to the left of center
	newCannon.y = BASTION_Y - 100; // Position above the bastion line
	// Apply dragon slayer mode if the global flag is enabled
	newCannon.dragonSlayerMode = dragonSlayerCannonsModeEnabled;
	game.addChild(newCannon);
	cannons.push(newCannon); // Add to the cannons array
}
// Helper function to add a Wizard Tower
function addWizardTower() {
	console.log("Wizard Tower upgrade chosen!");
	var newTower = new WizardTower();
	// Position the wizard tower near the bastion line, offset from center
	newTower.x = GAME_WIDTH / 2 + 300; // Example position to the right of center
	newTower.y = BASTION_Y - 100; // Position above the bastion line
	game.addChild(newTower);
	wizardTowers.push(newTower); // Add to the wizardTowers array
}
// Helper function to add a Viking Ally
function addVikingAlly() {
	console.log("Viking Ally upgrade chosen!");
	var newViking = new VikingAlly();
	// Position the viking near the bastion line, offset from cannons/towers
	newViking.x = GAME_WIDTH / 2; // Center for now
	newViking.y = BASTION_Y - 100; // Position above the bastion line
	game.addChild(newViking);
	vikingAllies.push(newViking); // Add to the vikingAllies array
}
// Helper function to add a Dart Ally
function addDartAlly() {
	console.log("Dart Ally upgrade chosen!");
	var newDartAlly = new DartAlly();
	// Position the dart ally near the bastion line, offset
	newDartAlly.x = GAME_WIDTH / 2 - 200; // Example position
	newDartAlly.y = BASTION_Y - 100; // Position above bastion line
	game.addChild(newDartAlly);
	darts.push(newDartAlly); // Add to the dartAllies array (need to rename array to dartAllies if creating a separate one)
}
// Helper function placeholder for adding Swordsman
function addSwordsman() {
	// Create a swordsman tower at the bastion line
	var tower = new Container();
	var towerGraphics = tower.attachAsset('swordsmanTower', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	tower.x = FIRING_POS_X; // Position in the center horizontally
	tower.y = BASTION_Y - 50; // Position just above the bastion line
	game.addChild(tower);
	// Set up interval to spawn swordsmen from the tower
	var spawnInterval = LK.setInterval(function () {
		var newSwordsman = new Swordsman();
		// Position the swordsman near the tower with a slight random offset
		newSwordsman.x = tower.x + (Math.random() * 100 - 50); // Random offset of ±50px
		newSwordsman.y = tower.y;
		game.addChild(newSwordsman);
		swordsmen.push(newSwordsman); // Add to the swordsmen array
	}, 3000); // Spawn a swordsman every 3 seconds
	// Swordsman spawn does not grant score
	// Store the interval reference in the tower to potentially clear it later
	tower.spawnInterval = spawnInterval;
}
// Helper function to add an Angel of Light
function addAngelOfLight() {
	console.log("Angel of Light upgrade chosen!");
	var newAngel = new AngelOfLight();
	// Position the angel near the bastion line, offset
	newAngel.x = GAME_WIDTH / 2 + 200; // Example position
	newAngel.y = BASTION_Y - 150; // Position slightly higher than other allies
	game.addChild(newAngel);
	angelOfLights.push(newAngel); // Add to the angelOfLights array
}
// Helper function to add a Bouncy Ball
function addBouncyBall() {
	console.log("Bouncy Ball upgrade chosen!");
	var newBall = new BouncyBall();
	// Start from center of screen
	newBall.x = GAME_WIDTH / 2;
	newBall.y = GAME_HEIGHT / 2;
	game.addChild(newBall);
	bouncyBalls.push(newBall);
}
// Helper function to add a Bomber
function addBomber() {
	console.log("Bomber upgrade chosen!");
	var newBomber = new Bomber();
	// Position near bastion line
	newBomber.x = GAME_WIDTH / 2 - 400;
	newBomber.y = BASTION_Y - 100;
	game.addChild(newBomber);
	bombers.push(newBomber);
}
// Helper function to add an XBOW
function addXBOW() {
	console.log("XBOW upgrade chosen!");
	var newXBOW = new XBOW();
	// Position at the center of the bastion
	newXBOW.x = GAME_WIDTH / 2;
	newXBOW.y = BASTION_Y - 100;
	game.addChild(newXBOW);
	xbows.push(newXBOW);
}
// Helper function to enable XBOW Smart Targeting
function enableXBOWSmartTargeting() {
	console.log("XBOW Smart Targeting upgrade chosen!");
	xbowSmartTargetingEnabled = true;
	// Enable smart targeting for all existing XBOWs
	for (var i = 0; i < xbows.length; i++) {
		xbows[i].smartTargetingEnabled = true;
		// Randomly assign targeting mode for variety
		xbows[i].targetingMode = Math.random() < 0.5 ? 'closest_to_bastion' : 'strongest';
	}
}
// Define all possible upgrades
var allUpgrades = [{
	id: 'faster_reload',
	name: 'Faster Reload',
	description: 'Decrease reload time by 20%',
	apply: function apply() {
		cooldownDuration = Math.max(60, Math.floor(cooldownDuration * 0.8));
	}
},
// Min 1 sec cooldown
{
	id: 'piercing_shots',
	name: 'Piercing Shots',
	description: 'Arrows pierce +1 enemy',
	apply: function apply() {
		arrowPierceLevel++;
	}
}, {
	id: 'quiver',
	name: 'Quiver',
	description: '+5 Arrows before reload',
	apply: function apply() {
		maxArrowsBeforeCooldown += 5;
	}
}, {
	id: 'heat_tipped',
	name: 'Heat-tipped Arrows',
	description: 'Arrows deal +1 damage',
	apply: function apply() {
		arrowDamage += 1;
		console.log("Heat-tipped Arrows upgrade chosen - damage increased to " + arrowDamage);
	}
}, {
	id: 'archer_ally',
	name: 'Archer Ally',
	description: 'Gain an allied archer',
	apply: addArcherAlly
}, {
	id: 'sabotage',
	name: 'Sabotage',
	description: 'Enemies 10% slower',
	apply: function apply() {
		enemySpeedMultiplier = Math.max(0.5, enemySpeedMultiplier * 0.9);
		applySabotage();
	}
},
// Max 50% slow
{
	id: 'swordsman',
	name: 'Swordsman',
	description: 'Gain a melee defender',
	apply: addSwordsman
}, {
	id: 'more_shots',
	name: 'More Shots',
	description: 'Shoot 2 arrows at once',
	apply: function apply() {
		multiShotEnabled = true; // Assuming a global flag for this
	}
}, {
	id: 'poison_shots',
	name: 'Poison Shots',
	description: 'Shots deal damage over time',
	apply: function apply() {
		poisonShotsEnabled = true; // Assuming a global flag for this
	}
}, {
	id: 'cannon',
	name: 'Cannon',
	description: 'Gain a cannon that targets the strongest enemy',
	apply: addCannon // Assuming a helper function addCannon
}, {
	id: 'ally_atk_speed',
	name: 'Ally ATK Speed',
	description: 'All allies attack faster',
	apply: function apply() {
		allyAttackSpeedMultiplier *= 0.8; // Assuming a global multiplier
		// Apply to existing allies as well in their update logic or a helper function
	}
}, {
	id: 'wizard_tower',
	name: 'Wizard Tower',
	description: 'Gain a wizard tower ally that shoots magic balls that slowdown enemies',
	apply: addWizardTower // Assuming a helper function addWizardTower
}, {
	id: 'aimbot',
	name: 'Aimbot',
	description: 'Arrows seek out enemies',
	apply: function apply() {
		aimbotEnabled = true; // Assuming a global flag for this
	}
}, {
	id: 'green_killer',
	name: 'Green Killer',
	description: '+50% Damage vs Green Enemies',
	apply: function apply() {
		greenKillerEnabled = true;
	}
}, {
	id: 'refined_projectiles',
	name: 'Refined Projectiles',
	description: 'Non-arrow projectiles +5 damage & faster',
	apply: function apply() {
		refinedProjectilesEnabled = true;
		// Existing projectiles won't update, new ones will have bonus
	}
}, {
	id: 'viking_ally',
	name: 'Viking Ally',
	description: 'Gain a viking that throws piercing axes',
	apply: addVikingAlly // Assuming helper function addVikingAlly
}, {
	id: 'green_slowdown',
	name: 'Green Slowdown',
	description: 'Projectiles slow Green enemies 10% for 10s (no stack)',
	apply: function apply() {
		greenSlowdownEnabled = true;
	}
}, {
	id: 'dart_shooter',
	name: 'Dart Shooter',
	description: 'Gain an ally that shoots fast darts, effective against green enemies',
	apply: addDartAlly // Assuming a helper function addDartAlly
}, {
	id: 'angel_of_light',
	name: 'Angel of Light',
	description: 'Gain an ally that stuns enemies and deals high damage to dark enemies',
	apply: addAngelOfLight // Assuming a helper function addAngelOfLight
}, {
	id: 'bouncy_ball',
	name: 'Bouncy Ball',
	description: 'Bounces around dealing massive damage to enemies',
	apply: addBouncyBall
}, {
	id: 'bomber',
	name: 'Bomber',
	description: 'Throws bombs that explode for area damage',
	apply: addBomber
}, {
	id: 'xbow',
	name: 'XBOW',
	description: 'A big bow that rapidly shoots arrows',
	apply: addXBOW
}, {
	id: 'xbow_smart_targeting',
	name: 'XBOW Smart Targeting',
	description: 'XBOWs can target closest to bastion or strongest enemy',
	apply: enableXBOWSmartTargeting
}, {
	id: 'dragon_slayer_cannons',
	name: 'Dragon Slayer Cannons',
	description: 'Cannons become rocket launchers that deal 25x damage to dragons and prioritize them',
	apply: function apply() {
		// Enable dragon slayer mode for all existing cannons
		for (var i = 0; i < cannons.length; i++) {
			cannons[i].dragonSlayerMode = true;
		}
		// Set global flag so all future cannons will have dragon slayer mode
		dragonSlayerCannonsModeEnabled = true;
	}
}, {
	id: 'battle_horn',
	name: 'Battle Horn',
	description: 'More enemies spawn, but they are all swordsmen: more score for more upgrades!',
	apply: function apply() {
		// Reduce spawn interval for more enemies
		enemySpawnInterval = Math.max(15, enemySpawnInterval * 0.5); // 50% faster spawning, min 0.25 seconds
		// Set global flag to force swordsman spawns
		battleHornEnabled = true;
	}
}];
// Function to create and show the upgrade selection popup
function showUpgradePopup() {
	isUpgradePopupActive = true;
	// Simple pause: Game logic checks isUpgradePopupActive flag in game.update
	// Switch to upgrade theme music with fade effect
	if (currentMusicPlaying !== 'UpgradeTheme' && !musicFadeInProgress) {
		musicFadeInProgress = true;
		// Fade out current music
		LK.playMusic('Gamemusic', {
			fade: {
				start: 1,
				end: 0,
				duration: 800
			}
		});
		// After fade out completes, start upgrade theme with fade in
		LK.setTimeout(function () {
			LK.playMusic('UpgradeTheme', {
				fade: {
					start: 0,
					end: 1,
					duration: 1000
				}
			});
			currentMusicPlaying = 'UpgradeTheme';
			musicFadeInProgress = false;
		}, 850);
	}
	// --- Create Popup UI ---
	upgradePopup = new Container();
	upgradePopup.x = GAME_WIDTH / 2;
	upgradePopup.y = GAME_HEIGHT / 2;
	game.addChild(upgradePopup); // Add to game layer for positioning relative to center
	// Add a semi-transparent background overlay
	var bg = upgradePopup.attachAsset('bastionLine', {
		// Reusing an asset for shape
		width: 1200,
		height: 800,
		color: 0x000000,
		// Black background
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	// Add title text
	var title = new Text2('Choose an Upgrade!', {
		size: 80,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -300; // Position relative to popup center
	upgradePopup.addChild(title);
	// --- Select 3 Random Unique Upgrades ---
	var availableToOffer = allUpgrades.slice(); // Copy available upgrades
	var choices = [];
	var numChoices = Math.min(3, availableToOffer.length); // Offer up to 3 choices
	// Make dragon slayer cannons more common past score 100
	var currentScore = LK.getScore();
	if (currentScore > 100 && !dragonSlayerCannonsModeEnabled) {
		// Add dragon slayer cannons upgrade multiple times to increase chances
		var dragonSlayerUpgrade = null;
		for (var ds = 0; ds < availableToOffer.length; ds++) {
			if (availableToOffer[ds].id === 'dragon_slayer_cannons') {
				dragonSlayerUpgrade = availableToOffer[ds];
				break;
			}
		}
		if (dragonSlayerUpgrade) {
			// Add it 2 more times to the pool (3x total chance)
			availableToOffer.push(dragonSlayerUpgrade);
			availableToOffer.push(dragonSlayerUpgrade);
		}
	}
	for (var i = 0; i < numChoices; i++) {
		var randomIndex = Math.floor(Math.random() * availableToOffer.length);
		choices.push(availableToOffer[randomIndex]);
		availableToOffer.splice(randomIndex, 1); // Remove chosen upgrade to ensure uniqueness
	}
	// --- Create Buttons for Choices ---
	var buttonYStart = -150;
	var buttonSpacing = 180;
	for (var j = 0; j < choices.length; j++) {
		var upgrade = choices[j];
		var button = createUpgradeButton(upgrade, buttonYStart + j * buttonSpacing);
		upgradePopup.addChild(button);
	}
}
// Function to create a single upgrade button
function createUpgradeButton(upgradeData, yPos) {
	var buttonContainer = new Container();
	buttonContainer.y = yPos;
	// Button background
	var buttonBg = buttonContainer.attachAsset('bastionLine', {
		// Reusing asset for shape
		width: 800,
		height: 150,
		color: 0x555555,
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Button text (Name + Description)
	var nameText = new Text2(upgradeData.name, {
		size: 50,
		fill: 0xFFFFFF
	});
	nameText.anchor.set(0.5, 0.5);
	nameText.y = -25;
	buttonContainer.addChild(nameText);
	var descText = new Text2(upgradeData.description, {
		size: 35,
		fill: 0xCCCCCC
	});
	descText.anchor.set(0.5, 0.5);
	descText.y = 30;
	buttonContainer.addChild(descText);
	// Make button interactive
	buttonContainer.interactive = true; // Needed for down event
	// Event handler for button press
	buttonContainer.down = function (x, y, obj) {
		upgradeData.apply(); // Apply the selected upgrade's effect
		hideUpgradePopup(); // Close the popup
	};
	return buttonContainer;
}
// Function to hide and destroy the upgrade popup
function hideUpgradePopup() {
	if (upgradePopup) {
		upgradePopup.destroy();
		upgradePopup = null;
	}
	isUpgradePopupActive = false;
	// Switch back to game music with fade effect
	if (currentMusicPlaying !== 'Gamemusic' && !musicFadeInProgress) {
		musicFadeInProgress = true;
		// Fade out upgrade theme
		LK.playMusic('UpgradeTheme', {
			fade: {
				start: 1,
				end: 0,
				duration: 800
			}
		});
		// After fade out completes, start game music with fade in
		LK.setTimeout(function () {
			LK.playMusic('Gamemusic', {
				fade: {
					start: 0,
					end: 1,
					duration: 1000
				}
			});
			currentMusicPlaying = 'Gamemusic';
			musicFadeInProgress = false;
		}, 850);
	}
	// Resume game logic (handled by checking flag in game.update)
}
// --- Upgradepedia ---
var upgradepediaButton;
var upgradepediaPopup = null;
var upgradeListContainer = null;
function showUpgradepedia() {
	isUpgradePopupActive = true; // Pause the game while upgradepedia is open
	upgradepediaPopup = new Container();
	upgradepediaPopup.x = GAME_WIDTH / 2;
	upgradepediaPopup.y = GAME_HEIGHT / 2;
	game.addChild(upgradepediaPopup);
	// Add a semi-transparent background overlay
	var bg = upgradepediaPopup.attachAsset('pedia_screen_bg', {
		width: 1600,
		height: 2000,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.9
	});
	// Add title text
	var title = new Text2('Upgradepedia', {
		size: 100,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -900;
	upgradepediaPopup.addChild(title);
	// Add close button
	var closeButton = createUpgradepediaCloseButton();
	closeButton.x = 750;
	closeButton.y = -900;
	upgradepediaPopup.addChild(closeButton);
	// Container for upgrade details
	upgradeListContainer = new Container();
	upgradeListContainer.y = -200;
	upgradepediaPopup.addChild(upgradeListContainer);
	displayUpgradeStats();
}
function hideUpgradepedia() {
	if (upgradepediaPopup) {
		upgradepediaPopup.destroy();
		upgradepediaPopup = null;
	}
	isUpgradePopupActive = false; // Unpause the game
}
function createUpgradepediaCloseButton() {
	var buttonContainer = new Container();
	var buttonBg = buttonContainer.attachAsset('pedia_button_bg', {
		width: 150,
		height: 80,
		color: 0xCC0000,
		anchorX: 0.5,
		anchorY: 0.5
	});
	var buttonText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF
	});
	buttonText.anchor.set(0.5, 0.5);
	buttonContainer.addChild(buttonText);
	buttonContainer.interactive = true;
	buttonContainer.down = function () {
		hideUpgradepedia();
	};
	return buttonContainer;
}
function displayUpgradeStats() {
	// Clear any existing content
	while (upgradeListContainer.children.length > 0) {
		upgradeListContainer.removeChildAt(0);
	}
	// Current page tracking
	var currentUpgrade = 0;
	var totalUpgrades = allUpgrades.length;
	// Map upgrade IDs to visual assets and additional info
	var upgradeAssets = {
		'faster_reload': {
			asset: 'Reload',
			scale: 0.4
		},
		'piercing_shots': {
			asset: 'arrow',
			scale: 0.6
		},
		'quiver': {
			asset: 'arrow',
			scale: 0.8,
			tint: 0xFFD700
		},
		'heat_tipped': {
			asset: 'arrow',
			scale: 0.6,
			tint: 0xFF4500
		},
		'archer_ally': {
			asset: 'Archer',
			scale: 0.8
		},
		'sabotage': {
			asset: 'thief',
			scale: 0.8
		},
		'swordsman': {
			asset: 'swordsmanAlly',
			scale: 0.8
		},
		'more_shots': {
			asset: 'arrow',
			scale: 0.5,
			count: 3
		},
		'poison_shots': {
			asset: 'arrow',
			scale: 0.6,
			tint: 0x00FF00
		},
		'cannon': {
			asset: 'cannon_asset',
			scale: 0.8
		},
		'ally_atk_speed': {
			asset: 'viking_axe',
			scale: 0.6
		},
		'wizard_tower': {
			asset: 'wizard_tower_asset',
			scale: 0.8
		},
		'aimbot': {
			asset: 'arrow',
			scale: 0.6,
			special: 'seeking'
		},
		'green_killer': {
			asset: 'arrow',
			scale: 0.6,
			tint: 0xFF0000
		},
		'refined_projectiles': {
			asset: 'cannonball',
			scale: 0.6,
			tint: 0xFFD700
		},
		'viking_ally': {
			asset: 'viking_ally',
			scale: 0.8
		},
		'green_slowdown': {
			asset: 'magic_ball_asset',
			scale: 0.6,
			tint: 0x00FF00
		},
		'dart_shooter': {
			asset: 'dart_asset',
			scale: 0.8
		},
		'angel_of_light': {
			asset: 'angel_of_light_asset',
			scale: 0.8
		},
		'bouncy_ball': {
			asset: 'cannonball',
			scale: 1.0,
			tint: 0xFF00FF
		},
		'bomber': {
			asset: 'bomber_asset',
			scale: 0.8
		},
		'xbow': {
			asset: 'xbow_asset',
			scale: 0.8
		},
		'xbow_smart_targeting': {
			asset: 'xbow_asset',
			scale: 0.8,
			tint: 0x00FFFF
		},
		'dragon_slayer_cannons': {
			asset: 'cannon_asset',
			scale: 0.8,
			tint: 0xFF0000
		},
		'battle_horn': {
			asset: 'flag_bearer_asset',
			scale: 0.8,
			tint: 0xFFD700
		}
	};
	function displayUpgradeDetails(index) {
		// Clear existing content
		while (upgradeListContainer.children.length > 0) {
			upgradeListContainer.removeChildAt(0);
		}
		var upgradeInfo = allUpgrades[index];
		var assetInfo = upgradeAssets[upgradeInfo.id] || {
			asset: 'arrow',
			scale: 0.6
		};
		// Upgrade display container
		var upgradeDisplay = new Container();
		upgradeDisplay.y = 0;
		upgradeListContainer.addChild(upgradeDisplay);
		// Add upgrade graphic
		if (assetInfo.count) {
			// Special case for multiple projectiles
			for (var i = 0; i < assetInfo.count; i++) {
				var graphic = upgradeDisplay.attachAsset(assetInfo.asset, {
					anchorX: 0.5,
					anchorY: 0.5,
					scaleX: assetInfo.scale,
					scaleY: assetInfo.scale,
					x: -400 + (i - 1) * 100,
					y: 50
				});
				if (assetInfo.tint) {
					graphic.tint = assetInfo.tint;
				}
			}
		} else {
			var upgradeGraphic = upgradeDisplay.attachAsset(assetInfo.asset, {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: assetInfo.scale,
				scaleY: assetInfo.scale,
				x: -400,
				y: 50
			});
			if (assetInfo.tint) {
				upgradeGraphic.tint = assetInfo.tint;
			}
			// Special visual effects
			if (assetInfo.special === 'seeking') {
				// Add rotation animation hint for seeking arrows
				upgradeGraphic.rotation = Math.PI / 6;
			}
		}
		// Add upgrade name
		var nameText = new Text2(upgradeInfo.name, {
			size: 70,
			fill: 0xFFFFFF
		});
		nameText.anchor.set(0.5, 0);
		nameText.x = 0;
		nameText.y = -400;
		upgradeDisplay.addChild(nameText);
		// Add description
		var descText = new Text2(upgradeInfo.description, {
			size: 45,
			fill: 0xCCCCCC,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		descText.anchor.set(0.5, 0);
		descText.x = 0;
		descText.y = -300;
		upgradeDisplay.addChild(descText);
		// Add detailed ability description
		var abilityText = getDetailedAbility(upgradeInfo.id);
		var abilityDisplay = new Text2('Ability: ' + abilityText, {
			size: 40,
			fill: 0x88FF88,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		abilityDisplay.anchor.set(0.5, 0);
		abilityDisplay.x = 0;
		abilityDisplay.y = -150;
		upgradeDisplay.addChild(abilityDisplay);
		// Status display
		var statusText = new Text2('Upgrade ' + (index + 1) + ' of ' + totalUpgrades, {
			size: 35,
			fill: 0xAAAAAA
		});
		statusText.anchor.set(0.5, 0);
		statusText.x = 0;
		statusText.y = 250;
		upgradeDisplay.addChild(statusText);
		// Navigation buttons
		var navButtons = new Container();
		navButtons.y = 350;
		upgradeDisplay.addChild(navButtons);
		// Previous button
		var prevButton = createUpgradeNavButton('← Previous', -250, function () {
			currentUpgrade = (currentUpgrade - 1 + totalUpgrades) % totalUpgrades;
			displayUpgradeDetails(currentUpgrade);
		});
		navButtons.addChild(prevButton);
		// Next button
		var nextButton = createUpgradeNavButton('Next →', 250, function () {
			currentUpgrade = (currentUpgrade + 1) % totalUpgrades;
			displayUpgradeDetails(currentUpgrade);
		});
		navButtons.addChild(nextButton);
	}
	function getDetailedAbility(upgradeId) {
		var abilities = {
			'faster_reload': 'Reduces the cooldown time between reloads by 20%. Stacks multiplicatively with minimum 1 second cooldown.',
			'piercing_shots': 'Each arrow can pierce through one additional enemy. Stacks to pierce multiple enemies.',
			'quiver': 'Increases maximum ammo capacity by 5 arrows before needing to reload.',
			'heat_tipped': 'Increases arrow damage by 1. Affects all arrow-based attacks including allies.',
			'archer_ally': 'Spawns an allied archer that independently targets and shoots at enemies every 3 seconds.',
			'sabotage': 'Reduces all enemy movement speed by 10%. Stacks multiplicatively with minimum 50% speed.',
			'swordsman': 'Creates a tower that spawns temporary swordsmen allies every 3 seconds. Swordsmen chase and attack nearby enemies.',
			'more_shots': 'Fire 3 arrows at once in a spread pattern. Works with all arrow upgrades.',
			'poison_shots': 'Arrows apply poison stacks that deal damage over time. Each stack deals damage every 0.5 seconds.',
			'cannon': 'Deploys a cannon that targets the strongest enemy and fires high-damage cannonballs every 5 seconds.',
			'ally_atk_speed': 'All allies attack 20% faster. Stacks multiplicatively.',
			'wizard_tower': 'Builds a tower that shoots magic balls causing slowdown effect on hit. Dragons are immune to slowdown.',
			'aimbot': 'Arrows and magic balls automatically seek the nearest enemy. Updates target if current target is destroyed.',
			'green_killer': 'Deal 50% extra damage to all Green-tagged enemies (Wizards, Spearmen, War Elephants, Shamans).',
			'refined_projectiles': 'Non-arrow projectiles (cannonballs, magic balls, axes) gain +5 damage and +5 speed.',
			'viking_ally': 'Summons a viking warrior that throws piercing axes. Each axe can pierce through 3 enemies.',
			'green_slowdown': 'Projectiles slow Green-tagged enemies by 10% for 10 seconds. Effect does not stack.',
			'dart_shooter': 'Deploys a rapid-fire dart shooter that deals double damage to Green enemies.',
			'angel_of_light': 'Summons an angel that stuns enemies for 5 seconds and deals triple damage to Black-tagged enemies. Dragons cannot be stunned.',
			'bouncy_ball': 'Releases a bouncing projectile that ricochets off walls dealing massive damage. Lasts 10 seconds or 20 bounces.',
			'bomber': 'Deploys a bomber that throws area damage bombs. Cannot directly target Dragons but explosion can damage them.',
			'xbow': 'Installs a large crossbow that rapidly fires arrows every 0.33 seconds. Arrows travel 50% faster.',
			'xbow_smart_targeting': 'XBOWs can now target either the enemy closest to bastion or the strongest enemy. All other allies have this by default.',
			'dragon_slayer_cannons': 'Transforms all current and future cannons into rocket launchers. Rockets deal 25x damage to Dragon-type enemies and prioritize targeting them over all other enemy types.',
			'battle_horn': 'Doubles enemy spawn rate but forces all spawned enemies to be basic swordsmen. Great for farming score since swordsmen are easy to defeat!'
		};
		return abilities[upgradeId] || 'Special ability that enhances your defenses.';
	}
	function createUpgradeNavButton(label, xPos, callback) {
		var button = new Container();
		button.x = xPos;
		var buttonBg = button.attachAsset('pedia_nav_button_bg', {
			width: 250,
			height: 80,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 40,
			fill: 0xFFFFFF
		});
		buttonText.anchor.set(0.5, 0.5);
		button.addChild(buttonText);
		button.interactive = true;
		button.down = callback;
		return button;
	}
	// Initial display
	displayUpgradeDetails(currentUpgrade);
}
// Create upgradepedia button
upgradepediaButton = new Container();
upgradepediaButton.x = 200; // Position on the left side
upgradepediaButton.y = GAME_HEIGHT - 200;
// Add button background
var upgradeBtnBg = upgradepediaButton.attachAsset('pedia_button_bg', {
	width: 300,
	height: 100,
	anchorX: 0.5,
	anchorY: 0.5
});
// Add button text
var upgradeBtnText = new Text2('Upgradepedia', {
	size: 40,
	fill: 0xFFFFFF
});
upgradeBtnText.anchor.set(0.5, 0.5);
upgradepediaButton.addChild(upgradeBtnText);
// Make button interactive
upgradepediaButton.interactive = true;
upgradepediaButton.down = function () {
	showUpgradepedia();
};
// Add the button to the game scene
game.addChild(upgradepediaButton);
// --- Relic Shop Button ---
var relicShopButton = new Container();
relicShopButton.x = GAME_WIDTH - 200; // Position on the right side
relicShopButton.y = GAME_HEIGHT - 320; // Position above Enemypedia button
var relicBtnBg = relicShopButton.attachAsset('pedia_button_bg', {
	width: 300,
	height: 100,
	anchorX: 0.5,
	anchorY: 0.5
});
var relicBtnText = new Text2('Relic Shop', {
	size: 40,
	fill: 0xFFFFFF
});
relicBtnText.anchor.set(0.5, 0.5);
relicShopButton.addChild(relicBtnText);
relicShopButton.interactive = true;
relicShopButton.down = function () {
	showRelicShop();
};
game.addChild(relicShopButton);
// --- Visual Setup ---
var bastionLine = game.addChild(LK.getAsset('bastionLine', {
	anchorX: 0.0,
	// Anchor at the left edge.
	anchorY: 0.5,
	// Anchor vertically centered.
	x: 0,
	// Position at the left edge of the screen.
	y: BASTION_Y // Position at the defined bastion Y-coordinate.
}));
// Create and configure the score display text.
scoreTxt = new Text2('0', {
	size: 150,
	// Font size.
	fill: 0xFFFFFF // White color.
});
scoreTxt.anchor.set(0.5, 0); // Anchor at the horizontal center, top edge.
// Add score text to the GUI layer at the top-center position.
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 30; // Add padding below the top edge. Ensure it's clear of the top-left menu icon area.
// Create and configure the ammo display text.
ammoTxt = new Text2('Ammo: ' + maxArrowsBeforeCooldown, {
	size: 80,
	fill: 0xFFFFFF // White color.
});
ammoTxt.anchor.set(0.5, 0); // Anchor at the horizontal center, top edge.
LK.gui.top.addChild(ammoTxt);
ammoTxt.y = 180; // Position below the score text
// --- Enemypedia ---
var enemypediaButton;
var enemypediaPopup = null;
var enemyListContainer = null; // Container for enemy list items
function showEnemypedia() {
	isUpgradePopupActive = true; // Pause the game while enemypedia is open
	enemypediaPopup = new Container();
	enemypediaPopup.x = GAME_WIDTH / 2;
	enemypediaPopup.y = GAME_HEIGHT / 2;
	game.addChild(enemypediaPopup);
	// Add a semi-transparent background overlay
	var bg = enemypediaPopup.attachAsset('bastionLine', {
		width: 1600,
		height: 1200,
		// Increased height for better layout
		color: 0x000000,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	// Add title text
	var title = new Text2('Enemypedia', {
		size: 100,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -500; // Position relative to popup center
	enemypediaPopup.addChild(title);
	// Add a close button
	var closeButton = createCloseButton();
	closeButton.x = 750; // Position relative to popup center
	closeButton.y = -500;
	enemypediaPopup.addChild(closeButton);
	// Container for the enemy details
	enemyListContainer = new Container();
	enemyListContainer.y = -100; // Centered position for detailed view
	enemypediaPopup.addChild(enemyListContainer);
	displayEnemyStats();
}
function hideEnemypedia() {
	if (enemypediaPopup) {
		enemypediaPopup.destroy();
		enemypediaPopup = null;
	}
	isUpgradePopupActive = false; // Unpause the game
}
function createCloseButton() {
	var buttonContainer = new Container();
	var buttonBg = buttonContainer.attachAsset('bastionLine', {
		width: 150,
		height: 80,
		color: 0xCC0000,
		// Red color for close
		anchorX: 0.5,
		anchorY: 0.5
	});
	var buttonText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF
	});
	buttonText.anchor.set(0.5, 0.5);
	buttonContainer.addChild(buttonText);
	buttonContainer.interactive = true;
	buttonContainer.down = function () {
		hideEnemypedia();
	};
	return buttonContainer;
}
function displayEnemyStats() {
	// Dummy data representing enemy types and their stats
	var enemyData = [{
		type: 'swordsman',
		assetId: 'enemy',
		description: 'Basic melee unit that has very low HP.',
		baseHealth: 1,
		baseSpeed: 3,
		dodgeChance: 0
	}, {
		type: 'knight',
		assetId: 'knight',
		description: 'A threat for the first few waves cause of its high health, but is slow.',
		baseHealth: 5,
		baseSpeed: 3 * 0.9,
		dodgeChance: 0
	}, {
		type: 'thief',
		assetId: 'thief',
		description: 'Fast, low health unit with a dodge chance; likes gravy.',
		baseHealth: 1,
		baseSpeed: 3 * 1.2,
		dodgeChance: 0.1
	}, {
		type: 'boss',
		assetId: 'boss',
		description: 'a boss that spawns randomly when youre in trobule.',
		baseHealth: 5,
		// Base health before scaling
		baseSpeed: 3 * 0.7,
		dodgeChance: 0
	}, {
		type: 'shield',
		assetId: 'shield_enemy',
		description: 'Slow unit that has high HP',
		baseHealth: 20,
		baseSpeed: 3 * 0.5,
		dodgeChance: 0
	}, {
		type: 'wizard',
		assetId: 'wizard_enemy',
		description: 'kinda tricky cause it teleports and has moderate speed.',
		baseHealth: 2,
		baseSpeed: 3 * 0.7,
		dodgeChance: 0
	}, {
		type: 'spearman',
		assetId: 'spearman',
		description: 'Standard, annoying green unit that spawns from Elephants most of the time.',
		baseHealth: 2,
		baseSpeed: 3 * 1.0,
		dodgeChance: 0
	}, {
		type: 'war_elephant',
		assetId: 'war_elephant',
		description: 'Extremely high health elephant, spawns spearmen on death',
		baseHealth: 500,
		baseSpeed: 3 * 0.3,
		dodgeChance: 0
	}, {
		type: 'elite_knight',
		assetId: 'elite_knight_asset',
		description: 'High health knight variant that is loyal to the king',
		baseHealth: 45,
		baseSpeed: 3 * 0.85,
		dodgeChance: 0
	}, {
		type: 'elite_shield',
		assetId: 'elite_shield_asset',
		description: 'Even higher health shield variant that is loyal to the king',
		baseHealth: 200,
		baseSpeed: 3 * 0.4,
		dodgeChance: 0
	}, {
		type: 'shaman',
		assetId: 'shaman_enemy',
		description: 'Reduces your ammo when he feels like it',
		baseHealth: 2,
		baseSpeed: 3 * 0.8,
		dodgeChance: 0
	}, {
		type: 'hot_air_balloon',
		assetId: 'hot_air_balloon_asset',
		description: 'Very low health. Spawns random non-green enemies on death.',
		baseHealth: 1,
		baseSpeed: 3 * 0.2,
		dodgeChance: 0
	}, {
		type: 'dark_bowman',
		assetId: 'dark_bowman_asset',
		description: 'Immune to arrows and cannonballs. Worst enemy of blue archers',
		baseHealth: 5,
		baseSpeed: 3 * 1.1,
		dodgeChance: 0
	}, {
		type: 'jester',
		assetId: 'jester_asset',
		description: 'High chance to dodge or reflect non-cannonball projectiles...YOU WILL LAUGH AT ALL OF HIS TRICKS',
		baseHealth: 2,
		baseSpeed: 3 * 1.1,
		dodgeChance: 0.3,
		// 30% dodge
		reflectChance: 0.2 // 20% reflect chance for non-cannonballs
	}, {
		type: 'dark_war_elephant',
		assetId: 'dark_war_elephant_asset',
		description: 'Immune to arrows. variant of green elephant, spawns Dark Bowmen on death.',
		baseHealth: 450,
		// Slightly less than green elephant
		baseSpeed: 3 * 0.3,
		// Same slow speed
		dodgeChance: 0
	}, {
		type: 'dark_spearman',
		assetId: 'dark_spearman_asset',
		description: 'A faster and more resistant spearman variant that came straight from rome. Immune to arrows and cannonballs',
		baseHealth: 15,
		// Base health
		baseSpeed: 3 * 1.2,
		// Faster than spearman
		dodgeChance: 0,
		tag: 'Black' // Immune to arrows and cannonballs
	}, {
		type: 'dragon',
		assetId: 'dragon_asset',
		description: 'A fearsome dragon with great HP and a high chance to dodge attacks. Cant be slowed down',
		baseHealth: 250,
		// Great HP
		baseSpeed: 3 * 0.9,
		// Moderately fast
		dodgeChance: 0.40,
		// High dodge chance (40%)
		tag: 'Dragon' // Special tag if needed for other mechanics, for now dodge is key
	}, {
		type: 'flag_bearer',
		assetId: 'flag_bearer_asset',
		description: 'Green-tagged enemy with an aura that makes nearby enemies move 50% faster',
		baseHealth: 5,
		baseSpeed: 3 * 0.8,
		dodgeChance: 0,
		tag: 'Green'
	}, {
		type: 'baby_dragon',
		assetId: 'baby_dragon_asset',
		description: 'Small dragon with less health but enters rage mode (double speed) when no other dragons are present',
		baseHealth: 50,
		baseSpeed: 3 * 1.1,
		dodgeChance: 0.25,
		tag: 'Dragon'
	}];
	// Clear any existing content in the list container
	while (enemyListContainer.children.length > 0) {
		enemyListContainer.removeChildAt(0);
	}
	// Current page tracking
	var currentEnemy = 0;
	var totalEnemies = enemyData.length;
	// Create enemy details display
	function displayEnemyDetails(index) {
		// Clear any existing content in the list container
		while (enemyListContainer.children.length > 0) {
			enemyListContainer.removeChildAt(0);
		}
		var enemyInfo = enemyData[index];
		// Enemy display container
		var enemyDisplay = new Container();
		enemyDisplay.y = 0;
		enemyListContainer.addChild(enemyDisplay);
		// Add enemy graphic (larger for individual view)
		var enemyGraphic = enemyDisplay.attachAsset(enemyInfo.assetId, {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: 0.8,
			scaleY: 0.8,
			x: -400,
			y: 50
		});
		// Add enemy name (larger font)
		var nameText = new Text2(enemyInfo.type.replace(/_/g, ' ').toUpperCase(), {
			size: 60,
			fill: 0xFFFFFF
		});
		nameText.anchor.set(0.5, 0);
		nameText.x = 0;
		nameText.y = -300;
		enemyDisplay.addChild(nameText);
		// Add description
		var descText = new Text2('Description: ' + enemyInfo.description, {
			size: 40,
			fill: 0xCCCCCC,
			wordWrap: true,
			wordWrapWidth: 1000
		});
		descText.anchor.set(0, 0);
		descText.x = -100;
		descText.y = -200;
		enemyDisplay.addChild(descText);
		// Add stats with improved layout
		var healthText = new Text2('Health: ' + enemyInfo.baseHealth, {
			size: 40,
			fill: 0x88FF88
		});
		healthText.anchor.set(0, 0);
		healthText.x = -100;
		healthText.y = -100;
		enemyDisplay.addChild(healthText);
		var speedText = new Text2('Speed: ' + enemyInfo.baseSpeed.toFixed(1), {
			size: 40,
			fill: 0x88CCFF
		});
		speedText.anchor.set(0, 0);
		speedText.x = -100;
		speedText.y = -40;
		enemyDisplay.addChild(speedText);
		var dodgeText = new Text2('Dodge Chance: ' + (enemyInfo.dodgeChance * 100).toFixed(0) + '%', {
			size: 40,
			fill: 0xFFCC88
		});
		dodgeText.anchor.set(0, 0);
		dodgeText.x = -100;
		dodgeText.y = 20;
		enemyDisplay.addChild(dodgeText);
		// Add reflect chance
		var reflectText = new Text2('Reflect Chance: ' + (enemyInfo.reflectChance * 100 || 0).toFixed(0) + '%', {
			size: 40,
			fill: 0xFFCCEE
		});
		reflectText.anchor.set(0, 0);
		reflectText.x = -100;
		reflectText.y = 80;
		enemyDisplay.addChild(reflectText);
		// Add unlock score
		var unlockScore = 0; // Default for swordsman
		if (enemyInfo.type === 'spearman') {
			unlockScore = 10;
		} else if (enemyInfo.type === 'thief') {
			unlockScore = 15;
		} else if (enemyInfo.type === 'knight') {
			unlockScore = 23;
		} else if (enemyInfo.type === 'wizard') {
			unlockScore = 25;
		} else if (enemyInfo.type === 'shield') {
			unlockScore = 30;
		} else if (enemyInfo.type === 'shaman') {
			unlockScore = 35;
		} else if (enemyInfo.type === 'dark_spearman') {
			unlockScore = 55;
		} // Dark Spearman unlock score
		else if (enemyInfo.type === 'dark_bowman') {
			unlockScore = 55;
		} // Note: Same as Dark Spearman, might need adjustment if only one is desired at 55. Keeping as per request.
		else if (enemyInfo.type === 'jester') {
			unlockScore = 69;
		} else if (enemyInfo.type === 'dragon') {
			unlockScore = 134;
		} // Dragon unlock score
		else if (enemyInfo.type === 'flag_bearer') {
			unlockScore = 27;
		} // Flag Bearer unlock score
		else if (enemyInfo.type === 'baby_dragon') {
			unlockScore = 125;
		} // Baby Dragon unlock score (same as war elephant)
		else if (enemyInfo.type === 'elite_knight') {
			unlockScore = 100;
		} else if (enemyInfo.type === 'elite_shield') {
			unlockScore = 112;
		} else if (enemyInfo.type === 'war_elephant') {
			unlockScore = 125;
		} else if (enemyInfo.type === 'dark_war_elephant') {
			unlockScore = 145;
		} // Dark war elephant starts appearing at score 145
		else if (enemyInfo.type === 'hot_air_balloon') {
			unlockScore = 154;
		}
		var unlockText = new Text2('Unlocks at Score: ' + unlockScore, {
			size: 40,
			fill: 0xFF88FF
		});
		unlockText.anchor.set(0, 0);
		unlockText.x = -100;
		unlockText.y = 140; // Adjusted Y position
		enemyDisplay.addChild(unlockText);
		// Status display (current enemy / total)
		var statusText = new Text2('Enemy ' + (index + 1) + ' of ' + totalEnemies, {
			size: 30,
			fill: 0xAAAAAA
		});
		statusText.anchor.set(0.5, 0);
		statusText.x = 0;
		statusText.y = 150;
		enemyDisplay.addChild(statusText);
		// Navigation buttons container
		var navButtons = new Container();
		navButtons.y = 250;
		enemyDisplay.addChild(navButtons);
		// Previous button
		var prevButton = createNavButton('← Previous', -250, function () {
			currentEnemy = (currentEnemy - 1 + totalEnemies) % totalEnemies;
			displayEnemyDetails(currentEnemy);
		});
		navButtons.addChild(prevButton);
		// Next button
		var nextButton = createNavButton('Next →', 250, function () {
			currentEnemy = (currentEnemy + 1) % totalEnemies;
			displayEnemyDetails(currentEnemy);
		});
		navButtons.addChild(nextButton);
	}
	// Create navigation button
	function createNavButton(label, xPos, callback) {
		var button = new Container();
		button.x = xPos;
		var buttonBg = button.attachAsset('bastionLine', {
			width: 250,
			height: 80,
			color: 0x555555,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 40,
			fill: 0xFFFFFF
		});
		buttonText.anchor.set(0.5, 0.5);
		button.addChild(buttonText);
		button.interactive = true;
		button.down = callback;
		return button;
	}
	// Initial display
	displayEnemyDetails(currentEnemy);
}
enemypediaButton = new Container();
// Position the button (e.g., bottom right of GUI)
enemypediaButton.x = GAME_WIDTH - 200; // Example X
enemypediaButton.y = GAME_HEIGHT - 200; // Example Y
// Add button background
var buttonBg = enemypediaButton.attachAsset('bastionLine', {
	// Reusing asset for shape
	width: 300,
	height: 100,
	color: 0x444444,
	// Grey color
	anchorX: 0.5,
	anchorY: 0.5
});
// Add button text
var buttonText = new Text2('Enemypedia', {
	size: 40,
	fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
enemypediaButton.addChild(buttonText);
// Make button interactive
enemypediaButton.interactive = true;
enemypediaButton.down = function () {
	showEnemypedia();
};
// Add the button to the game scene (or GUI if needed)
game.addChild(enemypediaButton);
// --- Relic Shop ---
var relicShopPopup = null;
var relicListContainer = null;
var goldText; // Text display for gold
function showRelicShop() {
	isUpgradePopupActive = true; // Pause the game
	relicShopPopup = new Container();
	relicShopPopup.x = GAME_WIDTH / 2;
	relicShopPopup.y = GAME_HEIGHT / 2;
	game.addChild(relicShopPopup);
	var bg = relicShopPopup.attachAsset('pedia_screen_bg', {
		width: 1600,
		height: 2000,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.9
	});
	var title = new Text2('Relic Shop', {
		size: 100,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -900;
	relicShopPopup.addChild(title);
	var closeButton = createRelicShopCloseButton();
	closeButton.x = 750;
	closeButton.y = -900;
	relicShopPopup.addChild(closeButton);
	// Gold display
	goldText = new Text2('Gold: ' + playerGold, {
		size: 50,
		fill: 0xFFD700
	});
	goldText.anchor.set(0.5, 0.5);
	goldText.y = -800;
	relicShopPopup.addChild(goldText);
	relicListContainer = new Container();
	relicListContainer.y = -200;
	relicShopPopup.addChild(relicListContainer);
	displayRelicDetails();
}
function hideRelicShop() {
	if (relicShopPopup) {
		relicShopPopup.destroy();
		relicShopPopup = null;
	}
	isUpgradePopupActive = false; // Unpause the game
}
function createRelicShopCloseButton() {
	var buttonContainer = new Container();
	var buttonBg = buttonContainer.attachAsset('pedia_button_bg', {
		width: 150,
		height: 80,
		color: 0xCC0000,
		anchorX: 0.5,
		anchorY: 0.5
	});
	var buttonText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF
	});
	buttonText.anchor.set(0.5, 0.5);
	buttonContainer.addChild(buttonText);
	buttonContainer.interactive = true;
	buttonContainer.down = function () {
		hideRelicShop();
	};
	return buttonContainer;
}
function displayRelicDetails() {
	while (relicListContainer.children.length > 0) {
		relicListContainer.removeChildAt(0);
	}
	var relicsData = [{
		id: 'damage',
		name: 'Damage Relic',
		description: 'Increase projectile, swordsman, and poison damage.',
		effect: '+1 damage per level'
	}, {
		id: 'slowdown',
		name: 'Slowdown Relic',
		description: 'All enemies are slower.',
		effect: '+2% slowdown per level'
	}, {
		id: 'green',
		name: 'Green Relic',
		description: 'Green enemies are slower and take more damage.',
		effect: '+2% slow & +2% damage per level'
	}, {
		id: 'dark',
		name: 'Dark Relic',
		description: 'Dark enemies can be hit by arrows/cannonballs and take more damage from them.',
		effect: '+5% damage per level'
	}, {
		id: 'dragon',
		name: 'Dragon Relic',
		description: 'Projectiles stun dragons.',
		effect: '+0.05 seconds stun per level'
	}, {
		id: 'reload',
		name: 'Reload Relic',
		description: 'Reload faster! Essential for rapid-fire gameplay.',
		effect: '-0.5 seconds reload time per level'
	}, {
		id: 'ammo',
		name: 'Ammo Relic',
		description: 'Regenerate ammo over time without reloading.',
		effect: '+1 ammo regenerated every 5 seconds per level'
	}, {
		id: 'swordsman',
		name: 'Swordsman Relic',
		description: 'Start each battle with a permanent swordsman ally.',
		effect: 'Unlocks permanent swordsman, +2 damage per upgrade'
	}];
	// Current page tracking
	var currentRelic = 0;
	var totalRelics = relicsData.length;
	// Create relic details display
	function displayRelicItem(index) {
		// Clear any existing content in the list container
		while (relicListContainer.children.length > 0) {
			relicListContainer.removeChildAt(0);
		}
		var relic = relicsData[index];
		var relicInfo = playerRelics[relic.id];
		// Relic display container
		var relicDisplay = new Container();
		relicDisplay.y = 0;
		relicListContainer.addChild(relicDisplay);
		// Background
		var bg = relicDisplay.attachAsset('pedia_button_bg', {
			width: 1400,
			height: 400,
			color: 0x333355,
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Relic Name
		var nameText = new Text2(relic.name + ' (Level ' + relicInfo.level + '/' + RELIC_MAX_LEVEL + ')', {
			size: 70,
			fill: 0xFFFFFF
		});
		nameText.anchor.set(0.5, 0);
		nameText.x = 0;
		nameText.y = -300;
		relicDisplay.addChild(nameText);
		// Relic Description
		var descText = new Text2(relic.description, {
			size: 45,
			fill: 0xCCCCCC,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		descText.anchor.set(0.5, 0);
		descText.x = 0;
		descText.y = -200;
		relicDisplay.addChild(descText);
		// Relic Effect
		var effectText = new Text2('Effect: ' + relic.effect, {
			size: 40,
			fill: 0x88FF88,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		effectText.anchor.set(0.5, 0);
		effectText.x = 0;
		effectText.y = -100;
		relicDisplay.addChild(effectText);
		// Buttons container
		var buttonsContainer = new Container();
		buttonsContainer.y = 0;
		relicDisplay.addChild(buttonsContainer);
		// Buy/Upgrade Button
		var buyButton = new Container();
		buyButton.x = -200;
		var buyBtnBgColor = relicInfo.level < RELIC_MAX_LEVEL ? 0x00CC00 : 0x666666;
		var buyBtnTextColor = relicInfo.level < RELIC_MAX_LEVEL ? 0xFFFFFF : 0xAAAAAA;
		var buyBtnBg = buyButton.attachAsset('pedia_nav_button_bg', {
			width: 200,
			height: 80,
			color: buyBtnBgColor,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buyBtnText = new Text2(relicInfo.level < RELIC_MAX_LEVEL ? 'Buy (5)' : 'MAX', {
			size: 40,
			fill: buyBtnTextColor
		});
		buyBtnText.anchor.set(0.5, 0.5);
		buyButton.addChild(buyBtnText);
		buyButton.interactive = relicInfo.level < RELIC_MAX_LEVEL && playerGold >= RELIC_COST_PER_LEVEL;
		if (buyButton.interactive) {
			buyButton.down = function (relicId) {
				return function () {
					if (playerGold >= RELIC_COST_PER_LEVEL && playerRelics[relicId].level < RELIC_MAX_LEVEL) {
						playerGold -= RELIC_COST_PER_LEVEL;
						playerRelics[relicId].level++;
						storage.playerGold = playerGold;
						// Reset ammo relic timer if ammo relic was upgraded
						if (relicId === 'ammo') {
							ammoRelicTimer = 0; // Reset timer when upgrading
						}
						// Save relics to storage using safe serialization
						try {
							var relicsData = {};
							relicsData.damage_level = playerRelics.damage.level;
							relicsData.damage_enabled = playerRelics.damage.enabled;
							relicsData.slowdown_level = playerRelics.slowdown.level;
							relicsData.slowdown_enabled = playerRelics.slowdown.enabled;
							relicsData.green_level = playerRelics.green.level;
							relicsData.green_enabled = playerRelics.green.enabled;
							relicsData.dark_level = playerRelics.dark.level;
							relicsData.dark_enabled = playerRelics.dark.enabled;
							relicsData.dragon_level = playerRelics.dragon.level;
							relicsData.dragon_enabled = playerRelics.dragon.enabled;
							relicsData.reload_level = playerRelics.reload.level;
							relicsData.reload_enabled = playerRelics.reload.enabled;
							relicsData.ammo_level = playerRelics.ammo.level;
							relicsData.ammo_enabled = playerRelics.ammo.enabled;
							relicsData.swordsman_level = playerRelics.swordsman.level;
							relicsData.swordsman_enabled = playerRelics.swordsman.enabled;
							storage.playerRelicsData = relicsData;
						} catch (e) {
							console.log("Error saving relics:", e);
						}
						goldText.setText('Gold: ' + playerGold);
						displayRelicItem(currentRelic); // Refresh the current relic display
					}
				};
			}(relic.id);
		}
		buttonsContainer.addChild(buyButton);
		// On/Off Button
		var toggleButton = new Container();
		toggleButton.x = 200;
		var toggleBtnBgColor = relicInfo.enabled ? 0x008800 : 0x880000;
		var toggleBtnBg = toggleButton.attachAsset('pedia_nav_button_bg', {
			width: 150,
			height: 80,
			color: toggleBtnBgColor,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var toggleBtnText = new Text2(relicInfo.enabled ? 'ON' : 'OFF', {
			size: 40,
			fill: 0xFFFFFF
		});
		toggleBtnText.anchor.set(0.5, 0.5);
		toggleButton.addChild(toggleBtnText);
		toggleButton.interactive = relicInfo.level > 0; // Only interactive if relic is owned
		if (toggleButton.interactive) {
			toggleButton.down = function (relicId) {
				return function () {
					playerRelics[relicId].enabled = !playerRelics[relicId].enabled;
					// Reset ammo relic timer if ammo relic was toggled
					if (relicId === 'ammo') {
						ammoRelicTimer = 0; // Reset timer when toggling
					}
					// Save relics to storage using safe serialization
					try {
						var relicsData = {};
						relicsData.damage_level = playerRelics.damage.level;
						relicsData.damage_enabled = playerRelics.damage.enabled;
						relicsData.slowdown_level = playerRelics.slowdown.level;
						relicsData.slowdown_enabled = playerRelics.slowdown.enabled;
						relicsData.green_level = playerRelics.green.level;
						relicsData.green_enabled = playerRelics.green.enabled;
						relicsData.dark_level = playerRelics.dark.level;
						relicsData.dark_enabled = playerRelics.dark.enabled;
						relicsData.dragon_level = playerRelics.dragon.level;
						relicsData.dragon_enabled = playerRelics.dragon.enabled;
						relicsData.reload_level = playerRelics.reload.level;
						relicsData.reload_enabled = playerRelics.reload.enabled;
						relicsData.ammo_level = playerRelics.ammo.level;
						relicsData.ammo_enabled = playerRelics.ammo.enabled;
						relicsData.swordsman_level = playerRelics.swordsman.level;
						relicsData.swordsman_enabled = playerRelics.swordsman.enabled;
						storage.playerRelicsData = relicsData;
					} catch (e) {
						console.log("Error saving relics:", e);
					}
					displayRelicItem(currentRelic); // Refresh the current relic display
				};
			}(relic.id);
		} else {
			toggleBtnBg.tint = 0x666666; // Grey out if not owned
		}
		buttonsContainer.addChild(toggleButton);
		// Status display (current relic / total)
		var statusText = new Text2('Relic ' + (index + 1) + ' of ' + totalRelics, {
			size: 35,
			fill: 0xAAAAAA
		});
		statusText.anchor.set(0.5, 0);
		statusText.x = 0;
		statusText.y = 150;
		relicDisplay.addChild(statusText);
		// Navigation buttons container
		var navButtons = new Container();
		navButtons.y = 250;
		relicDisplay.addChild(navButtons);
		// Previous button
		var prevButton = createRelicNavButton('← Previous', -250, function () {
			currentRelic = (currentRelic - 1 + totalRelics) % totalRelics;
			displayRelicItem(currentRelic);
		});
		navButtons.addChild(prevButton);
		// Next button
		var nextButton = createRelicNavButton('Next →', 250, function () {
			currentRelic = (currentRelic + 1) % totalRelics;
			displayRelicItem(currentRelic);
		});
		navButtons.addChild(nextButton);
	}
	function createRelicNavButton(label, xPos, callback) {
		var button = new Container();
		button.x = xPos;
		var buttonBg = button.attachAsset('pedia_nav_button_bg', {
			width: 250,
			height: 80,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 40,
			fill: 0xFFFFFF
		});
		buttonText.anchor.set(0.5, 0.5);
		button.addChild(buttonText);
		button.interactive = true;
		button.down = callback;
		return button;
	}
	// Initial display
	displayRelicItem(currentRelic);
}
// --- Input Event Handlers ---
// Handles touch/mouse press down event on the game area.
game.down = function (x, y, obj) {
	// Record the starting position of the drag in game coordinates.
	var gamePos = game.toLocal({
		x: x,
		y: y
	});
	dragStartX = gamePos.x;
	dragStartY = gamePos.y;
	// Potential enhancement: Show an aiming indicator originating from FIRING_POS_X, FIRING_POS_Y towards the drag point.
};
// Handles touch/mouse move event while dragging on the game area.
game.move = function (x, y, obj) {
	// Only process if a drag is currently active.
	if (dragStartX !== null) {
		var gamePos = game.toLocal({
			x: x,
			y: y
		});
		// Potential enhancement: Update the aiming indicator based on the current drag position (gamePos).
	}
};
// Handles touch/mouse release event on the game area.
game.up = function (x, y, obj) {
	// Only process if a drag was active.
	if (dragStartX !== null && cooldownTimer <= 0) {
		// Only allow firing if not on cooldown.
		var gamePos = game.toLocal({
			x: x,
			y: y
		});
		var dragEndX = gamePos.x;
		var dragEndY = gamePos.y;
		// Calculate the difference between the firing position and the release point to determine direction.
		// A longer drag could potentially mean more power, but we'll keep it simple: direction only.
		var dx = dragEndX - FIRING_POS_X;
		var dy = dragEndY - FIRING_POS_Y;
		// Avoid division by zero or zero vector if start and end points are the same.
		if (dx === 0 && dy === 0) {
			// Optionally handle this case, e.g., fire straight up or do nothing.
			// Let's fire straight up if drag distance is negligible.
			dy = -1;
		}
		// Calculate the angle using atan2. Note the order (dx, dy) and the negation of dy
		// because the Y-axis is inverted in screen coordinates (positive Y is down).
		var angle = Math.atan2(dx, -dy);
		// Create a new arrow instance with the calculated angle.
		var newArrow = new Arrow(angle);
		newArrow.x = FIRING_POS_X;
		newArrow.y = FIRING_POS_Y;
		// Initialize last position for state tracking (e.g., off-screen detection)
		newArrow.lastY = newArrow.y;
		newArrow.lastX = newArrow.x;
		// Add the arrow to the game scene and the tracking array.
		game.addChild(newArrow);
		arrows.push(newArrow);
		if (multiShotEnabled) {
			// Fire a second arrow with a slight angle offset
			var angle2 = angle + Math.PI / 12; // Offset by 15 degrees
			var newArrow2 = new Arrow(angle2);
			newArrow2.x = FIRING_POS_X;
			newArrow2.y = FIRING_POS_Y;
			newArrow2.lastY = newArrow2.y;
			newArrow2.lastX = newArrow2.x;
			game.addChild(newArrow2);
			arrows.push(newArrow2);
			// Fire a third arrow with the opposite angle offset
			var angle3 = angle - Math.PI / 12; // Offset by -15 degrees
			var newArrow3 = new Arrow(angle3);
			newArrow3.x = FIRING_POS_X;
			newArrow3.y = FIRING_POS_Y;
			newArrow3.lastY = newArrow3.y;
			newArrow3.lastX = newArrow3.x;
			game.addChild(newArrow3);
			arrows.push(newArrow3);
		}
		LK.getSound('shoot').play(); // Play shooting sound.
		arrowsFired++; // Increment arrow count.
		ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired)); // Update ammo display.
		// Check if cooldown needs to start based on Quiver upgrade
		if (arrowsFired >= maxArrowsBeforeCooldown) {
			var effectiveCooldownDuration = cooldownDuration;
			// Apply reload relic bonus if enabled
			if (playerRelics.reload.enabled) {
				effectiveCooldownDuration = Math.max(30, cooldownDuration - playerRelics.reload.level * 30); // 0.5 seconds faster per level, min 0.5s
			}
			cooldownTimer = effectiveCooldownDuration; // Start cooldown (duration affected by Faster Reload upgrade and reload relic)
			arrowsFired = 0; // Reset arrow count.
			ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired)); // Update ammo display.
			LK.getSound('Reload').play(); // Play reload sound.
		}
		// Reset drag state.
		dragStartX = null;
		dragStartY = null;
		// Potential enhancement: Hide the aiming indicator.
	}
};
// --- Main Game Update Loop ---
// This function is called automatically by the LK engine on every frame (tick).
game.update = function () {
	// --- Upgrade System Check ---
	var currentScore = LK.getScore();
	// Check if score reached a multiple of 10 and is higher than the last upgrade score
	if (!isUpgradePopupActive && currentScore > 0 && currentScore % 10 === 0 && currentScore !== lastUpgradeScore) {
		lastUpgradeScore = currentScore; // Mark this score level as having triggered an upgrade offer
		showUpgradePopup(); // Show the upgrade selection screen
	}
	// --- Pause Game Logic if Upgrade Popup is Active ---
	if (isUpgradePopupActive) {
		// Potential: Update UI animations if any
		return; // Skip the rest of the game update loop
	}
	// --- Resume Game Logic ---
	if (isUpgradePopupActive) {
		return; // Skip enemy movement and spawning if upgrade popup is active
	}
	// Handle ammo relic regeneration
	if (playerRelics.ammo.enabled && playerRelics.ammo.level > 0) {
		ammoRelicTimer++;
		// Give ammo every 5 seconds (300 ticks)
		if (ammoRelicTimer >= 300) {
			ammoRelicTimer = 0;
			// Only regenerate if not at max ammo and not reloading
			if (arrowsFired > 0 && cooldownTimer <= 0) {
				// Give ammo based on relic level (1 per level)
				var ammoToRegenerate = playerRelics.ammo.level;
				arrowsFired = Math.max(0, arrowsFired - ammoToRegenerate);
				ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired));
			}
		}
	}
	// Decrease cooldown timer if active.
	if (cooldownTimer > 0) {
		cooldownTimer--;
		ammoTxt.setText('Reloading...'); // Show reloading status
	} else if (ammoTxt.text !== 'Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired)) {
		// Ensure ammo display is correct if not reloading
		ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired));
	}
	// 1. Update and check Arrows
	for (var i = arrows.length - 1; i >= 0; i--) {
		var arrow = arrows[i];
		// Note: LK engine calls arrow.update() automatically as it's added to the game stage.
		// Initialize last position if it hasn't been set yet (first frame).
		if (arrow.lastY === undefined) {
			arrow.lastY = arrow.y;
		}
		if (arrow.lastX === undefined) {
			arrow.lastX = arrow.x;
		}
		// Check for collisions between the current arrow and all enemies.
		var hitEnemy = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			// Use the intersects method for collision detection.
			if (arrow.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Calculate damage, applying Green Killer bonus if applicable
				var damageToDeal = arrow.damage;
				if (greenKillerEnabled && enemy.tag === 'Green') {
					damageToDeal *= 1.5; // Apply 50% damage bonus
				}
				// Apply damage to the enemy and check if it was defeated
				var enemyDefeated = enemy.takeDamage(damageToDeal, arrow); // Pass the arrow object as source
				// Check if the arrow was reflected (takeDamage returns false and arrow is destroyed)
				if (!enemyDefeated && !arrow.parent) {
					// Arrow was reflected, remove it from the array and stop processing
					arrows.splice(i, 1);
					hitEnemy = true; // Mark that this arrow is done
					break; // Stop checking this arrow against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Handle arrow piercing
				arrow.pierceLeft--; // Decrease remaining pierces
				if (arrow.pierceLeft <= 0) {
					// Arrow has no pierces left, destroy it
					arrow.destroy();
					arrows.splice(i, 1); // Remove arrow from array.
					hitEnemy = true; // Mark that this arrow is done
					break; // Stop checking this arrow against other enemies as it's destroyed
				} else {
					// Arrow pierced this enemy and can continue
					// We don't set hitEnemy = true here because the arrow continues
					// We don't break because it might hit another enemy in the same frame further along its path
					// Apply Green Slowdown if applicable and arrow is still piercing
					if (!enemyDefeated && greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
						enemy.slowTimer = 10 * 60;
						enemy.currentSlowAmount = 0.9;
					}
				}
			}
		}
		// If the arrow hit an enemy, it was destroyed, so skip to the next arrow.
		if (hitEnemy) {
			continue;
		}
		// Check if the arrow has gone off-screen (top, left, or right).
		// Use transition detection: check if it was on screen last frame and is off screen now.
		var wasOnScreen = arrow.lastY > -arrow.height / 2 && arrow.lastX > -arrow.width / 2 && arrow.lastX < GAME_WIDTH + arrow.width / 2;
		var isOffScreen = arrow.y < -arrow.height / 2 ||
		// Off top edge
		arrow.x < -arrow.width / 2 ||
		// Off left edge
		arrow.x > GAME_WIDTH + arrow.width / 2; // Off right edge
		if (wasOnScreen && isOffScreen) {
			// Arrow is off-screen, destroy it and remove from the array.
			arrow.destroy();
			arrows.splice(i, 1);
		} else if (!isOffScreen) {
			// Update last known position only if the arrow is still potentially on screen
			arrow.lastY = arrow.y;
			arrow.lastX = arrow.x;
		}
	}
	// 2. Update and check Cannonballs
	for (var cb = cannonballs.length - 1; cb >= 0; cb--) {
		var cannonball = cannonballs[cb];
		// Note: LK engine calls cannonball.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (cannonball.lastY === undefined) {
			cannonball.lastY = cannonball.y;
		}
		if (cannonball.lastX === undefined) {
			cannonball.lastX = cannonball.x;
		}
		// Check for collisions between the current cannonball and all enemies.
		var hitEnemy = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			// Use the intersects method for collision detection.
			if (cannonball.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Apply damage to the enemy and check if it was defeated
				var damageToApply = cannonball.damage;
				// Apply dragon slayer damage multiplier if applicable
				if (cannonball.dragonDamageMultiplier && enemy.tag === 'Dragon') {
					damageToApply *= cannonball.dragonDamageMultiplier;
				}
				var enemyDefeated = enemy.takeDamage(damageToApply, cannonball); // Pass cannonball as source
				// Check if the cannonball had no effect (e.g. Dark War Elephant immunity) and is still in game
				if (!enemyDefeated && cannonball.parent) {
					// Cannonball had no effect, but wasn't destroyed by a normal hit.
					// It might have been immune. If so, we still destroy the cannonball.
					cannonball.destroy();
					cannonballs.splice(cb, 1);
					hitEnemy = true; // Mark that this cannonball is done
					break; // Stop checking this cannonball against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Cannonballs are destroyed on hit
				cannonball.destroy();
				// Apply Green Slowdown if applicable before destroying cannonball
				if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
					enemy.slowTimer = 10 * 60;
					enemy.currentSlowAmount = 0.9;
				}
				cannonball.destroy();
				cannonballs.splice(cb, 1); // Remove cannonball from array.
				hitEnemy = true; // Mark that this cannonball is done
				break; // Stop checking this cannonball against other enemies as it's destroyed
			}
		}
		// If the cannonball hit an enemy, it was destroyed, so skip to the next cannonball.
		if (hitEnemy) {
			continue;
		}
		// Check if the cannonball has gone off-screen.
		var wasOnScreen = cannonball.lastY > -cannonball.height / 2 && cannonball.lastX > -cannonball.width / 2 && cannonball.lastX < GAME_WIDTH + cannonball.width / 2;
		var isOffScreen = cannonball.y < -cannonball.height / 2 ||
		// Off top edge
		cannonball.x < -cannonball.width / 2 ||
		// Off left edge
		cannonball.x > GAME_WIDTH + cannonball.width / 2; // Off right edge
		if (wasOnScreen && isOffScreen) {
			// Cannonball is off-screen, destroy it and remove from the array.
			cannonball.destroy();
			cannonballs.splice(cb, 1);
		} else if (!isOffScreen) {
			// Update last known position only if the cannonball is still potentially on screen
			cannonball.lastY = cannonball.y;
			cannonball.lastX = cannonball.x;
		}
	}
	// 3. Update and check Enemies
	for (var k = enemies.length - 1; k >= 0; k--) {
		var enemy = enemies[k];
		// Note: LK engine calls enemy.update() automatically.
		// Initialize last position if not set.
		if (enemy.lastY === undefined) {
			enemy.lastY = enemy.y;
		}
		// Check if the enemy has reached or passed the bastion line.
		// Use transition detection: was the enemy's bottom edge above the line last frame,
		// and is it on or below the line now?
		var enemyBottomY = enemy.y + enemy.height / 2;
		var enemyLastBottomY = enemy.lastY + enemy.height / 2;
		var wasAboveBastion = enemyLastBottomY < BASTION_Y;
		var isAtOrBelowBastion = enemyBottomY >= BASTION_Y;
		if (wasAboveBastion && isAtOrBelowBastion) {
			// Enemy reached the bastion! Game Over.
			LK.getSound('gameOverSfx').play(); // Play game over sound effect.
			LK.showGameOver(); // Trigger the engine's game over sequence.
			// Calculate gold earned
			var goldEarned = Math.floor(currentScore / 5);
			playerGold += goldEarned;
			storage.playerGold = playerGold; // Save gold to storage
			// Save relics to storage using safe serialization
			try {
				var relicsData = {};
				relicsData.damage_level = playerRelics.damage.level;
				relicsData.damage_enabled = playerRelics.damage.enabled;
				relicsData.slowdown_level = playerRelics.slowdown.level;
				relicsData.slowdown_enabled = playerRelics.slowdown.enabled;
				relicsData.green_level = playerRelics.green.level;
				relicsData.green_enabled = playerRelics.green.enabled;
				relicsData.dark_level = playerRelics.dark.level;
				relicsData.dark_enabled = playerRelics.dark.enabled;
				relicsData.dragon_level = playerRelics.dragon.level;
				relicsData.dragon_enabled = playerRelics.dragon.enabled;
				relicsData.reload_level = playerRelics.reload.level;
				relicsData.reload_enabled = playerRelics.reload.enabled;
				relicsData.ammo_level = playerRelics.ammo.level;
				relicsData.ammo_enabled = playerRelics.ammo.enabled;
				relicsData.swordsman_level = playerRelics.swordsman.level;
				relicsData.swordsman_enabled = playerRelics.swordsman.enabled;
				storage.playerRelicsData = relicsData;
			} catch (e) {
				console.log("Error saving relics:", e);
			}
			console.log("Game Over! Earned " + goldEarned + " gold. Total gold: " + playerGold);
			// LK.showGameOver handles game state reset, no need to manually clear arrays here.
			return; // Exit the update loop immediately as the game is over.
		} else {
			// Update last known position if game is not over for this enemy.
			enemy.lastY = enemy.y;
		}
	}
	// 3. Update and check Swordsmen (allies)
	for (var l = swordsmen.length - 1; l >= 0; l--) {
		var swordsman = swordsmen[l];
		// Swordsman update method handles its own lifetime and attacking
		// Check if the swordsman has been destroyed by its lifetime timer
		if (!swordsman.parent) {
			// If it no longer has a parent, it has been destroyed
			swordsmen.splice(l, 1); // Remove swordsman from array
		}
	}
	// 4. Update and check Cannons (allies)
	for (var m = cannons.length - 1; m >= 0; m--) {
		var cannon = cannons[m];
		// Cannons do not have a lifetime timer or destruction logic in this basic version
		// If they had, we'd check !cannon.parent and splice here as in Swordsmen
	}
	// 5. Update and check Wizard Towers (allies)
	for (var wt = wizardTowers.length - 1; wt >= 0; wt--) {
		var tower = wizardTowers[wt];
		// Wizard towers do not have a lifetime timer or destruction logic in this basic version
		// If they had, we'd check !tower.parent and splice here
	}
	// 5.5 Update and check Viking Allies
	for (var va = vikingAllies.length - 1; va >= 0; va--) {
		var viking = vikingAllies[va];
		// Vikings do not have a lifetime timer or destruction logic in this version
		// LK engine calls viking.update() automatically.
	}
	// 5.6 Update and check Angel of Lights (allies)
	for (var angelIdx = angelOfLights.length - 1; angelIdx >= 0; angelIdx--) {
		var angel = angelOfLights[angelIdx];
		// Angels do not have a lifetime timer or destruction logic in this version
		// LK engine calls angel.update() automatically.
	}
	// 5.7 Update and check Bouncy Balls
	for (var bbIdx = bouncyBalls.length - 1; bbIdx >= 0; bbIdx--) {
		var ball = bouncyBalls[bbIdx];
		// LK engine calls ball.update() automatically.
		// Check for collisions with enemies
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (ball.intersects(enemy)) {
				// Apply damage
				var enemyDefeated = enemy.takeDamage(ball.damage, ball);
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1);
					scoreTxt.setText(LK.getScore());
					enemy.destroy();
					enemies.splice(j, 1);
				}
				// Bouncy ball doesn't get destroyed on hit
				LK.effects.flashObject(enemy, 0xFF00FF, 300);
			}
		}
		// Check if ball was destroyed by lifetime
		if (!ball.parent) {
			bouncyBalls.splice(bbIdx, 1);
		}
	}
	// 5.8 Update and check Bombs
	for (var bombIdx = bombs.length - 1; bombIdx >= 0; bombIdx--) {
		var bomb = bombs[bombIdx];
		// LK engine calls bomb.update() automatically.
		// Check if bomb was destroyed after explosion
		if (!bomb.parent) {
			bombs.splice(bombIdx, 1);
		}
	}
	// 5.9 Update and check Bombers
	for (var bomberIdx = bombers.length - 1; bomberIdx >= 0; bomberIdx--) {
		var bomber = bombers[bomberIdx];
		// LK engine calls bomber.update() automatically.
	}
	// 5.10 Update and check XBOWs
	for (var xbowIdx = xbows.length - 1; xbowIdx >= 0; xbowIdx--) {
		var xbow = xbows[xbowIdx];
		// LK engine calls xbow.update() automatically.
	}
	// 6. Update and check Magic Balls
	for (var mb = magicBalls.length - 1; mb >= 0; mb--) {
		var magicBall = magicBalls[mb];
		// Note: LK engine calls magicBall.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (magicBall.lastY === undefined) {
			magicBall.lastY = magicBall.y;
		}
		if (magicBall.lastX === undefined) {
			magicBall.lastX = magicBall.x;
		}
		// Check for collisions between the current magic ball and all enemies.
		var hitEnemy = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			// Use the intersects method for collision detection.
			if (magicBall.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Apply damage (minimal) and slowdown effect to the enemy and check if it was defeated
				var enemyDefeated = enemy.takeDamage(magicBall.damage, magicBall); // Pass the magic ball object as source
				// Check if the magic ball was reflected (takeDamage returns false and magicBall is destroyed)
				if (!enemyDefeated && !magicBall.parent) {
					// Magic ball was reflected, remove it from the array and stop processing
					magicBalls.splice(mb, 1);
					hitEnemy = true; // Mark that this magic ball is done
					break; // Stop checking this magic ball against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Magic balls are destroyed on hit
				magicBall.destroy();
				// Apply Green Slowdown if applicable before destroying magic ball
				if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
					// Note: Enemy.takeDamage already checks for MagicBall source to apply its default slow.
					// This adds the Green Slowdown effect *on top* if applicable and not already slowed.
					// However, takeDamage applies slow based on MagicBall properties. Let's apply Green Slowdown here explicitly.
					enemy.slowTimer = 10 * 60; // 10 seconds
					enemy.currentSlowAmount = 0.9; // 10% slow
				}
				magicBall.destroy();
				magicBalls.splice(mb, 1); // Remove magic ball from array.
				hitEnemy = true; // Mark that this magic ball is done
				break; // Stop checking this magic ball against other enemies as it's destroyed
			}
		}
		// If the magic ball hit an enemy, it was destroyed, so skip to the next magic ball.
		if (hitEnemy) {
			continue;
		}
		// Check if the magic ball has gone off-screen.
		var wasOnScreen = magicBall.lastY > -magicBall.height / 2 && magicBall.lastX > -magicBall.width / 2 && magicBall.lastX < GAME_WIDTH + magicBall.width / 2;
		var isOffScreen = magicBall.y < -magicBall.height / 2 ||
		// Off top edge
		magicBall.x < -magicBall.width / 2 ||
		// Off left edge
		magicBall.x > GAME_WIDTH + magicBall.width / 2; // Off right edge
		if (wasOnScreen && isOffScreen) {
			// Magic ball is off-screen, destroy it and remove from the array.
			magicBall.destroy();
			magicBalls.splice(mb, 1);
		} else if (!isOffScreen) {
			// Update last known position only if the magic ball is still potentially on screen
			magicBall.lastY = magicBall.y;
			magicBall.lastX = magicBall.x;
		}
	}
	// 6.5 Update and check Viking Axes
	for (var axeIdx = vikingAxes.length - 1; axeIdx >= 0; axeIdx--) {
		var axe = vikingAxes[axeIdx];
		// Note: LK engine calls axe.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (axe.lastY === undefined) {
			axe.lastY = axe.y;
		}
		if (axe.lastX === undefined) {
			axe.lastX = axe.x;
		}
		// Check for collisions between the current axe and all enemies.
		var hitEnemyAxe = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (axe.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Apply Green Killer bonus if applicable (Vikings benefit too)
				var damageToDealAxe = axe.damage;
				if (greenKillerEnabled && enemy.tag === 'Green') {
					damageToDealAxe *= 1.5; // Apply 50% damage bonus
				}
				// Apply damage and check if defeated
				var enemyDefeated = enemy.takeDamage(damageToDealAxe, axe); // Pass axe as source for potential effects
				// Check if the axe was reflected (takeDamage returns false and axe is destroyed)
				if (!enemyDefeated && !axe.parent) {
					// Axe was reflected, remove it from the array and stop processing
					vikingAxes.splice(axeIdx, 1);
					hitEnemyAxe = true; // Mark that this axe is done
					break; // Stop checking this axe against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Handle axe piercing
				axe.pierceLeft--; // Decrease remaining pierces
				if (axe.pierceLeft <= 0) {
					// Axe has no pierces left, destroy it
					axe.destroy();
					vikingAxes.splice(axeIdx, 1); // Remove axe from array.
					hitEnemyAxe = true; // Mark that this axe is done
					break; // Stop checking this axe against other enemies
				} else {
					// Axe pierced this enemy and can continue
					// Potentially apply Green Slowdown if enabled
					if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
						enemy.slowTimer = 10 * 60;
						enemy.currentSlowAmount = 0.9;
					}
				}
			}
		}
		// If the axe hit and was destroyed, skip to the next axe.
		if (hitEnemyAxe) {
			continue;
		}
		// Check if the axe has gone off-screen.
		var wasOnScreenAxe = axe.lastY > -axe.height / 2 && axe.lastX > -axe.width / 2 && axe.lastX < GAME_WIDTH + axe.width / 2;
		var isOffScreenAxe = axe.y < -axe.height / 2 || axe.y > GAME_HEIGHT + axe.height / 2 || axe.x < -axe.width / 2 || axe.x > GAME_WIDTH + axe.width / 2;
		if (wasOnScreenAxe && isOffScreenAxe) {
			axe.destroy();
			vikingAxes.splice(axeIdx, 1);
		} else if (!isOffScreenAxe) {
			axe.lastY = axe.y;
			axe.lastX = axe.x;
		}
	}
	// 6.6 Update and check Darts
	for (var dartIdx = darts.length - 1; dartIdx >= 0; dartIdx--) {
		var dart = darts[dartIdx];
		// Note: LK engine calls dart.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (dart.lastY === undefined) {
			dart.lastY = dart.y;
		}
		if (dart.lastX === undefined) {
			dart.lastX = dart.x;
		}
		// Check for collisions between the current dart and all enemies.
		var hitEnemyDart = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (dart.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Calculate damage, applying bonus against Green enemies
				var damageToDealDart = dart.damage;
				var greenDamageMultiplier = 2; // Base multiplier for darts vs Green enemies
				// Apply Green Relic damage bonus if enabled and enemy is Green-tagged
				if (playerRelics.green.enabled && enemy.tag === 'Green') {
					greenDamageMultiplier += playerRelics.green.level * 0.02; // Additional damage multiplier from relic
				}
				if (enemy.tag === 'Green') {
					damageToDealDart *= greenDamageMultiplier; // Apply calculated multiplier
				}
				// Apply damage and check if defeated
				var enemyDefeated = enemy.takeDamage(damageToDealDart, dart); // Pass dart as source
				// Check if the dart was reflected (takeDamage returns false and dart is destroyed)
				if (!enemyDefeated && !dart.parent) {
					// Dart was reflected, remove it from the array and stop processing
					darts.splice(dartIdx, 1);
					hitEnemyDart = true; // Mark that this dart is done
					break; // Stop checking this dart against other enemies
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Darts are destroyed on hit
				dart.destroy();
				// Apply Green Slowdown if applicable before destroying dart
				if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
					enemy.slowTimer = 10 * 60;
					enemy.currentSlowAmount = 0.9;
				}
				darts.splice(dartIdx, 1); // Remove dart from array.
				hitEnemyDart = true; // Mark that this dart is done
				break; // Stop checking this dart against other enemies
			}
		}
		// If the dart hit and was destroyed, skip to the next dart.
		if (hitEnemyDart) {
			continue;
		}
		// Check if the dart has gone off-screen.
		var wasOnScreenDart = dart.lastY > -dart.height / 2 && dart.lastX > -dart.width / 2 && dart.lastX < GAME_WIDTH + dart.width / 2;
		var isOffScreenDart = dart.y < -dart.height / 2 || dart.y > GAME_HEIGHT + dart.height / 2 || dart.x < -dart.width / 2 || dart.x > GAME_WIDTH + dart.width / 2;
		if (wasOnScreenDart && isOffScreenDart) {
			dart.destroy();
			darts.splice(dartIdx, 1);
		} else if (!isOffScreenDart) {
			dart.lastY = dart.y;
			dart.lastX = dart.x;
		}
	}
	// 7. Spawn new Enemies periodically
	// Use LK.ticks and the spawn interval. Ensure interval doesn't go below minimum.
	if (LK.ticks % Math.max(minEnemySpawnInterval, Math.floor(enemySpawnInterval)) === 0) {
		var currentScore = LK.getScore();
		var baseSpeedForSpawn = Math.min(maxEnemySpeed, currentEnemySpeed); // Base speed adjusted by game difficulty progression
		// Determine if this spawn *could* be a boss (e.g., every 7th spawn after score 10)
		var potentialBoss = (enemies.length + 1) % 7 === 0 && currentScore >= 10;
		var typeToSpawn = 'swordsman'; // Default type
		var enemyHealth = 1; // Default health
		var enemyDodgeChance = 0; // Default dodge chance
		var enemySpeed = baseSpeedForSpawn; // Start with base speed
		// Determine base type based on score thresholds and randomness
		var possibleTypes = ['swordsman'];
		if (currentScore >= 10) {
			possibleTypes.push('spearman');
		}
		if (currentScore >= 15) {
			possibleTypes.push('thief');
		}
		if (currentScore >= 23) {
			possibleTypes.push('knight');
		}
		if (currentScore >= 25) {
			possibleTypes.push('wizard');
		} // Wizards start appearing at score 25
		if (currentScore >= 30) {
			possibleTypes.push('shield');
		} // Shields start appearing at score 30
		if (currentScore >= 35) {
			possibleTypes.push('shaman'); // Shaman appears at score 35
			console.log("Shaman added to possible enemy types");
		}
		if (currentScore >= 55) {
			possibleTypes.push('dark_bowman'); // Dark bowman appears at score 55
			possibleTypes.push('dark_spearman'); // Dark Spearman appears at score 55
		}
		if (currentScore >= 69) {
			possibleTypes.push('jester'); // Jester appears at score 69
		}
		if (currentScore >= 100) {
			possibleTypes.push('elite_knight'); // Elite Knights start appearing at score 100
		}
		if (currentScore >= 134) {
			possibleTypes.push('dragon'); // Dragon appears at score 134
		}
		if (currentScore >= 112) {
			possibleTypes.push('elite_shield'); // Elite Shields appear at score 112
		}
		if (currentScore >= 125) {
			// War Elephant appears at score 125
			possibleTypes.push('war_elephant');
			// Baby Dragon also appears at score 125 (same as war elephant)
			possibleTypes.push('baby_dragon');
		}
		if (currentScore >= 145) {
			possibleTypes.push('dark_war_elephant'); // Dark War Elephant appears at score 145
		}
		if (currentScore >= 154) {
			// Hot Air Balloon appears at score 100
			possibleTypes.push('hot_air_balloon');
		}
		if (currentScore >= 27) {
			possibleTypes.push('flag_bearer'); // Flag Bearer appears at score 27
		}
		// Check if Battle Horn is active - if so, make half of spawns swordsmen, rest random
		if (battleHornEnabled) {
			// 50% chance to force swordsman, 50% chance to pick random
			if (Math.random() < 0.5) {
				typeToSpawn = 'swordsman';
			} else {
				var chosenTypeIndex = Math.floor(Math.random() * possibleTypes.length);
				typeToSpawn = possibleTypes[chosenTypeIndex];
			}
		} else {
			// Randomly select a type from the available pool for this score level
			var chosenTypeIndex = Math.floor(Math.random() * possibleTypes.length);
			typeToSpawn = possibleTypes[chosenTypeIndex];
		}
		// Set stats based on chosen type and apply score-based scaling
		if (typeToSpawn === 'knight') {
			var baseKnightHP = 5;
			var hpIncreaseIntervalKnight = 30; // Health increases every 30 score points after appearing
			var hpIncreasesKnight = Math.floor(Math.max(0, currentScore - 23) / hpIncreaseIntervalKnight);
			enemyHealth = baseKnightHP + hpIncreasesKnight * 5;
			enemySpeed *= 0.9; // Knights are slightly slower than base swordsman speed
		} else if (typeToSpawn === 'thief') {
			enemyHealth = 1; // Thieves are fragile
			enemyDodgeChance = 0.10; // 10% dodge chance
			var speedIncreaseIntervalThief = 25; // Speed increases every 25 score points after appearing
			var speedIncreasePercentThief = 0.05; // 5% speed increase each time
			var speedIncreasesThief = Math.floor(Math.max(0, currentScore - 15) / speedIncreaseIntervalThief);
			var thiefSpeedMultiplier = Math.pow(1 + speedIncreasePercentThief, speedIncreasesThief);
			enemySpeed *= 1.2 * thiefSpeedMultiplier; // Thieves are faster base + scaling speed
		} else if (typeToSpawn === 'shield') {
			var baseShieldHP = 20;
			var hpIncreaseIntervalShield = 35; // Gains HP every 35 score points after appearing
			var hpIncreasesShield = Math.floor(Math.max(0, currentScore - 30) / hpIncreaseIntervalShield);
			enemyHealth = baseShieldHP + hpIncreasesShield * 20;
			enemySpeed *= 0.5; // Shield enemies are very slow
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'shaman') {
			var baseShamanHP = 2;
			var statIncreaseIntervalShaman = 10; // Gains stats every 10 score points after appearing
			var statIncreasesShaman = Math.floor(Math.max(0, currentScore - 35) / statIncreaseIntervalShaman);
			enemyHealth = baseShamanHP + statIncreasesShaman * 1; // Gains 1 HP per interval
			enemySpeed *= 0.8 * Math.pow(1.04, statIncreasesShaman); // Base speed, gains 4% speed per interval
			enemyDodgeChance = 0; // Shaman cannot dodge
		} else if (typeToSpawn === 'wizard') {
			var baseWizardHP = 2;
			var statIncreaseIntervalWizard = 10; // Gains stats every 10 score points after appearing
			var statIncreasesWizard = Math.floor(Math.max(0, currentScore - 25) / statIncreaseIntervalWizard);
			enemyHealth = baseWizardHP + statIncreasesWizard * 1; // Gains 1 HP per interval
			enemySpeed *= 0.7 * Math.pow(1.05, statIncreasesWizard); // Slow base, gains 5% speed per interval
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'elite_knight') {
			var baseEliteKnightHP = 45;
			var hpIncreaseIntervalElite = 30; // Gains HP every 30 score points after appearing
			var hpIncreasesElite = Math.floor(Math.max(0, currentScore - 100) / hpIncreaseIntervalElite);
			enemyHealth = baseEliteKnightHP + hpIncreasesElite * 15;
			enemySpeed *= 0.85; // Slightly slower than base knight speed
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'elite_shield') {
			var baseEliteShieldHP = 200; // Starts with 200 HP
			var hpIncreaseIntervalEliteShield = 20; // Gains HP every 20 score points after appearing
			var hpIncreasesEliteShield = Math.floor(Math.max(0, currentScore - 112) / hpIncreaseIntervalEliteShield);
			enemyHealth = baseEliteShieldHP + hpIncreasesEliteShield * 50; // Gains 50 HP per interval
			enemySpeed *= 0.4; // Elite Shield enemies are slower than regular shield enemies
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'spearman') {
			var baseSpearmanHP = 2;
			var hpIncreaseIntervalSpearman = 10; // Gains HP every 10 score points after appearing
			var hpIncreasesSpearman = Math.floor(Math.max(0, currentScore - 10) / hpIncreaseIntervalSpearman);
			enemyHealth = baseSpearmanHP + hpIncreasesSpearman * 3; // Gains 3 HP per interval
			var speedIncreaseIntervalSpearman = 10; // Gains speed every 10 score points after appearing
			var speedIncreasePercentSpearman = 0.05; // 5% speed increase each time
			var speedIncreasesSpearman = Math.floor(Math.max(0, currentScore - 10) / speedIncreaseIntervalSpearman);
			var spearmanSpeedMultiplier = Math.pow(1 + speedIncreasePercentSpearman, speedIncreasesSpearman);
			enemySpeed *= 1.0 * spearmanSpeedMultiplier; // Base speed + scaling speed
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'war_elephant') {
			var baseElephantHP = 500;
			var hpIncreaseIntervalElephant = 15; // Gains HP every 15 score points after appearing
			var hpIncreasesElephant = Math.floor(Math.max(0, currentScore - 125) / hpIncreaseIntervalElephant);
			enemyHealth = baseElephantHP + hpIncreasesElephant * 100; // Gains 100 HP per interval
			enemySpeed *= 0.3; // War Elephants are very slow
			enemyDodgeChance = 0;
			// Note: War elephant death spawns spearmen - this will be handled in the Enemy death logic.
		} else if (typeToSpawn === 'hot_air_balloon') {
			enemyHealth = 1; // Always has 1 HP
			enemySpeed *= 0.2; // Very slow movement
			enemyDodgeChance = 0;
			// Note: Hot air balloon death spawns 5 random non-green enemies - handled in Enemy death logic
		} else if (typeToSpawn === 'dark_bowman') {
			var baseDarkBowmanHP = 5;
			var statIncreaseIntervalBowman = 10; // Gains stats every 10 score points after appearing
			var statIncreasesBowman = Math.floor(Math.max(0, currentScore - 55) / statIncreaseIntervalBowman);
			enemyHealth = baseDarkBowmanHP + statIncreasesBowman * 3; // Gains 3 HP per interval
			var speedIncreasePercentBowman = 0.05; // 5% speed increase each time
			var bowmanSpeedMultiplier = Math.pow(1 + speedIncreasePercentBowman, statIncreasesBowman);
			enemySpeed *= 1.1 * bowmanSpeedMultiplier; // Slightly faster than base speed + scaling
			enemyDodgeChance = 0;
			// Note: Dark bowman has Black tag making it immune to arrows
		} else if (typeToSpawn === 'jester') {
			var baseJesterHP = 2;
			enemyHealth = baseJesterHP; // Jester HP doesn't scale with score
			var baseJesterSpeed = baseSpeedForSpawn * 1.1; // Jester starts faster
			var speedIncreaseIntervalJester = 12; // Gains speed every 12 score points after appearing
			var speedIncreasePercentJester = 0.03; // 3% speed increase each time
			var speedIncreasesJester = Math.floor(Math.max(0, currentScore - 69) / speedIncreaseIntervalJester);
			enemySpeed = baseJesterSpeed * Math.pow(1 + speedIncreasePercentJester, speedIncreasesJester);
			enemyDodgeChance = 0.30; // 30% dodge chance
			// The reflectChance is set in the Enemy class constructor based on type, no need to set here.
		} else if (typeToSpawn === 'dark_war_elephant') {
			var baseDarkElephantHP = 450;
			var hpIncreaseIntervalDarkElephant = 10; // Gains HP every 10 score points after appearing
			var hpIncreasesDarkElephant = Math.floor(Math.max(0, currentScore - 120) / hpIncreaseIntervalDarkElephant);
			enemyHealth = baseDarkElephantHP + hpIncreasesDarkElephant * 80; // Gains 80 HP per interval
			enemySpeed *= 0.3; // Dark War Elephants are very slow
			enemyDodgeChance = 0;
			// Note: Dark War elephant death spawns dark bowmen - this will be handled in the Enemy death logic.
		} else if (typeToSpawn === 'dark_spearman') {
			var baseDarkSpearmanHP = 15;
			var baseDarkSpearmanSpeedMultiplier = 1.2;
			var statIncreaseIntervalDarkSpearman = 10; // Gains stats every 10 score points after appearing
			var statIncreasesDarkSpearman = Math.floor(Math.max(0, currentScore - 55) / statIncreaseIntervalDarkSpearman);
			enemyHealth = baseDarkSpearmanHP + statIncreasesDarkSpearman * 5; // Gains 5 HP per interval
			var darkSpearmanSpeedBonus = Math.pow(1 + 0.03, statIncreasesDarkSpearman); // Gains 3% speed per interval
			enemySpeed *= baseDarkSpearmanSpeedMultiplier * darkSpearmanSpeedBonus;
			enemyDodgeChance = 0;
			// Tag 'Black' is set in Enemy constructor
		} else if (typeToSpawn === 'dragon') {
			var baseDragonHP = 250;
			var hpIncreaseIntervalDragon = 15; // Gains HP every 15 score points after appearing
			var hpIncreasesDragon = Math.floor(Math.max(0, currentScore - 100) / hpIncreaseIntervalDragon);
			enemyHealth = baseDragonHP + hpIncreasesDragon * 50; // Gains 50 HP per interval
			enemySpeed *= 0.9; // Dragons are moderately fast
			enemyDodgeChance = 0.40; // 40% dodge chance
			// Tag 'Dragon' could be set in Enemy constructor if needed for other mechanics
		} else if (typeToSpawn === 'flag_bearer') {
			var baseFlagBearerHP = 5;
			var hpIncreaseIntervalFlagBearer = 10; // Gains HP every 10 score points after appearing
			var hpIncreasesFlagBearer = Math.floor(Math.max(0, currentScore - 27) / hpIncreaseIntervalFlagBearer);
			enemyHealth = baseFlagBearerHP + hpIncreasesFlagBearer * 2; // Gains 2 HP per interval
			var speedIncreaseIntervalFlagBearer = 10; // Gains speed every 10 score points
			var speedIncreasesFlagBearer = Math.floor(Math.max(0, currentScore - 27) / speedIncreaseIntervalFlagBearer);
			var flagBearerSpeedMultiplier = Math.pow(1.03, speedIncreasesFlagBearer); // 3% speed increase per interval
			enemySpeed *= 0.8 * flagBearerSpeedMultiplier; // Slower base speed but increases over time
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'baby_dragon') {
			var baseBabyDragonHP = 50;
			var hpIncreaseIntervalBabyDragon = 9; // Gains HP every 9 score points after appearing
			var hpIncreasesBabyDragon = Math.floor(Math.max(0, currentScore - 125) / hpIncreaseIntervalBabyDragon);
			enemyHealth = baseBabyDragonHP + hpIncreasesBabyDragon * 10; // Gains 10 HP per interval
			var speedIncreaseIntervalBabyDragon = 9; // Gains speed every 9 score points
			var speedIncreasesBabyDragon = Math.floor(Math.max(0, currentScore - 125) / speedIncreaseIntervalBabyDragon);
			var babyDragonSpeedMultiplier = Math.pow(1.02, speedIncreasesBabyDragon); // 2% speed increase per interval
			enemySpeed *= 1.1 * babyDragonSpeedMultiplier; // Faster than regular dragon
			enemyDodgeChance = 0.25; // 25% dodge chance
		} else {
			// Swordsman (default)
			enemyHealth = 1;
			// Speed remains baseSpeedForSpawn initially
		}
		// Check if this spawn should be overridden to be a Boss
		if (potentialBoss) {
			typeToSpawn = 'boss'; // Set type to boss
			enemyHealth = 5 + Math.floor(currentScore / 8); // Boss health scales significantly with score
			enemySpeed = baseSpeedForSpawn * 0.7; // Bosses are slower but much tougher (reset speed based on base)
			enemyDodgeChance = 0; // Bosses typically don't dodge
		}
		// Apply the global Sabotage speed multiplier AFTER type-specific adjustments
		enemySpeed *= enemySpeedMultiplier;
		// Create the new enemy instance with the calculated stats
		var newEnemy;
		if (typeToSpawn === 'flag_bearer') {
			newEnemy = new FlagBearer();
			newEnemy.speed = enemySpeed;
			newEnemy.baseSpeed = enemySpeed;
			newEnemy.health = enemyHealth;
			newEnemy.maxHealth = enemyHealth;
			newEnemy.dodgeChance = enemyDodgeChance;
		} else if (typeToSpawn === 'baby_dragon') {
			newEnemy = new BabyDragon();
			newEnemy.speed = enemySpeed;
			newEnemy.baseSpeed = enemySpeed;
			newEnemy.health = enemyHealth;
			newEnemy.maxHealth = enemyHealth;
			newEnemy.dodgeChance = enemyDodgeChance;
		} else {
			newEnemy = new Enemy(typeToSpawn, enemySpeed, enemyHealth, enemyDodgeChance);
		}
		// Position the new enemy at the top, random horizontal position with padding
		// Use the actual width of the created enemy's graphic for padding calculation
		// Need to access width after creation, use a sensible default or estimate if needed before creation
		var tempAsset = LK.getAsset(newEnemy.assetId || 'enemy', {}); // Get asset dimensions (might need refinement if assetId isn't on newEnemy yet)
		var spawnPadding = (tempAsset ? tempAsset.width / 2 : 100) + 20; // Use default if asset not found easily
		newEnemy.x = spawnPadding + Math.random() * (GAME_WIDTH - 2 * spawnPadding);
		newEnemy.y = -(tempAsset ? tempAsset.height / 2 : 100); // Start just above the top edge.
		// Initialize last position for state tracking (used for bastion collision check).
		newEnemy.lastY = newEnemy.y;
		// Add the new enemy to the game scene and the tracking array.
		game.addChild(newEnemy);
		enemies.push(newEnemy);
		// Increase difficulty for the next spawn: decrease spawn interval and increase base speed.
		// These affect the *next* potential spawn's base calculations.
		enemySpawnInterval -= enemySpawnRateDecrease;
		currentEnemySpeed += enemySpeedIncrease;
	}
};
// --- Swordsman Relic Initial Setup ---
if (playerRelics.swordsman.enabled && playerRelics.swordsman.level > 0) {
	// Spawn permanent swordsman for swordsman relic
	var permanentSwordsman = new Swordsman();
	permanentSwordsman.x = FIRING_POS_X + 100; // Position near player
	permanentSwordsman.y = FIRING_POS_Y - 50;
	permanentSwordsman.lifetime = Infinity; // Permanent swordsman
	permanentSwordsman.attackDamage = 1 + (playerRelics.swordsman.level - 1) * 2; // Base damage +2 per level after first
	game.addChild(permanentSwordsman);
	swordsmen.push(permanentSwordsman);
}
// --- Initial Game Setup ---
// Set the initial score text based on the starting score (which is 0).
scoreTxt.setText(LK.getScore());
// Set the initial ammo display.
if (ammoTxt) {
	// Ensure ammoTxt is initialized
	ammoTxt.setText('Ammo: ' + maxArrowsBeforeCooldown);
}
;
// Play the background music.
// Check if we need to show a title screen first
if (!isGameStarted) {// Assuming a flag 'isGameStarted' for title screen state
	// Don't play music immediately if showing title screen
} else {
	LK.playMusic('Gamemusic');
	;
}
// Placeholder for the title screen container
var titleScreen = null;
// Flag to track game start state
var isGameStarted = false;
// Function to show the title screen
function showTitleScreen() {
	isGameStarted = false; // Ensure game is not started
	// Create the title screen container
	titleScreen = new Container();
	titleScreen.x = GAME_WIDTH / 2;
	titleScreen.y = GAME_HEIGHT / 2;
	game.addChild(titleScreen);
	// Add title text
	var titleText = new Text2('Defend Your Bastion!', {
		size: 120,
		fill: 0xFFFFFF
	});
	titleText.anchor.set(0.5, 0.5);
	titleText.y = -200;
	titleScreen.addChild(titleText);
	// Add a simple instruction text
	var instructionText = new Text2('Tap to Start', {
		size: 60,
		fill: 0xCCCCCC
	});
	instructionText.anchor.set(0.5, 0.5);
	instructionText.y = 100;
	titleScreen.addChild(instructionText);
	// Make the title screen interactive to start the game
	titleScreen.interactive = true;
	titleScreen.down = function () {
		startGame(); // Start the game when tapped
	};
	// Pause game logic while title screen is active
	isUpgradePopupActive = true; // Reusing this flag to pause game logic
}
// Function to start the game
function startGame() {
	isGameStarted = true; // Set game started flag
	isUpgradePopupActive = false; // Unpause game logic
	if (titleScreen) {
		titleScreen.destroy();
		titleScreen = null;
	}
	// Reset game state if needed (LK might handle this on game start)
	// Play game music
	LK.playMusic('Gamemusic');
}
// Initially show the title screen
showTitleScreen(); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
/** 
	* Represents an Angel of Light ally that stuns enemies and deals high damage to dark enemies.
	*/ 
var AngelOfLight = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the angel graphic asset (reusing viking_ally for simplicity)
	// Will need a dedicated asset for the Angel of Light if available.
	var graphics = self.attachAsset('angel_of_light_asset', {
		// Placeholder asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.tint = 0xFFFF00; // Yellow tint for Angel of Light
	self.attackRange = 600; // Moderate attack range
	self.attackDamage = 5; // Base damage
	self.attackInterval = 480; // Attack every 8 seconds (480 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.stunDuration = 5 * 60; // Stun duration in ticks (5 seconds)
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and using light ability.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy within range
			var closestEnemy = null;
			var closestDistance = self.attackRange;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, use light ability
			if (closestEnemy) {
				// Apply stun and damage to the target
				if (closestEnemy.tag !== 'Dragon') {
					// Dragons are immune to stuns (slowdown effect)
					closestEnemy.slowTimer = Math.max(closestEnemy.slowTimer, self.stunDuration); // Apply stun (reusing slowTimer)
					closestEnemy.currentSlowAmount = 0.0; // 100% slowdown (stun)
				}
				var damageToDeal = self.attackDamage;
				if (closestEnemy.tag === 'Black') {
					damageToDeal *= 3; // Triple damage against Black enemies
				}
				closestEnemy.takeDamage(damageToDeal, self); // Deal damage
				// Optional: Add visual/sound effect for light ability here later
				LK.effects.flashObject(closestEnemy, 0xFFFFFF, 300); // Flash white for stun/damage
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents an allied archer that shoots arrows independently.
*/ 
var ArcherAlly = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the archer graphic asset
	var graphics = self.attachAsset('Archer', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No rotation needed for 'Archer' asset as it's already upright and flipped
	self.fireTimer = 0; // Timer for shooting
	self.fireInterval = 180; // Shoot every 3 seconds (3 * 60 ticks)
	/** 
	* Update method called each game tick by the LK engine.
	* Handles firing logic.
	*/ 
	self.update = function () {
		self.fireTimer++;
		var effectiveFireInterval = Math.max(60, self.fireInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.fireTimer >= effectiveFireInterval) {
			self.fireTimer = 0; // Reset timer
			// Find the closest enemy to shoot at
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Calculate distance to the enemy
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, fire an arrow
			if (closestEnemy) {
				// Calculate angle towards the closest enemy
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				// Create a new arrow instance
				var newArrow = new Arrow(angle);
				// Apply multi-shot to allies if the upgrade is enabled for the player
				if (multiShotEnabled) {
					var angle2 = angle + Math.PI / 12; // Offset by 15 degrees
					var newArrow2 = new Arrow(angle2);
					newArrow2.x = self.x;
					newArrow2.y = self.y;
					newArrow2.lastY = newArrow2.y;
					newArrow2.lastX = newArrow2.x;
					game.addChild(newArrow2);
					arrows.push(newArrow2);
					var angle3 = angle - Math.PI / 12; // Offset by -15 degrees
					var newArrow3 = new Arrow(angle3);
					newArrow3.x = self.x;
					newArrow3.y = self.y;
					newArrow3.lastY = newArrow3.y;
					newArrow3.lastX = newArrow3.x;
					game.addChild(newArrow3);
					arrows.push(newArrow3);
				}
				newArrow.x = self.x;
				newArrow.y = self.y;
				// Ally arrows do not count towards the player's reload counter
				// The Arrow class handles piercing level based on player upgrade, but the ally doesn't benefit from player reload.
				// For simplicity, we'll let the ally benefit from player's piercing upgrade.
				newArrow.lastY = newArrow.y;
				newArrow.lastX = newArrow.x;
				// Add the arrow to the game scene and the tracking array.
				game.addChild(newArrow);
				arrows.push(newArrow); // Add to the same arrows array for collision detection
				// Ally doesn't play the 'shoot' sound
			}
		}
	};
	return self; // Return self for potential inheritance
});
// Sound when an enemy reaches the bastion
// No plugins needed for this version of the game.
/** 
* Represents an Arrow fired by the player.
* @param {number} angle - The angle in radians at which the arrow is fired.
*/ 
var Arrow = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the arrow graphic asset
	var graphics = self.attachAsset('arrow', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align arrow graphic with direction
	self.speed = 30; // Speed of the arrow in pixels per tick
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	self.pierceLeft = arrowPierceLevel; // How many more enemies this arrow can pierce
	self.damage = arrowDamage; // Damage dealt by this arrow
	self.isPoison = poisonShotsEnabled; // Flag if this arrow applies poison
	self.targetEnemy = null; // Potential target for aimbot
	self.seekSpeed = 0.1; // How quickly the arrow adjusts its direction to seek
	if (aimbotEnabled) {
		// Find the closest enemy to seek if aimbot is enabled
		var closestEnemy = null;
		var closestDistance = Infinity;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < closestDistance) {
				closestDistance = distance;
				closestEnemy = enemy;
			}
		}
		if (closestEnemy) {
			self.targetEnemy = closestEnemy;
		}
	}
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the arrow based on its velocity.
	*/ 
	self.update = function () {
		if (aimbotEnabled && self.targetEnemy && self.targetEnemy.parent) {
			// If aimbot is enabled, a target exists and is still in the game, seek it
			var targetAngle = Math.atan2(self.targetEnemy.x - self.x, -(self.targetEnemy.y - self.y));
			// Smoothly adjust the arrow's angle towards the target angle
			var angleDiff = targetAngle - (self.rotation - Math.PI / 2); // Difference considering graphic rotation
			// Normalize angle difference to be between -PI and PI
			if (angleDiff > Math.PI) {
				angleDiff -= 2 * Math.PI;
			}
			if (angleDiff < -Math.PI) {
				angleDiff += 2 * Math.PI;
			}
			// Interpolate angle
			var newAngle = self.rotation - Math.PI / 2 + angleDiff * self.seekSpeed;
			self.rotation = newAngle + Math.PI / 2;
			self.vx = Math.sin(newAngle) * self.speed;
			self.vy = -Math.cos(newAngle) * self.speed;
		} else if (aimbotEnabled && (!self.targetEnemy || !self.targetEnemy.parent)) {
			// If aimbot is enabled but current target is gone, find a new target
			self.targetEnemy = null; // Clear old target
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			if (closestEnemy) {
				self.targetEnemy = closestEnemy;
			}
		}
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Baby Dragon enemy with rage mode when no other dragons are present.
*/ 
var BabyDragon = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the baby dragon graphic asset
	var graphics = self.attachAsset('baby_dragon_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No base tint - only apply pink tint when raging
	self.type = 'baby_dragon';
	self.speed = 3; // Base speed (will be set from spawn)
	self.health = 50; // Base health (will be set from spawn)
	self.maxHealth = 50;
	self.dodgeChance = 0.25; // 25% dodge chance (less than adult dragon)
	self.tag = 'Dragon'; // Dragon-tagged enemy
	self.isRaging = false;
	self.rageSpeedMultiplier = 2.0; // Double speed when raging
	self.baseSpeed = self.speed;
	self.poisonStacks = 0;
	self.poisonTimer = 0;
	self.poisonDamagePerTick = 0.05;
	self.slowTimer = 0;
	self.currentSlowAmount = 1.0;
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the baby dragon and checks for rage mode.
	*/ 
	self.update = function () {
		// Check for rage mode (no other dragons on screen)
		var otherDragonsExist = false;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			if (enemy !== self && enemy.tag === 'Dragon') {
				otherDragonsExist = true;
				break;
			}
		}
		// Apply or remove rage mode
		if (!otherDragonsExist && !self.isRaging) {
			// Enter rage mode
			self.isRaging = true;
			self.speed = self.baseSpeed * self.rageSpeedMultiplier;
			// Apply pink tint with tween animation
			tween(graphics, {
				tint: 0xFF69B4
			}, {
				duration: 300
			}); // Pink tint when raging
			LK.effects.flashObject(self, 0xFF69B4, 500); // Flash effect with pink
		} else if (otherDragonsExist && self.isRaging) {
			// Exit rage mode
			self.isRaging = false;
			self.speed = self.baseSpeed;
			// Remove tint with tween animation
			tween(graphics, {
				tint: 0xFFFFFF
			}, {
				duration: 300
			}); // Return to normal color
		}
		// Normal movement (dragons are immune to slowdown)
		self.y += self.speed;
		// Apply poison damage
		if (self.poisonStacks > 0) {
			self.poisonTimer++;
			if (self.poisonTimer >= 30) {
				self.poisonTimer = 0;
				var poisonDmg = self.poisonStacks * self.poisonDamagePerTick * 30;
				self.health -= poisonDmg;
			}
			if (self.health <= 0 && self.parent) {
				LK.setScore(LK.getScore() + 1);
				scoreTxt.setText(LK.getScore());
				self.destroy();
				return;
			}
		}
		// Visual feedback based on health
		var healthRatio = self.maxHealth > 0 ? self.health / self.maxHealth : 0;
		graphics.alpha = 0.4 + healthRatio * 0.6;
	};
	/** 
	* Method called when the baby dragon takes damage.
	*/ 
	self.takeDamage = function (damage, source) {
		// Check for dodge
		if (self.dodgeChance > 0 && Math.random() < self.dodgeChance) {
			return false;
		}
		// Dragons are not immune to arrows/cannonballs
		self.health -= damage;
		// Apply poison if applicable
		if (source && source.isPoison) {
			self.poisonStacks++;
			self.poisonTimer = 0;
		}
		// Dragons are immune to slowdown effects
		return self.health <= 0;
	};
	return self;
});
/** 
* Represents a Bomb projectile thrown by a Bomber ally.
* @param {number} targetX - The target X coordinate.
* @param {number} targetY - The target Y coordinate.
*/ 
var Bomb = Container.expand(function (targetX, targetY) {
	var self = Container.call(this);
	// Create and attach the bomb graphic asset
	var graphics = self.attachAsset('bomb_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.targetX = targetX;
	self.targetY = targetY;
	self.startX = self.x;
	self.startY = self.y;
	self.damage = 15; // Area damage
	self.explosionRadius = 200; // Explosion radius
	self.arcHeight = 300; // Height of bomb arc
	self.flightTime = 60; // 1 second flight time
	self.flightTimer = 0;
	self.hasExploded = false;
	/** 
	* Update method called each game tick by the LK engine.
	* Handles arc movement and explosion.
	*/ 
	self.update = function () {
		if (self.hasExploded) {
			return;
		}
		self.flightTimer++;
		var progress = self.flightTimer / self.flightTime;
		if (progress >= 1) {
			// Bomb has reached target, explode
			self.explode();
			return;
		}
		// Calculate arc position
		var baseX = self.startX + (self.targetX - self.startX) * progress;
		var baseY = self.startY + (self.targetY - self.startY) * progress;
		// Add arc height (parabola)
		var arcOffset = -4 * self.arcHeight * progress * (progress - 1);
		self.x = baseX;
		self.y = baseY - arcOffset;
		// Rotate bomb as it flies
		graphics.rotation += 0.2;
	};
	self.explode = function () {
		if (self.hasExploded) {
			return;
		}
		self.hasExploded = true;
		// Create explosion visual effect
		LK.effects.flashScreen(0xFFAA00, 200); // Orange flash
		// Deal area damage to all enemies within radius
		for (var i = enemies.length - 1; i >= 0; i--) {
			var enemy = enemies[i];
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance <= self.explosionRadius) {
				// Calculate damage falloff (full damage at center, less at edges)
				var damageFalloff = 1 - distance / self.explosionRadius * 0.5;
				var damageToApply = self.damage * damageFalloff;
				var enemyDefeated = enemy.takeDamage(damageToApply, self);
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1);
					scoreTxt.setText(LK.getScore());
					enemy.destroy();
					enemies.splice(i, 1);
				}
				// Apply visual effect to hit enemies
				LK.effects.flashObject(enemy, 0xFFAA00, 300);
			}
		}
		self.destroy();
	};
	return self;
});
/** 
* Represents a Bomber ally that throws bombs for area damage.
*/ 
var Bomber = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the bomber graphic asset
	var graphics = self.attachAsset('bomber_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range like other allies
	self.attackInterval = 240; // Attack every 4 seconds
	self.attackTimer = 0;
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and throwing bombs.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier);
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0;
			// Find a suitable target (not Dragon-tagged)
			var bestTarget = null;
			var bestScore = -1;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Skip Dragon-tagged enemies
				if (enemy.tag === 'Dragon') {
					continue;
				}
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance <= self.attackRange) {
					// Prioritize groups of enemies (check nearby enemy count)
					var nearbyCount = 0;
					for (var j = 0; j < enemies.length; j++) {
						if (i !== j) {
							var ex = enemies[j].x - enemy.x;
							var ey = enemies[j].y - enemy.y;
							if (Math.sqrt(ex * ex + ey * ey) <= 200) {
								nearbyCount++;
							}
						}
					}
					var score = nearbyCount * 10 + (self.attackRange - distance) / 100;
					if (score > bestScore) {
						bestScore = score;
						bestTarget = enemy;
					}
				}
			}
			if (bestTarget) {
				// Create and throw bomb
				var bomb = new Bomb(bestTarget.x, bestTarget.y);
				bomb.startX = self.x;
				bomb.startY = self.y;
				bomb.x = self.x;
				bomb.y = self.y;
				game.addChild(bomb);
				bombs.push(bomb);
			}
		}
	};
	return self;
});
/** 
* Represents a Bouncy Ball that bounces around the screen dealing damage to enemies.
*/ 
var BouncyBall = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the bouncy ball graphic asset (reusing cannonball for now)
	var graphics = self.attachAsset('cannonball', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.5,
		scaleY: 1.5
	});
	graphics.tint = 0xFF00FF; // Magenta tint for bouncy ball
	self.speed = 15; // Base speed
	self.damage = 20; // Massive damage
	self.vx = (Math.random() - 0.5) * self.speed * 2; // Random initial horizontal velocity
	self.vy = -Math.abs((Math.random() - 0.5) * self.speed * 2); // Initial upward velocity
	self.lifetime = 600; // 10 seconds lifetime (600 ticks)
	self.lifetimeTimer = 0;
	self.bounceCount = 0; // Track number of bounces
	self.maxBounces = 20; // Maximum bounces before disappearing
	/** 
	* Update method called each game tick by the LK engine.
	* Handles movement, bouncing, and lifetime.
	*/ 
	self.update = function () {
		self.lifetimeTimer++;
		// Check lifetime
		if (self.lifetimeTimer >= self.lifetime || self.bounceCount >= self.maxBounces) {
			self.destroy();
			return;
		}
		// Move
		self.x += self.vx;
		self.y += self.vy;
		// Bounce off walls
		if (self.x <= graphics.width / 2 || self.x >= GAME_WIDTH - graphics.width / 2) {
			self.vx = -self.vx; // Reverse horizontal direction
			self.x = Math.max(graphics.width / 2, Math.min(GAME_WIDTH - graphics.width / 2, self.x));
			self.bounceCount++;
			// Flash on bounce
			LK.effects.flashObject(self, 0xFFFFFF, 200);
		}
		// Bounce off top and bottom
		if (self.y <= graphics.height / 2 || self.y >= BASTION_Y - graphics.height / 2) {
			self.vy = -self.vy; // Reverse vertical direction
			self.y = Math.max(graphics.height / 2, Math.min(BASTION_Y - graphics.height / 2, self.y));
			self.bounceCount++;
			// Flash on bounce
			LK.effects.flashObject(self, 0xFFFFFF, 200);
		}
	};
	return self;
});
/** 
	* Represents a Cannon ally that targets the strongest enemy.
	*/ 
var Cannon = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the cannon graphic asset (need to add a new asset for this)
	// Use dragon slayer cannon asset if mode is enabled, otherwise use regular cannon asset
	var assetId = self.dragonSlayerMode ? 'dragon_slayer_cannon_asset' : 'cannon_asset';
	var graphics = self.attachAsset(assetId, {
		// Use actual cannon asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = 800; // Long attack range
	self.attackDamage = 10; // High damage
	self.attackInterval = 300; // Attack every 5 seconds (300 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.rotation = 0; // For aiming visual if implemented later
	self.dragonSlayerMode = false; // Flag to indicate if this cannon is a dragon slayer cannon
	/** 
	* Update method called each game tick by the LK engine.
	* Handles attacking the strongest enemy.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			var targetEnemy = null;
			if (self.dragonSlayerMode) {
				// In dragon slayer mode, prioritize dragons
				var closestDragon = null;
				var closestDragonDistance = Infinity;
				var strongestNonDragon = null;
				var maxNonDragonHealth = -1;
				for (var i = 0; i < enemies.length; i++) {
					var enemy = enemies[i];
					if (enemy.tag === 'Dragon') {
						// Check distance for dragons
						var dx = enemy.x - self.x;
						var dy = enemy.y - self.y;
						var distance = Math.sqrt(dx * dx + dy * dy);
						if (distance < closestDragonDistance) {
							closestDragonDistance = distance;
							closestDragon = enemy;
						}
					} else {
						// Track strongest non-dragon as fallback
						if (enemy.health > maxNonDragonHealth) {
							maxNonDragonHealth = enemy.health;
							strongestNonDragon = enemy;
						}
					}
				}
				// Prioritize dragon if found, otherwise target strongest non-dragon
				targetEnemy = closestDragon || strongestNonDragon;
			} else {
				// Normal mode: find the strongest enemy (highest health)
				var maxHealth = -1;
				for (var i = 0; i < enemies.length; i++) {
					var enemy = enemies[i];
					if (enemy.health > maxHealth) {
						maxHealth = enemy.health;
						targetEnemy = enemy;
					}
				}
			}
			// If a target enemy is found within range, attack it
			if (targetEnemy) {
				// Calculate angle towards the target enemy
				var angle = Math.atan2(targetEnemy.x - self.x, -(targetEnemy.y - self.y));
				// Create a new cannonball instance, passing the dragon slayer mode status
				var newCannonball = new Cannonball(angle);
				newCannonball.dragonSlayerMode = self.dragonSlayerMode; // Pass the mode status
				// Position the cannonball at the cannon's location
				newCannonball.x = self.x;
				newCannonball.y = self.y;
				newCannonball.lastY = newCannonball.y; // Initialize lastY for state tracking
				newCannonball.lastX = newCannonball.x; // Initialize lastX for state tracking
				// If dragon slayer mode and targeting a dragon, apply damage bonus
				if (self.dragonSlayerMode && targetEnemy.tag === 'Dragon') {
					newCannonball.dragonDamageMultiplier = 25; // 25x damage to dragons
					// The Cannonball class will handle the asset and tint based on the mode.
				}
				// Add the cannonball to the game scene and the tracking array.
				game.addChild(newCannonball);
				cannonballs.push(newCannonball); // Add to the new cannonballs array
				// Optional: Add a visual/sound effect for cannon shot here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
	* Represents a Cannonball fired by a Cannon.
	* @param {number} angle - The angle in radians at which the cannonball is fired.
	*/ 
var Cannonball = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the graphic asset (rocket if dragon slayer mode, otherwise cannonball)
	var assetId = self.dragonSlayerMode ? 'rocket_asset' : 'cannonball';
	var graphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align graphic with direction
	// Apply red tint for rocket if in dragon slayer mode
	if (self.dragonSlayerMode) {
		graphics.tint = 0xFF0000; // Red tint for dragon slayer rockets
	}
	self.dragonSlayerMode = false; // Flag to indicate if this is a dragon slayer rocket
	self.dragonDamageMultiplier = 1; // Default damage multiplier
	self.speed = 20; // Base speed of the cannonball
	self.damage = 10; // Base damage dealt by this cannonball
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
		self.damage += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the cannonball based on its velocity.
	*/ 
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Dart projectile fired by a Dart Ally.
* @param {number} angle - The angle in radians at which the dart is fired.
*/ 
var Dart = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the dart graphic asset (reusing arrow for simplicity)
	// Will need a dedicated asset for the Dart if available.
	var graphics = self.attachAsset('dart_asset', {
		// Placeholder asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.tint = 0x9933CC; // Purple tint for darts
	graphics.rotation = angle + Math.PI / 2; // Align dart graphic with direction
	self.speed = 40; // Fast speed
	self.damage = 0.5; // Base damage dealt by this dart
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
		self.damage += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the dart based on its velocity.
	*/ 
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Dart Ally that shoots fast darts.
*/ 
var DartAlly = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the dart ally graphic asset (reusing archer asset for simplicity)
	// Will need a dedicated asset for the Dart Ally if available.
	var graphics = self.attachAsset('disguised_swordsman', {
		// Placeholder asset
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range
	self.attackDamage = 0.5; // Low damage per dart
	self.attackInterval = 30; // Attack every 0.5 seconds (30 ticks) - very fast
	self.attackTimer = 0; // Timer for attacks
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and shooting darts.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(10, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade, min 0.16s
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy to shoot at
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Calculate distance to the enemy
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, shoot a dart
			if (closestEnemy) {
				// Calculate angle towards the closest enemy
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				// Create a new dart instance
				var newDart = new Dart(angle);
				newDart.x = self.x;
				newDart.y = self.y;
				newDart.lastY = newDart.y;
				newDart.lastX = newDart.x;
				// Add the dart to the game scene and the tracking array.
				game.addChild(newDart);
				darts.push(newDart); // Add to the new darts array
				// Optional: Add throwing sound effect here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
	* Represents an Enemy attacker moving towards the bastion.
	* @param {string} type - The type of enemy ('swordsman', 'knight', 'thief', 'boss', 'shield', 'wizard', 'elite_knight').
* @param {number} speed - The final calculated speed of the enemy.
* @param {number} health - The initial and maximum health of the enemy.
* @param {number} dodgeChance - The chance (0 to 1) for the enemy to dodge an attack.
*/ 
var Enemy = Container.expand(function (type, speed, health, dodgeChance) {
	var self = Container.call(this);
	// Set asset based on type
	var assetId = 'enemy'; // Default swordsman asset
	if (type === 'knight') {
		assetId = 'knight';
	} else if (type === 'elite_knight') {
		assetId = 'elite_knight_asset'; // Use specific asset for elite knight
	} else if (type === 'thief') {
		assetId = 'thief';
	} else if (type === 'boss') {
		assetId = 'boss';
	} else if (type === 'shield') {
		assetId = 'shield_enemy'; // Use specific asset for shield
	} else if (type === 'wizard') {
		assetId = 'wizard_enemy'; // Use specific asset for wizard
	} else if (type === 'spearman') {
		assetId = 'spearman'; // Use specific asset for spearman
	} else if (type === 'war_elephant') {
		assetId = 'war_elephant'; // Use specific asset for war elephant
	} else if (type === 'elite_shield') {
		assetId = 'elite_shield_asset'; // Use specific asset for elite shield
	} else if (type === 'shaman') {
		assetId = 'shaman_enemy'; // Use specific asset for shaman
	} else if (type === 'hot_air_balloon') {
		assetId = 'hot_air_balloon_asset'; // Use specific asset for hot air balloon
	} else if (type === 'dark_bowman') {
		assetId = 'dark_bowman_asset'; // Use specific asset for dark bowman
	} else if (type === 'jester') {
		assetId = 'jester_asset'; // Use specific asset for jester
	} else if (type === 'dark_war_elephant') {
		assetId = 'dark_war_elephant_asset'; // Use specific asset for dark war elephant
	} else if (type === 'dark_spearman') {
		assetId = 'dark_spearman_asset'; // Use specific asset for dark spearman
	} else if (type === 'dragon') {
		assetId = 'dragon_asset'; // Use specific asset for dragon
	} else if (type === 'flag_bearer') {
		assetId = 'flag_bearer_asset'; // Use specific asset for flag bearer
	} else if (type === 'baby_dragon') {
		assetId = 'baby_dragon_asset'; // Use specific baby dragon asset
	}
	var graphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.type = type; // 'swordsman', 'knight', 'thief', 'boss', 'shield', 'wizard', 'elite_knight', 'shaman', etc.
	self.speed = speed; // Final calculated speed
	self.health = health;
	self.maxHealth = health; // Store max health for visual feedback
	self.dodgeChance = dodgeChance || 0; // Default to 0 if undefined
	self.reflectChance = type === 'jester' ? 0.20 : 0; // 20% reflect chance, added in Enemy class
	self.poisonStacks = 0; // Number of poison stacks
	self.poisonTimer = 0; // Timer for poison damage
	self.poisonDamagePerTick = 0.05; // Damage per tick per stack
	self.slowTimer = 0; // Timer for slowdown effect
	self.currentSlowAmount = 1.0; // Multiplier for current slowdown effect (1.0 means no slow)
	// Initialize shaman-specific properties
	if (type === 'shaman') {
		self.shamanTimer = 0;
	}
	// Set tag property based on type
	self.tag = null; // Default tag is null
	if (self.type === 'wizard' || self.type === 'spearman' || self.type === 'war_elephant' || self.type === 'shaman') {
		self.tag = 'Green';
	} else if (self.type === 'dark_bowman' || self.type === 'dark_war_elephant' || self.type === 'dark_spearman') {
		self.tag = 'Black'; // Black-tagged enemies are immune to arrows and cannonballs
	}
	// Wizard-specific properties
	if (self.type === 'wizard') {
		self.teleportTimer = 0;
		self.teleportInterval = 180; // 3 seconds * 60 FPS
	}
	// --- Public Methods (defined before use) ---
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the enemy downwards (or teleports for wizard) and updates visual feedback.
	*/ 
	self.update = function () {
		if (self.type === 'wizard') {
			self.teleportTimer = (self.teleportTimer || 0) + 1; // Initialize timer if needed
			if (self.teleportTimer >= self.teleportInterval) {
				self.teleportTimer = 0;
				// Teleport logic: Random X, slightly advanced Y
				var oldY = self.y;
				var teleportPadding = graphics.width / 2 + 20; // Use actual graphic width
				var newX = teleportPadding + Math.random() * (GAME_WIDTH - 2 * teleportPadding);
				// Advance Y slightly, but don't teleport past bastion
				var newY = Math.min(BASTION_Y - graphics.height, self.y + 100 + Math.random() * 100); // Advance 100-200px
				// Ensure not teleporting backwards significantly or offscreen top
				newY = Math.max(graphics.height / 2, newY);
				self.x = newX;
				self.y = newY;
				self.lastY = oldY; // Set lastY to pre-teleport position to avoid false bastion triggers
				// Add a visual effect for teleport
				LK.effects.flashObject(self, 0xAA00FF, 300); // Purple flash
			} else {
				// Move normally if not teleporting this frame
				self.y += self.speed;
			}
		} else {
			// Normal movement for other enemy types
			var effectiveSpeed = self.speed * self.currentSlowAmount;
			// Apply global slowdown relic if enabled and not a Dragon
			if (playerRelics.slowdown.enabled && self.tag !== 'Dragon') {
				effectiveSpeed *= 1 - playerRelics.slowdown.level * 0.02; // Apply global slow
			}
			// Apply Green Relic slowdown if enabled and enemy is Green-tagged and not a Dragon
			if (playerRelics.green.enabled && self.tag === 'Green' && self.tag !== 'Dragon') {
				effectiveSpeed *= 1 - playerRelics.green.level * 0.02; // Apply Green Relic slow
			}
			self.y += effectiveSpeed; // Apply slowdown to movement
		}
		// Decrease slowdown timer and reset slow amount if timer runs out
		if (self.slowTimer > 0) {
			self.slowTimer--;
			if (self.slowTimer <= 0) {
				self.currentSlowAmount = 1.0; // Reset speed multiplier when slowdown ends
				// Optional: Remove visual feedback for slowdown here later
			}
		}
		// Apply poison damage if stacks exist
		if (self.poisonStacks > 0) {
			self.poisonTimer++;
			if (self.poisonTimer >= 30) {
				// Apply poison damage every 0.5 seconds (30 ticks)
				self.poisonTimer = 0;
				var poisonDmg = self.poisonStacks * self.poisonDamagePerTick * 30; // Damage per 0.5s
				self.health -= poisonDmg;
				// Optional: Add visual feedback for poison damage here later
			}
			// Check if health dropped to zero or below due to poison
			if (self.health <= 0 && self.parent) {
				// Ensure enemy is still in the game
				// Enemy defeated by poison
				LK.setScore(LK.getScore() + 1); // Increment score.
				scoreTxt.setText(LK.getScore()); // Update score display.
				// Destroy the enemy
				self.destroy();
				// The main game update loop needs to handle removing the enemy from the `enemies` array
				return; // Stop updating this destroyed instance
			}
		}
		// Visual feedback based on health - alpha fade (applies to all types)
		var healthRatio = self.maxHealth > 0 ? self.health / self.maxHealth : 0;
		graphics.alpha = 0.4 + healthRatio * 0.6; // Fade from 1.0 down to 0.4
		// Shaman ability: reduce player ammo periodically
		if (self.type === 'shaman') {
			if (self.shamanTimer === undefined) {
				self.shamanTimer = 0;
			}
			self.shamanTimer += 1;
			var shamanAbilityInterval = 300; // 5 seconds * 60 FPS
			if (self.shamanTimer >= shamanAbilityInterval) {
				self.shamanTimer = 0;
				// Reduce player ammo, but not below 0
				arrowsFired = Math.min(maxArrowsBeforeCooldown, arrowsFired + 1); // Make it require one more shot for reload
				ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired));
				// Optional: Add a visual/sound effect for shaman ability
			}
		}
	}; //{N} // Adjusted line identifier
	/** 
	* Method called when the enemy is hit by an arrow.
	* Handles dodging and health reduction.
	* @param {number} damage - The amount of damage the arrow deals.
	* @returns {boolean} - True if the enemy is defeated, false otherwise.
	*/ 
	self.takeDamage = function (damage) {
		var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
		// Add source parameter, default to null
		// Check for dodge first (only if dodgeChance is positive)
		if (self.dodgeChance > 0 && Math.random() < self.dodgeChance) {
			// Optional: Add a visual effect for dodge here later
			// console.log(self.type + " dodged!");
			return false; // Dodged, so not defeated by this hit
		}
		// Check for reflection (only for Jester and non-cannonball projectiles)
		if (self.type === 'jester' && self.reflectChance > 0 && Math.random() < self.reflectChance && !(source instanceof Cannonball)) {
			// Optional: Add a visual effect for reflection here later
			// console.log(self.type + " reflected!");
			// Projectile is destroyed, enemy takes no damage
			if (source && source.destroy) {
				source.destroy();
				// Need to remove from the source array in the main game loop
			}
			return false; // Reflected, so not defeated by this hit
		}
		// Check if enemy is Black-tagged and source is an Arrow or Cannonball
		if (self.tag === 'Black' && (source instanceof Arrow || source instanceof Cannonball)) {
			// Black-tagged enemies are immune to arrow and cannonball projectiles
			// Unless Dark Relic is enabled
			if (!playerRelics.dark.enabled) {
				return false; // Not defeated, projectile has no effect
			}
		}
		var finalDamage = damage;
		// Apply damage relic bonus if enabled
		if (playerRelics.damage.enabled) {
			finalDamage += playerRelics.damage.level;
		}
		// Apply Green Relic damage bonus if enabled and enemy is Green-tagged
		if (playerRelics.green.enabled && self.tag === 'Green') {
			finalDamage *= 1 + playerRelics.green.level * 0.2;
		}
		// Apply Dark Relic damage bonus if enabled and enemy is Black-tagged
		if (playerRelics.dark.enabled && self.tag === 'Black' && (source instanceof Arrow || source instanceof Cannonball)) {
			finalDamage *= 1 + playerRelics.dark.level * 0.05;
		}
		self.health -= finalDamage;
		// Check if the damage source was a poison arrow and apply poison stacks
		if (source && source.isPoison) {
			// Use the 'source' parameter
			self.poisonStacks++; // Increase poison stacks
			self.poisonTimer = 0; // Reset timer to apply damage immediately
		}
		// Check if the damage source was a Magic Ball and apply slowdown
		if (source && source instanceof MagicBall) {
			if (self.tag !== 'Dragon') {
				// Dragons are immune to slowdowns
				self.slowTimer = source.slowDuration; // Apply slowdown duration
				self.currentSlowAmount = source.slowAmount; // Apply slowdown amount
				// Optional: Add visual feedback for slowdown here later
			}
		}
		// Check if the damage source was an Arrow and apply Dragon relic stun
		if (playerRelics.dragon.enabled && source instanceof Arrow && self.tag === 'Dragon') {
			// Apply stun (reusing slowTimer for duration, 0.0 for 100% slow)
			var stunDuration = 0.25 * 60 + playerRelics.dragon.level * 0.05 * 60; // Base 0.25s + 0.05s per level
			self.slowTimer = Math.max(self.slowTimer, stunDuration);
			self.currentSlowAmount = 0.0; // 100% slow (stun)
		}
		// Check if the damage source should apply Green Slowdown
		if (greenSlowdownEnabled && self.tag === 'Green' && self.slowTimer <= 0 && self.tag !== 'Dragon') {
			// Dragons are immune to slowdowns
			// Apply Green Slowdown only if the upgrade is active, enemy is Green, not already slowed, and not a Dragon
			self.slowTimer = 10 * 60; // 10 seconds * 60 ticks/sec
			self.currentSlowAmount = 0.9; // 10% slowdown
			// Optional: Add visual feedback for green slowdown
		}
		// Check if enemy was defeated by this damage
		var defeated = self.health <= 0;
		if (defeated && self.type === 'war_elephant') {
			// If War Elephant is defeated, spawn 5 spearmen
			for (var i = 0; i < 5; i++) {
				var spawnPadding = 100; // Padding from edge
				var spawnX = self.x + (Math.random() * 200 - 100); // Spawn around elephant's x
				var spawnY = self.y + (Math.random() * 100 - 50); // Spawn around elephant's y, slightly forward
				// Ensure spawns are within game bounds
				spawnX = Math.max(spawnPadding, Math.min(GAME_WIDTH - spawnPadding, spawnX));
				spawnY = Math.max(spawnPadding, Math.min(BASTION_Y - 50, spawnY)); // Don't spawn too close to bastion
				var newSpearman = new Enemy('spearman', currentEnemySpeed * enemySpeedMultiplier, 2, 0); // Base spearman stats
				newSpearman.x = spawnX;
				newSpearman.y = spawnY;
				newSpearman.lastY = newSpearman.y;
				game.addChild(newSpearman);
				enemies.push(newSpearman);
			}
		} else if (defeated && self.type === 'dark_war_elephant') {
			// If Dark War Elephant is defeated, spawn 5 Dark Bowmen
			for (var i = 0; i < 5; i++) {
				var spawnPadding = 100; // Padding from edge
				var spawnX = self.x + (Math.random() * 200 - 100); // Spawn around elephant's x
				var spawnY = self.y + (Math.random() * 100 - 50); // Spawn around elephant's y, slightly forward
				// Ensure spawns are within game bounds
				spawnX = Math.max(spawnPadding, Math.min(GAME_WIDTH - spawnPadding, spawnX));
				spawnY = Math.max(spawnPadding, Math.min(BASTION_Y - 50, spawnY)); // Don't spawn too close to bastion
				var newDarkBowman = new Enemy('dark_bowman', currentEnemySpeed * enemySpeedMultiplier, 5, 0); // Base dark bowman stats
				newDarkBowman.x = spawnX;
				newDarkBowman.y = spawnY;
				newDarkBowman.lastY = newDarkBowman.y;
				game.addChild(newDarkBowman);
				enemies.push(newDarkBowman);
			}
		} else if (defeated && self.type === 'hot_air_balloon') {
			// If Hot Air Balloon is defeated, spawn 5 random non-green enemies
			var possibleTypes = ['swordsman', 'knight', 'thief', 'shield', 'elite_knight', 'elite_shield', 'dark_bowman'];
			for (var i = 0; i < 5; i++) {
				// Choose random enemy type that is not green-tagged
				var randomType = possibleTypes[Math.floor(Math.random() * possibleTypes.length)];
				var randomHP = 1 + Math.floor(Math.random() * 5); // Random HP between 1-5
				var randomSpeed = currentEnemySpeed * 0.7 * enemySpeedMultiplier; // Slower than average
				var newEnemy = new Enemy(randomType, randomSpeed, randomHP, 0);
				// Spawn in a staggered pattern below the balloon
				var spawnPadding = 100;
				var spawnX = self.x + (Math.random() * 300 - 150); // Wider spread than elephant
				var spawnY = self.y + Math.random() * 200; // Always below the balloon
				// Ensure spawns are within game bounds
				spawnX = Math.max(spawnPadding, Math.min(GAME_WIDTH - spawnPadding, spawnX));
				spawnY = Math.min(BASTION_Y - 50, spawnY); // Don't spawn too close to bastion
				newEnemy.x = spawnX;
				newEnemy.y = spawnY;
				newEnemy.lastY = newEnemy.y;
				game.addChild(newEnemy);
				enemies.push(newEnemy);
			}
		}
		// No need to update alpha here, self.update handles it
		return defeated; // Return true if health is 0 or less
	}; //{O} // Adjusted line identifier
	// --- Initialization ---
	// Apply visual distinctions based on type
	graphics.tint = 0xFFFFFF; // Reset tint
	graphics.scale.set(1.0); // Reset scale
	if (self.type === 'knight') {
		graphics.tint = 0xCCCCCC; // Grey tint for Knights
		graphics.scale.set(1.1);
	} else if (self.type === 'elite_knight') {
		graphics.tint = 0xFFD700; // Gold tint for Elite Knights
		graphics.scale.set(1.2); // Slightly larger than normal knight
	} else if (self.type === 'thief') {
		graphics.tint = 0xCCFFCC; // Pale Green tint for Thieves
		graphics.scale.set(0.9);
	} else if (self.type === 'boss') {
		graphics.tint = 0xFFCCCC; // Pale Red tint for Bosses
		graphics.scale.set(1.4); // Make bosses quite large
	} else if (self.type === 'shield') {
		graphics.tint = 0xADD8E6; // Light Blue tint for Shield
		graphics.scale.set(1.2); // Make shield enemies bulky
	} else if (self.type === 'wizard') {
		graphics.tint = 0xE0B0FF; // Light Purple tint for Wizard
		graphics.scale.set(1.0);
	} else if (self.type === 'elite_shield') {
		graphics.tint = 0x8A2BE2; // Blue Violet tint for Elite Shield
		graphics.scale.set(1.3); // Slightly larger than normal shield
	} else if (self.type === 'jester') {
		graphics.tint = 0xFFB6C1; // Light Pink tint for Jester
		graphics.scale.set(1.0);
	} else if (self.type === 'dark_war_elephant') {
		graphics.tint = 0x333333; // Dark Grey tint for Dark War Elephant
		graphics.scale.set(1.4); // Same size as regular elephant
	} else if (self.type === 'dark_spearman') {
		graphics.scale.set(1.05); // Slightly larger than regular spearman
	} else if (self.type === 'dragon') {
		graphics.scale.set(1.6); // Dragons are large
	} //{11} // Modified original line identifier location
	return self; // Return self for potential inheritance
});
/** 
	* Represents a Flag Bearer enemy that provides a speed boost aura to nearby enemies.
	*/ 
var FlagBearer = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the flag bearer graphic asset
	var graphics = self.attachAsset('flag_bearer_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No tint applied to flag bearer
	self.type = 'flag_bearer';
	self.speed = 3; // Base speed (will be set from spawn)
	self.health = 5; // Base health (will be set from spawn)
	self.maxHealth = 5;
	self.dodgeChance = 0;
	self.tag = 'Green'; // Green-tagged enemy
	self.auraRadius = 300; // Radius of speed boost aura
	self.auraBoost = 1.5; // 50% speed boost to enemies in aura
	self.poisonStacks = 0;
	self.poisonTimer = 0;
	self.poisonDamagePerTick = 0.05;
	self.slowTimer = 0;
	self.currentSlowAmount = 1.0;
	// Create aura visual effect
	self.auraCircle = self.attachAsset('light_effect_asset', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.auraRadius * 2,
		height: self.auraRadius * 2,
		tint: 0x00FF00,
		alpha: 0.2
	});
	// Position aura behind the flag bearer
	self.setChildIndex(self.auraCircle, 0);
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the flag bearer and applies aura effects.
	*/ 
	self.update = function () {
		// Normal movement
		self.y += self.speed * self.currentSlowAmount;
		// Apply aura effect to nearby enemies
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			if (enemy === self) {
				continue;
			} // Skip self
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance <= self.auraRadius) {
				// Enemy is within aura range
				if (!enemy.hasAuraBoost) {
					enemy.hasAuraBoost = true;
					enemy.baseSpeed = enemy.speed;
					enemy.speed = enemy.baseSpeed * self.auraBoost;
				}
			} else if (enemy.hasAuraBoost) {
				// Enemy left aura range
				enemy.hasAuraBoost = false;
				enemy.speed = enemy.baseSpeed || enemy.speed;
			}
		}
		// Handle slowdown timer
		if (self.slowTimer > 0) {
			self.slowTimer--;
			if (self.slowTimer <= 0) {
				self.currentSlowAmount = 1.0;
			}
		}
		// Apply poison damage
		if (self.poisonStacks > 0) {
			self.poisonTimer++;
			if (self.poisonTimer >= 30) {
				self.poisonTimer = 0;
				var poisonDmg = self.poisonStacks * self.poisonDamagePerTick * 30;
				self.health -= poisonDmg;
			}
			if (self.health <= 0 && self.parent) {
				LK.setScore(LK.getScore() + 1);
				scoreTxt.setText(LK.getScore());
				self.destroy();
				return;
			}
		}
		// Visual feedback based on health
		var healthRatio = self.maxHealth > 0 ? self.health / self.maxHealth : 0;
		graphics.alpha = 0.4 + healthRatio * 0.6;
		// Update aura visual effect
		if (self.auraCircle) {
			self.auraCircle.x = self.x;
			self.auraCircle.y = self.y;
			// Pulse effect
			self.auraPulseTimer = (self.auraPulseTimer || 0) + 0.05;
			var pulseScale = 1.0 + Math.sin(self.auraPulseTimer) * 0.1;
			self.auraCircle.scale.set(pulseScale);
			self.auraCircle.alpha = 0.15 + Math.sin(self.auraPulseTimer * 2) * 0.05;
		}
	};
	/** 
	* Method called when the flag bearer takes damage.
	*/ 
	self.takeDamage = function (damage, source) {
		// Check for dodge
		if (self.dodgeChance > 0 && Math.random() < self.dodgeChance) {
			return false;
		}
		// Check if source is Arrow or Cannonball (Green enemies are not immune)
		self.health -= damage;
		// Apply poison if applicable
		if (source && source.isPoison) {
			self.poisonStacks++;
			self.poisonTimer = 0;
		}
		// Apply slowdown from Magic Ball
		if (source && source instanceof MagicBall) {
			self.slowTimer = source.slowDuration;
			self.currentSlowAmount = source.slowAmount;
		}
		// Apply Green Slowdown
		if (greenSlowdownEnabled && self.tag === 'Green' && self.slowTimer <= 0) {
			self.slowTimer = 10 * 60;
			self.currentSlowAmount = 0.9;
		}
		return self.health <= 0;
	};
	// Clean up aura effects when destroyed
	var originalDestroy = self.destroy;
	self.destroy = function () {
		// Remove aura effects from all enemies
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			if (enemy.hasAuraBoost) {
				enemy.hasAuraBoost = false;
				enemy.speed = enemy.baseSpeed || enemy.speed;
			}
		}
		// Clean up aura visual
		if (self.auraCircle) {
			self.auraCircle.destroy();
			self.auraCircle = null;
		}
		originalDestroy.call(self);
	};
	return self;
});
/** 
	* Represents a Magic Ball projectile fired by a Wizard Tower.
	* @param {number} angle - The angle in radians at which the magic ball is fired.
	*/ 
var MagicBall = Container.expand(function (angle) {
	var self = Container.call(this);
	// Create and attach the magic ball graphic asset
	var graphics = self.attachAsset('magic_ball_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align magic ball graphic with direction
	self.speed = 15; // Base speed of the magic ball
	self.damage = 2; // Base damage dealt by this magic ball
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
		self.damage += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	self.slowDuration = 0; // Duration of slowdown applied on hit
	self.slowAmount = 0; // Multiplier for enemy speed on hit
	self.targetEnemy = null; // Track the specific enemy the magic ball is seeking
	self.seekSpeed = 0.05; // How quickly the magic ball adjusts its direction to seek
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the magic ball based on its velocity and seeks target if Aimbot is enabled.
	*/ 
	self.update = function () {
		if (aimbotEnabled && self.targetEnemy && self.targetEnemy.parent) {
			// If aimbot is enabled, a target exists and is still in the game, seek it
			var targetAngle = Math.atan2(self.targetEnemy.x - self.x, -(self.targetEnemy.y - self.y));
			// Smoothly adjust the magic ball's angle towards the target angle
			var angleDiff = targetAngle - (self.rotation - Math.PI / 2); // Difference considering graphic rotation
			// Normalize angle difference to be between -PI and PI
			if (angleDiff > Math.PI) {
				angleDiff -= 2 * Math.PI;
			}
			if (angleDiff < -Math.PI) {
				angleDiff += 2 * Math.PI;
			}
			// Interpolate angle
			var newAngle = self.rotation - Math.PI / 2 + angleDiff * self.seekSpeed;
			self.rotation = newAngle + Math.PI / 2;
			self.vx = Math.sin(newAngle) * self.speed;
			self.vy = -Math.cos(newAngle) * self.speed;
		} else if (aimbotEnabled && (!self.targetEnemy || !self.targetEnemy.parent)) {
			// If aimbot is enabled but current target is gone, find a new target
			self.targetEnemy = null; // Clear old target
			var closestEnemy = null;
			var closestDistance = Infinity;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			if (closestEnemy) {
				self.targetEnemy = closestEnemy;
			}
		}
		self.x += self.vx;
		self.y += self.vy;
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Swordsman ally that attacks enemies in melee range.
*/ 
var Swordsman = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the swordsman graphic asset (reusing enemy asset for simplicity)
	var graphics = self.attachAsset('swordsmanAlly', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// No tint needed as ally asset has unique colors
	graphics.scale.set(1.0); // Use the asset's intended scale
	self.attackRange = 150; // Melee attack range
	self.attackDamage = 1; // Damage per hit
	self.attackInterval = 60; // Attack every 1 second (60 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.lifetime = 10 * 60; // Lifetime in ticks (10 seconds * 60 ticks/sec)
	self.lifetimeTimer = 0; // Timer for lifetime
	/** 
	* Update method called each game tick by the LK engine.
	* Handles attacking and lifetime.
	*/ 
	self.update = function () {
		self.attackTimer++;
		self.lifetimeTimer++;
		// Check for lifetime
		var effectiveAttackInterval = Math.max(30, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade, min 0.5s
		if (self.lifetimeTimer >= self.lifetime) {
			self.destroy();
			// Remove from the swordsmen array in the main game loop
			return; // Stop updating this instance
		}
		// Find the closest enemy to chase or attack
		var closestEnemy = null;
		var closestDistance = Infinity;
		for (var i = 0; i < enemies.length; i++) {
			var enemy = enemies[i];
			// Calculate distance to the enemy
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < closestDistance) {
				closestDistance = distance;
				closestEnemy = enemy;
			}
		}
		// If an enemy exists, chase it or attack if within range
		if (closestEnemy) {
			// Movement speed toward enemies
			var moveSpeed = 5;
			// If not within attack range, move toward the enemy
			if (closestDistance > self.attackRange) {
				// Calculate direction vector to enemy
				var dirX = closestEnemy.x - self.x;
				var dirY = closestEnemy.y - self.y;
				// Normalize the direction vector
				var length = Math.sqrt(dirX * dirX + dirY * dirY);
				dirX = dirX / length;
				dirY = dirY / length;
				// Move toward the enemy
				self.x += dirX * moveSpeed;
				self.y += dirY * moveSpeed;
			}
			// If within attack range and attack timer is ready, attack
			else if (self.attackTimer >= effectiveAttackInterval) {
				self.attackTimer = 0; // Reset timer
				// Apply damage to the enemy and check if it was defeated
				var finalSwordsmanDamage = self.attackDamage;
				// Apply damage relic bonus if enabled
				if (playerRelics.damage.enabled) {
					finalSwordsmanDamage += playerRelics.damage.level;
				}
				var enemyDefeated = closestEnemy.takeDamage(finalSwordsmanDamage, self); // Pass the swordsman as source
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score when enemy is defeated by swordsman.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					closestEnemy.destroy();
					// Remove from the enemies array in the main game loop
				}
				// Optional: Add a visual/sound effect for attack here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents a Viking ally that throws piercing axes.
*/ 
var VikingAlly = Container.expand(function () {
	var self = Container.call(this);
	var graphics = self.attachAsset('viking_ally', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range
	self.attackInterval = 150; // Attack every 2.5 seconds (150 ticks)
	self.attackTimer = 0; // Timer for attacks
	/** 
	* Update method called each game tick by the LK engine.
	* Handles finding targets and throwing axes.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy within range
			var closestEnemy = null;
			var closestDistance = self.attackRange;
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, throw an axe
			if (closestEnemy) {
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				var newAxe = new VikingAxe(angle);
				newAxe.x = self.x;
				newAxe.y = self.y;
				newAxe.lastY = newAxe.y;
				newAxe.lastX = newAxe.x;
				game.addChild(newAxe);
				vikingAxes.push(newAxe); // Add to the vikingAxes array
				// Optional: Add throwing sound effect here later
			}
		}
	};
	return self;
});
/** 
* Represents an Axe thrown by a Viking Ally.
* @param {number} angle - The angle in radians at which the axe is thrown.
*/ 
var VikingAxe = Container.expand(function (angle) {
	var self = Container.call(this);
	var graphics = self.attachAsset('viking_axe', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	graphics.rotation = angle + Math.PI / 2; // Align axe graphic with direction
	self.speed = 25; // Speed of the axe
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.speed += 5;
	}
	self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
	self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
	self.damage = 3; // Base damage dealt by this axe
	// Apply refined projectiles bonus if enabled
	if (refinedProjectilesEnabled) {
		self.damage += 5;
	}
	self.pierceLeft = 3; // Can pierce through 3 enemies
	/** 
	* Update method called each game tick by the LK engine.
	* Moves the axe based on its velocity and handles rotation.
	*/ 
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
		graphics.rotation += 0.2; // Add spinning effect
	};
	return self;
});
/** 
	* Represents a Wizard Tower ally that shoots magic balls.
	*/ 
var WizardTower = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the wizard tower graphic asset
	var graphics = self.attachAsset('wizard_tower_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.attackRange = Infinity; // Infinite attack range
	self.attackDamage = 0.5; // Low damage, primary effect is slowdown
	self.attackInterval = 120; // Attack every 2 seconds (120 ticks)
	self.attackTimer = 0; // Timer for attacks
	self.slowDuration = 180; // Duration of slowdown effect in ticks (3 seconds)
	self.slowAmount = 0.5; // Multiplier for enemy speed (0.5 means 50% slower)
	/** 
	* Update method called each game tick by the LK engine.
	* Handles attacking enemies.
	*/ 
	self.update = function () {
		self.attackTimer++;
		var effectiveAttackInterval = Math.max(60, self.attackInterval * allyAttackSpeedMultiplier); // Apply ally attack speed upgrade
		if (self.attackTimer >= effectiveAttackInterval) {
			self.attackTimer = 0; // Reset timer
			// Find the closest enemy within range to shoot at
			var closestEnemy = null;
			var closestDistance = self.attackRange; // Limit to attack range
			for (var i = 0; i < enemies.length; i++) {
				var enemy = enemies[i];
				// Calculate distance to the enemy
				var dx = enemy.x - self.x;
				var dy = enemy.y - self.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < closestDistance) {
					closestDistance = distance;
					closestEnemy = enemy;
				}
			}
			// If an enemy is found, fire a magic ball
			if (closestEnemy) {
				// Calculate angle towards the closest enemy
				var angle = Math.atan2(closestEnemy.x - self.x, -(closestEnemy.y - self.y));
				// Create a new magic ball instance
				var newMagicBall = new MagicBall(angle);
				// Position the magic ball at the tower's location
				newMagicBall.x = self.x;
				newMagicBall.y = self.y;
				newMagicBall.lastY = newMagicBall.y; // Initialize lastY for state tracking
				newMagicBall.lastX = newMagicBall.x; // Initialize lastX for state tracking
				newMagicBall.slowDuration = self.slowDuration; // Pass slow duration to the magic ball
				newMagicBall.slowAmount = self.slowAmount; // Pass slow amount to the magic ball
				// Add the magic ball to the game scene and the tracking array.
				game.addChild(newMagicBall);
				magicBalls.push(newMagicBall); // Add to the magicBalls array
				// Optional: Add a visual/sound effect for magic ball shot here later
			}
		}
	};
	return self; // Return self for potential inheritance
});
/** 
* Represents an XBOW (crossbow) ally that rapidly shoots arrows.
*/ 
var XBOW = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach the XBOW graphic asset
	var graphics = self.attachAsset('xbow_asset', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.fireInterval = 20; // Very rapid fire (every 0.33 seconds)
	self.fireTimer = 0;
	self.targetingMode = 'closest_to_bastion'; // Default targeting mode
	self.smartTargetingEnabled = false; // Flag for smart targeting upgrade
	self.tintApplied = false; // Track if tint has been applied
	/** 
	* Update method called each game tick by the LK engine.
	* Handles rapid firing logic.
	*/ 
	self.update = function () {
		self.fireTimer++;
		var baseInterval = self.smartTargetingEnabled ? 15.36 : self.fireInterval; // 0.256 seconds when smart targeting enabled
		var effectiveFireInterval = Math.max(10, baseInterval * allyAttackSpeedMultiplier);
		if (self.fireTimer >= effectiveFireInterval) {
			self.fireTimer = 0;
			// Find target based on targeting mode
			var target = null;
			if (self.smartTargetingEnabled) {
				// Apply green tint when smart targeting is enabled
				if (!self.tintApplied) {
					graphics.tint = 0x00FF00; // Green tint
					self.tintApplied = true;
				}
				if (self.targetingMode === 'closest_to_bastion') {
					// Find enemy closest to bastion
					var closestDistance = Infinity;
					for (var i = 0; i < enemies.length; i++) {
						var enemy = enemies[i];
						var distanceToBastion = BASTION_Y - enemy.y;
						if (distanceToBastion > 0 && distanceToBastion < closestDistance) {
							closestDistance = distanceToBastion;
							target = enemy;
						}
					}
				} else if (self.targetingMode === 'strongest') {
					// Find enemy with highest health
					var maxHealth = -1;
					for (var i = 0; i < enemies.length; i++) {
						var enemy = enemies[i];
						if (enemy.health > maxHealth) {
							maxHealth = enemy.health;
							target = enemy;
						}
					}
				}
			}
			// Default behavior: shoot at center of screen
			var angle;
			if (target) {
				// Calculate angle towards target
				angle = Math.atan2(target.x - self.x, -(target.y - self.y));
			} else {
				// No target or smart targeting disabled - shoot straight up towards center
				angle = 0; // 0 radians = straight up
			}
			// Create arrow
			var newArrow = new Arrow(angle);
			newArrow.x = self.x;
			newArrow.y = self.y;
			newArrow.lastY = newArrow.y;
			newArrow.lastX = newArrow.x;
			// XBOW arrows are faster
			newArrow.speed *= 1.5;
			newArrow.vx = Math.sin(angle) * newArrow.speed;
			newArrow.vy = -Math.cos(angle) * newArrow.speed;
			// Disable aimbot for XBOW arrows
			newArrow.targetEnemy = null;
			game.addChild(newArrow);
			arrows.push(newArrow);
			// Apply multi-shot if enabled
			if (multiShotEnabled) {
				// Fire a second arrow with a slight angle offset
				var angle2 = angle + Math.PI / 12; // Offset by 15 degrees
				var newArrow2 = new Arrow(angle2);
				newArrow2.x = self.x;
				newArrow2.y = self.y;
				newArrow2.lastY = newArrow2.y;
				newArrow2.lastX = newArrow2.x;
				// XBOW arrows are faster
				newArrow2.speed *= 1.5;
				newArrow2.vx = Math.sin(angle2) * newArrow2.speed;
				newArrow2.vy = -Math.cos(angle2) * newArrow2.speed;
				// Disable aimbot for XBOW arrows
				newArrow2.targetEnemy = null;
				game.addChild(newArrow2);
				arrows.push(newArrow2);
				// Fire a third arrow with the opposite angle offset
				var angle3 = angle - Math.PI / 12; // Offset by -15 degrees
				var newArrow3 = new Arrow(angle3);
				newArrow3.x = self.x;
				newArrow3.y = self.y;
				newArrow3.lastY = newArrow3.y;
				newArrow3.lastX = newArrow3.x;
				// XBOW arrows are faster
				newArrow3.speed *= 1.5;
				newArrow3.vx = Math.sin(angle3) * newArrow3.speed;
				newArrow3.vy = -Math.cos(angle3) * newArrow3.speed;
				// Disable aimbot for XBOW arrows
				newArrow3.targetEnemy = null;
				game.addChild(newArrow3);
				arrows.push(newArrow3);
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
// Create the main game instance with a dark background color.
var game = new LK.Game({
	backgroundColor: 0x101030 // Dark blue/purple background
});
/**** 
* Game Code
****/ 
// Use actual war elephant asset
// Use actual spearman asset
// Placeholder ID, adjust size slightly, reuse flipX
// Placeholder ID
// Placeholder ID, adjust size slightly
// Constants defining game dimensions and key vertical positions.
//var facekit = LK.import('@upit/facekit.v1');
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
//var storage = LK.import('@upit/storage.v1');
//Storage library which should be used for persistent game data
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
//Only include the plugins you need to create the game.
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BASTION_Y = GAME_HEIGHT - 250; // Y-coordinate representing the defense line. Enemies crossing this trigger game over.
var FIRING_POS_Y = GAME_HEIGHT - 150; // Y-coordinate from where arrows are fired.
var FIRING_POS_X = GAME_WIDTH / 2; // X-coordinate from where arrows are fired (center).
// Arrays to keep track of active arrows and enemies.
var arrows = [];
var enemies = [];
// Variables for game state and difficulty scaling.
var scoreTxt; // Text2 object for displaying the score.
var ammoTxt; // Text2 object for displaying the current ammo count.
var dragStartX = null; // Starting X coordinate of a touch/mouse drag.
var dragStartY = null; // Starting Y coordinate of a touch/mouse drag.
var enemySpawnInterval = 120; // Initial ticks between enemy spawns (2 seconds at 60 FPS).
var arrowsFired = 0; // Counter for arrows fired since the last cooldown.
var cooldownTimer = 0; // Timer in ticks for the cooldown period.
var cooldownDuration = 6 * 60; // Cooldown duration in ticks (6 seconds * 60 ticks/sec). Min duration enforced in upgrade.
var baseMaxArrowsBeforeCooldown = 15; // Base max arrows before reload (Quiver upgrade)
var maxArrowsBeforeCooldown = baseMaxArrowsBeforeCooldown; // Max arrows before reload
var ammoRelicTimer = 0; // Timer for ammo relic regeneration
var arrowPierceLevel = 1; // How many enemies an arrow can pierce (Piercing Shots upgrade)
var arrowDamage = 1; // Base damage for arrows (Heat-tipped arrows upgrade)
var enemySpeedMultiplier = 1.0; // Multiplier for enemy speed (Sabotage upgrade) Min multiplier enforced in upgrade.
var minEnemySpawnInterval = 30; // Minimum ticks between enemy spawns (0.5 seconds).
var enemySpawnRateDecrease = 0.08; // Amount to decrease spawn interval each time an enemy spawns.
var currentEnemySpeed = 3; // Initial base speed of enemies.
var maxEnemySpeed = 12; // Maximum base speed enemies can reach.
var enemySpeedIncrease = 0.015; // Amount to increase enemy base speed each time an enemy spawns.
var archerAllies = []; // Array to hold ArcherAlly instances
var swordsmen = []; // Array to hold Swordsman instances
var cannonballs = []; // Array to hold Cannonball instances
var multiShotEnabled = false; // Flag for More Shots upgrade
var poisonShotsEnabled = false; // Flag for Poison Shots upgrade
var cannons = []; // Array to hold Cannon instances
var allyAttackSpeedMultiplier = 1.0; // Multiplier for ally attack speed
var wizardTowers = []; // Array to hold WizardTower instances
var magicBalls = []; // Array to hold MagicBall instances
var aimbotEnabled = false; // Flag for Aimbot upgrade
var greenKillerEnabled = false; // Flag for Green Killer upgrade
var refinedProjectilesEnabled = false; // Flag for Refined Projectiles upgrade
var greenSlowdownEnabled = false; // Flag for Green Slowdown upgrade
var vikingAllies = []; // Array to hold VikingAlly instances
var vikingAxes = []; // Array to hold VikingAxe instances
var darts = []; // Array to hold Dart instances
var angelOfLights = []; // Array to hold AngelOfLight instances
var bouncyBalls = []; // Array to hold BouncyBall instances
var bombs = []; // Array to hold Bomb instances
var bombers = []; // Array to hold Bomber instances
var xbows = []; // Array to hold XBOW instances
var xbowSmartTargetingEnabled = false; // Flag for XBOW Smart Targeting upgrade
var battleHornEnabled = false; // Flag for Battle Horn upgrade
var dragonSlayerCannonsModeEnabled = false; // Flag for Dragon Slayer Cannons upgrade
// --- Relics and Gold System ---
var playerGold = storage.playerGold || 0; // Load gold from storage, default to 0
// Load relics from storage using flat format
var storedRelicsData = storage.playerRelicsData || {};
var playerRelics = {
	damage: {
		level: storedRelicsData.damage_level || 0,
		enabled: storedRelicsData.damage_enabled || false
	},
	slowdown: {
		level: storedRelicsData.slowdown_level || 0,
		enabled: storedRelicsData.slowdown_enabled || false
	},
	green: {
		level: storedRelicsData.green_level || 0,
		enabled: storedRelicsData.green_enabled || false
	},
	dark: {
		level: storedRelicsData.dark_level || 0,
		enabled: storedRelicsData.dark_enabled || false
	},
	dragon: {
		level: storedRelicsData.dragon_level || 0,
		enabled: storedRelicsData.dragon_enabled || false
	},
	reload: {
		level: storedRelicsData.reload_level || 0,
		enabled: storedRelicsData.reload_enabled || false
	},
	ammo: {
		level: storedRelicsData.ammo_level || 0,
		enabled: storedRelicsData.ammo_enabled || false
	},
	swordsman: {
		level: storedRelicsData.swordsman_level || 0,
		enabled: storedRelicsData.swordsman_enabled || false
	}
};
var RELIC_MAX_LEVEL = 10;
var RELIC_COST_PER_LEVEL = 5; // 5 gold per level
// --- Upgrade System ---
var lastUpgradeScore = -1; // Score at which the last upgrade was offered
var isUpgradePopupActive = false; // Flag indicating if the upgrade choice popup is visible
var upgradePopup = null; // Container for the upgrade UI elements
var currentMusicPlaying = 'Gamemusic'; // Track which music is currently playing
var musicFadeInProgress = false; // Flag to track if a music fade transition is in progress
// Helper function to apply Sabotage effect to existing enemies
function applySabotage() {
	for (var i = 0; i < enemies.length; i++) {
		// We assume Enemy class will use enemySpeedMultiplier when calculating effective speed
		// If Enemy.speed stores base speed, we might need an effectiveSpeed method or update speed directly.
		// For simplicity, let's assume Enemy.update uses the global multiplier.
		// If direct modification is needed: enemies[i].speed = baseSpeed * enemySpeedMultiplier;
	}
	// Also update the current base speed calculation baseline if necessary, though modifying the multiplier should suffice.
}
// Helper function placeholder for adding Archer Ally
function addArcherAlly() {
	// Implementation requires ArcherAlly class definition
	console.log("Archer Ally upgrade chosen!");
	var ally = new ArcherAlly();
	// Position the ally next to the player's firing position, slightly offset.
	ally.x = FIRING_POS_X + 150; // Position to the right of the player
	ally.y = FIRING_POS_Y;
	game.addChild(ally);
	archerAllies.push(ally); // Add to the new archerAllies array
}
// Helper function to add a Cannon ally
function addCannon() {
	console.log("Cannon upgrade chosen!");
	var newCannon = new Cannon();
	// Position the cannon near the bastion line
	newCannon.x = GAME_WIDTH / 2 - 300; // Example position to the left of center
	newCannon.y = BASTION_Y - 100; // Position above the bastion line
	// Apply dragon slayer mode if the global flag is enabled
	newCannon.dragonSlayerMode = dragonSlayerCannonsModeEnabled;
	game.addChild(newCannon);
	cannons.push(newCannon); // Add to the cannons array
}
// Helper function to add a Wizard Tower
function addWizardTower() {
	console.log("Wizard Tower upgrade chosen!");
	var newTower = new WizardTower();
	// Position the wizard tower near the bastion line, offset from center
	newTower.x = GAME_WIDTH / 2 + 300; // Example position to the right of center
	newTower.y = BASTION_Y - 100; // Position above the bastion line
	game.addChild(newTower);
	wizardTowers.push(newTower); // Add to the wizardTowers array
}
// Helper function to add a Viking Ally
function addVikingAlly() {
	console.log("Viking Ally upgrade chosen!");
	var newViking = new VikingAlly();
	// Position the viking near the bastion line, offset from cannons/towers
	newViking.x = GAME_WIDTH / 2; // Center for now
	newViking.y = BASTION_Y - 100; // Position above the bastion line
	game.addChild(newViking);
	vikingAllies.push(newViking); // Add to the vikingAllies array
}
// Helper function to add a Dart Ally
function addDartAlly() {
	console.log("Dart Ally upgrade chosen!");
	var newDartAlly = new DartAlly();
	// Position the dart ally near the bastion line, offset
	newDartAlly.x = GAME_WIDTH / 2 - 200; // Example position
	newDartAlly.y = BASTION_Y - 100; // Position above bastion line
	game.addChild(newDartAlly);
	darts.push(newDartAlly); // Add to the dartAllies array (need to rename array to dartAllies if creating a separate one)
}
// Helper function placeholder for adding Swordsman
function addSwordsman() {
	// Create a swordsman tower at the bastion line
	var tower = new Container();
	var towerGraphics = tower.attachAsset('swordsmanTower', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	tower.x = FIRING_POS_X; // Position in the center horizontally
	tower.y = BASTION_Y - 50; // Position just above the bastion line
	game.addChild(tower);
	// Set up interval to spawn swordsmen from the tower
	var spawnInterval = LK.setInterval(function () {
		var newSwordsman = new Swordsman();
		// Position the swordsman near the tower with a slight random offset
		newSwordsman.x = tower.x + (Math.random() * 100 - 50); // Random offset of ±50px
		newSwordsman.y = tower.y;
		game.addChild(newSwordsman);
		swordsmen.push(newSwordsman); // Add to the swordsmen array
	}, 3000); // Spawn a swordsman every 3 seconds
	// Swordsman spawn does not grant score
	// Store the interval reference in the tower to potentially clear it later
	tower.spawnInterval = spawnInterval;
}
// Helper function to add an Angel of Light
function addAngelOfLight() {
	console.log("Angel of Light upgrade chosen!");
	var newAngel = new AngelOfLight();
	// Position the angel near the bastion line, offset
	newAngel.x = GAME_WIDTH / 2 + 200; // Example position
	newAngel.y = BASTION_Y - 150; // Position slightly higher than other allies
	game.addChild(newAngel);
	angelOfLights.push(newAngel); // Add to the angelOfLights array
}
// Helper function to add a Bouncy Ball
function addBouncyBall() {
	console.log("Bouncy Ball upgrade chosen!");
	var newBall = new BouncyBall();
	// Start from center of screen
	newBall.x = GAME_WIDTH / 2;
	newBall.y = GAME_HEIGHT / 2;
	game.addChild(newBall);
	bouncyBalls.push(newBall);
}
// Helper function to add a Bomber
function addBomber() {
	console.log("Bomber upgrade chosen!");
	var newBomber = new Bomber();
	// Position near bastion line
	newBomber.x = GAME_WIDTH / 2 - 400;
	newBomber.y = BASTION_Y - 100;
	game.addChild(newBomber);
	bombers.push(newBomber);
}
// Helper function to add an XBOW
function addXBOW() {
	console.log("XBOW upgrade chosen!");
	var newXBOW = new XBOW();
	// Position at the center of the bastion
	newXBOW.x = GAME_WIDTH / 2;
	newXBOW.y = BASTION_Y - 100;
	game.addChild(newXBOW);
	xbows.push(newXBOW);
}
// Helper function to enable XBOW Smart Targeting
function enableXBOWSmartTargeting() {
	console.log("XBOW Smart Targeting upgrade chosen!");
	xbowSmartTargetingEnabled = true;
	// Enable smart targeting for all existing XBOWs
	for (var i = 0; i < xbows.length; i++) {
		xbows[i].smartTargetingEnabled = true;
		// Randomly assign targeting mode for variety
		xbows[i].targetingMode = Math.random() < 0.5 ? 'closest_to_bastion' : 'strongest';
	}
}
// Define all possible upgrades
var allUpgrades = [{
	id: 'faster_reload',
	name: 'Faster Reload',
	description: 'Decrease reload time by 20%',
	apply: function apply() {
		cooldownDuration = Math.max(60, Math.floor(cooldownDuration * 0.8));
	}
},
// Min 1 sec cooldown
{
	id: 'piercing_shots',
	name: 'Piercing Shots',
	description: 'Arrows pierce +1 enemy',
	apply: function apply() {
		arrowPierceLevel++;
	}
}, {
	id: 'quiver',
	name: 'Quiver',
	description: '+5 Arrows before reload',
	apply: function apply() {
		maxArrowsBeforeCooldown += 5;
	}
}, {
	id: 'heat_tipped',
	name: 'Heat-tipped Arrows',
	description: 'Arrows deal +1 damage',
	apply: function apply() {
		arrowDamage += 1;
		console.log("Heat-tipped Arrows upgrade chosen - damage increased to " + arrowDamage);
	}
}, {
	id: 'archer_ally',
	name: 'Archer Ally',
	description: 'Gain an allied archer',
	apply: addArcherAlly
}, {
	id: 'sabotage',
	name: 'Sabotage',
	description: 'Enemies 10% slower',
	apply: function apply() {
		enemySpeedMultiplier = Math.max(0.5, enemySpeedMultiplier * 0.9);
		applySabotage();
	}
},
// Max 50% slow
{
	id: 'swordsman',
	name: 'Swordsman',
	description: 'Gain a melee defender',
	apply: addSwordsman
}, {
	id: 'more_shots',
	name: 'More Shots',
	description: 'Shoot 2 arrows at once',
	apply: function apply() {
		multiShotEnabled = true; // Assuming a global flag for this
	}
}, {
	id: 'poison_shots',
	name: 'Poison Shots',
	description: 'Shots deal damage over time',
	apply: function apply() {
		poisonShotsEnabled = true; // Assuming a global flag for this
	}
}, {
	id: 'cannon',
	name: 'Cannon',
	description: 'Gain a cannon that targets the strongest enemy',
	apply: addCannon // Assuming a helper function addCannon
}, {
	id: 'ally_atk_speed',
	name: 'Ally ATK Speed',
	description: 'All allies attack faster',
	apply: function apply() {
		allyAttackSpeedMultiplier *= 0.8; // Assuming a global multiplier
		// Apply to existing allies as well in their update logic or a helper function
	}
}, {
	id: 'wizard_tower',
	name: 'Wizard Tower',
	description: 'Gain a wizard tower ally that shoots magic balls that slowdown enemies',
	apply: addWizardTower // Assuming a helper function addWizardTower
}, {
	id: 'aimbot',
	name: 'Aimbot',
	description: 'Arrows seek out enemies',
	apply: function apply() {
		aimbotEnabled = true; // Assuming a global flag for this
	}
}, {
	id: 'green_killer',
	name: 'Green Killer',
	description: '+50% Damage vs Green Enemies',
	apply: function apply() {
		greenKillerEnabled = true;
	}
}, {
	id: 'refined_projectiles',
	name: 'Refined Projectiles',
	description: 'Non-arrow projectiles +5 damage & faster',
	apply: function apply() {
		refinedProjectilesEnabled = true;
		// Existing projectiles won't update, new ones will have bonus
	}
}, {
	id: 'viking_ally',
	name: 'Viking Ally',
	description: 'Gain a viking that throws piercing axes',
	apply: addVikingAlly // Assuming helper function addVikingAlly
}, {
	id: 'green_slowdown',
	name: 'Green Slowdown',
	description: 'Projectiles slow Green enemies 10% for 10s (no stack)',
	apply: function apply() {
		greenSlowdownEnabled = true;
	}
}, {
	id: 'dart_shooter',
	name: 'Dart Shooter',
	description: 'Gain an ally that shoots fast darts, effective against green enemies',
	apply: addDartAlly // Assuming a helper function addDartAlly
}, {
	id: 'angel_of_light',
	name: 'Angel of Light',
	description: 'Gain an ally that stuns enemies and deals high damage to dark enemies',
	apply: addAngelOfLight // Assuming a helper function addAngelOfLight
}, {
	id: 'bouncy_ball',
	name: 'Bouncy Ball',
	description: 'Bounces around dealing massive damage to enemies',
	apply: addBouncyBall
}, {
	id: 'bomber',
	name: 'Bomber',
	description: 'Throws bombs that explode for area damage',
	apply: addBomber
}, {
	id: 'xbow',
	name: 'XBOW',
	description: 'A big bow that rapidly shoots arrows',
	apply: addXBOW
}, {
	id: 'xbow_smart_targeting',
	name: 'XBOW Smart Targeting',
	description: 'XBOWs can target closest to bastion or strongest enemy',
	apply: enableXBOWSmartTargeting
}, {
	id: 'dragon_slayer_cannons',
	name: 'Dragon Slayer Cannons',
	description: 'Cannons become rocket launchers that deal 25x damage to dragons and prioritize them',
	apply: function apply() {
		// Enable dragon slayer mode for all existing cannons
		for (var i = 0; i < cannons.length; i++) {
			cannons[i].dragonSlayerMode = true;
		}
		// Set global flag so all future cannons will have dragon slayer mode
		dragonSlayerCannonsModeEnabled = true;
	}
}, {
	id: 'battle_horn',
	name: 'Battle Horn',
	description: 'More enemies spawn, but they are all swordsmen: more score for more upgrades!',
	apply: function apply() {
		// Reduce spawn interval for more enemies
		enemySpawnInterval = Math.max(15, enemySpawnInterval * 0.5); // 50% faster spawning, min 0.25 seconds
		// Set global flag to force swordsman spawns
		battleHornEnabled = true;
	}
}];
// Function to create and show the upgrade selection popup
function showUpgradePopup() {
	isUpgradePopupActive = true;
	// Simple pause: Game logic checks isUpgradePopupActive flag in game.update
	// Switch to upgrade theme music with fade effect
	if (currentMusicPlaying !== 'UpgradeTheme' && !musicFadeInProgress) {
		musicFadeInProgress = true;
		// Fade out current music
		LK.playMusic('Gamemusic', {
			fade: {
				start: 1,
				end: 0,
				duration: 800
			}
		});
		// After fade out completes, start upgrade theme with fade in
		LK.setTimeout(function () {
			LK.playMusic('UpgradeTheme', {
				fade: {
					start: 0,
					end: 1,
					duration: 1000
				}
			});
			currentMusicPlaying = 'UpgradeTheme';
			musicFadeInProgress = false;
		}, 850);
	}
	// --- Create Popup UI ---
	upgradePopup = new Container();
	upgradePopup.x = GAME_WIDTH / 2;
	upgradePopup.y = GAME_HEIGHT / 2;
	game.addChild(upgradePopup); // Add to game layer for positioning relative to center
	// Add a semi-transparent background overlay
	var bg = upgradePopup.attachAsset('bastionLine', {
		// Reusing an asset for shape
		width: 1200,
		height: 800,
		color: 0x000000,
		// Black background
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	// Add title text
	var title = new Text2('Choose an Upgrade!', {
		size: 80,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -300; // Position relative to popup center
	upgradePopup.addChild(title);
	// --- Select 3 Random Unique Upgrades ---
	var availableToOffer = allUpgrades.slice(); // Copy available upgrades
	var choices = [];
	var numChoices = Math.min(3, availableToOffer.length); // Offer up to 3 choices
	// Make dragon slayer cannons more common past score 100
	var currentScore = LK.getScore();
	if (currentScore > 100 && !dragonSlayerCannonsModeEnabled) {
		// Add dragon slayer cannons upgrade multiple times to increase chances
		var dragonSlayerUpgrade = null;
		for (var ds = 0; ds < availableToOffer.length; ds++) {
			if (availableToOffer[ds].id === 'dragon_slayer_cannons') {
				dragonSlayerUpgrade = availableToOffer[ds];
				break;
			}
		}
		if (dragonSlayerUpgrade) {
			// Add it 2 more times to the pool (3x total chance)
			availableToOffer.push(dragonSlayerUpgrade);
			availableToOffer.push(dragonSlayerUpgrade);
		}
	}
	for (var i = 0; i < numChoices; i++) {
		var randomIndex = Math.floor(Math.random() * availableToOffer.length);
		choices.push(availableToOffer[randomIndex]);
		availableToOffer.splice(randomIndex, 1); // Remove chosen upgrade to ensure uniqueness
	}
	// --- Create Buttons for Choices ---
	var buttonYStart = -150;
	var buttonSpacing = 180;
	for (var j = 0; j < choices.length; j++) {
		var upgrade = choices[j];
		var button = createUpgradeButton(upgrade, buttonYStart + j * buttonSpacing);
		upgradePopup.addChild(button);
	}
}
// Function to create a single upgrade button
function createUpgradeButton(upgradeData, yPos) {
	var buttonContainer = new Container();
	buttonContainer.y = yPos;
	// Button background
	var buttonBg = buttonContainer.attachAsset('bastionLine', {
		// Reusing asset for shape
		width: 800,
		height: 150,
		color: 0x555555,
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Button text (Name + Description)
	var nameText = new Text2(upgradeData.name, {
		size: 50,
		fill: 0xFFFFFF
	});
	nameText.anchor.set(0.5, 0.5);
	nameText.y = -25;
	buttonContainer.addChild(nameText);
	var descText = new Text2(upgradeData.description, {
		size: 35,
		fill: 0xCCCCCC
	});
	descText.anchor.set(0.5, 0.5);
	descText.y = 30;
	buttonContainer.addChild(descText);
	// Make button interactive
	buttonContainer.interactive = true; // Needed for down event
	// Event handler for button press
	buttonContainer.down = function (x, y, obj) {
		upgradeData.apply(); // Apply the selected upgrade's effect
		hideUpgradePopup(); // Close the popup
	};
	return buttonContainer;
}
// Function to hide and destroy the upgrade popup
function hideUpgradePopup() {
	if (upgradePopup) {
		upgradePopup.destroy();
		upgradePopup = null;
	}
	isUpgradePopupActive = false;
	// Switch back to game music with fade effect
	if (currentMusicPlaying !== 'Gamemusic' && !musicFadeInProgress) {
		musicFadeInProgress = true;
		// Fade out upgrade theme
		LK.playMusic('UpgradeTheme', {
			fade: {
				start: 1,
				end: 0,
				duration: 800
			}
		});
		// After fade out completes, start game music with fade in
		LK.setTimeout(function () {
			LK.playMusic('Gamemusic', {
				fade: {
					start: 0,
					end: 1,
					duration: 1000
				}
			});
			currentMusicPlaying = 'Gamemusic';
			musicFadeInProgress = false;
		}, 850);
	}
	// Resume game logic (handled by checking flag in game.update)
}
// --- Upgradepedia ---
var upgradepediaButton;
var upgradepediaPopup = null;
var upgradeListContainer = null;
function showUpgradepedia() {
	isUpgradePopupActive = true; // Pause the game while upgradepedia is open
	upgradepediaPopup = new Container();
	upgradepediaPopup.x = GAME_WIDTH / 2;
	upgradepediaPopup.y = GAME_HEIGHT / 2;
	game.addChild(upgradepediaPopup);
	// Add a semi-transparent background overlay
	var bg = upgradepediaPopup.attachAsset('pedia_screen_bg', {
		width: 1600,
		height: 2000,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.9
	});
	// Add title text
	var title = new Text2('Upgradepedia', {
		size: 100,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -900;
	upgradepediaPopup.addChild(title);
	// Add close button
	var closeButton = createUpgradepediaCloseButton();
	closeButton.x = 750;
	closeButton.y = -900;
	upgradepediaPopup.addChild(closeButton);
	// Container for upgrade details
	upgradeListContainer = new Container();
	upgradeListContainer.y = -200;
	upgradepediaPopup.addChild(upgradeListContainer);
	displayUpgradeStats();
}
function hideUpgradepedia() {
	if (upgradepediaPopup) {
		upgradepediaPopup.destroy();
		upgradepediaPopup = null;
	}
	isUpgradePopupActive = false; // Unpause the game
}
function createUpgradepediaCloseButton() {
	var buttonContainer = new Container();
	var buttonBg = buttonContainer.attachAsset('pedia_button_bg', {
		width: 150,
		height: 80,
		color: 0xCC0000,
		anchorX: 0.5,
		anchorY: 0.5
	});
	var buttonText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF
	});
	buttonText.anchor.set(0.5, 0.5);
	buttonContainer.addChild(buttonText);
	buttonContainer.interactive = true;
	buttonContainer.down = function () {
		hideUpgradepedia();
	};
	return buttonContainer;
}
function displayUpgradeStats() {
	// Clear any existing content
	while (upgradeListContainer.children.length > 0) {
		upgradeListContainer.removeChildAt(0);
	}
	// Current page tracking
	var currentUpgrade = 0;
	var totalUpgrades = allUpgrades.length;
	// Map upgrade IDs to visual assets and additional info
	var upgradeAssets = {
		'faster_reload': {
			asset: 'Reload',
			scale: 0.4
		},
		'piercing_shots': {
			asset: 'arrow',
			scale: 0.6
		},
		'quiver': {
			asset: 'arrow',
			scale: 0.8,
			tint: 0xFFD700
		},
		'heat_tipped': {
			asset: 'arrow',
			scale: 0.6,
			tint: 0xFF4500
		},
		'archer_ally': {
			asset: 'Archer',
			scale: 0.8
		},
		'sabotage': {
			asset: 'thief',
			scale: 0.8
		},
		'swordsman': {
			asset: 'swordsmanAlly',
			scale: 0.8
		},
		'more_shots': {
			asset: 'arrow',
			scale: 0.5,
			count: 3
		},
		'poison_shots': {
			asset: 'arrow',
			scale: 0.6,
			tint: 0x00FF00
		},
		'cannon': {
			asset: 'cannon_asset',
			scale: 0.8
		},
		'ally_atk_speed': {
			asset: 'viking_axe',
			scale: 0.6
		},
		'wizard_tower': {
			asset: 'wizard_tower_asset',
			scale: 0.8
		},
		'aimbot': {
			asset: 'arrow',
			scale: 0.6,
			special: 'seeking'
		},
		'green_killer': {
			asset: 'arrow',
			scale: 0.6,
			tint: 0xFF0000
		},
		'refined_projectiles': {
			asset: 'cannonball',
			scale: 0.6,
			tint: 0xFFD700
		},
		'viking_ally': {
			asset: 'viking_ally',
			scale: 0.8
		},
		'green_slowdown': {
			asset: 'magic_ball_asset',
			scale: 0.6,
			tint: 0x00FF00
		},
		'dart_shooter': {
			asset: 'dart_asset',
			scale: 0.8
		},
		'angel_of_light': {
			asset: 'angel_of_light_asset',
			scale: 0.8
		},
		'bouncy_ball': {
			asset: 'cannonball',
			scale: 1.0,
			tint: 0xFF00FF
		},
		'bomber': {
			asset: 'bomber_asset',
			scale: 0.8
		},
		'xbow': {
			asset: 'xbow_asset',
			scale: 0.8
		},
		'xbow_smart_targeting': {
			asset: 'xbow_asset',
			scale: 0.8,
			tint: 0x00FFFF
		},
		'dragon_slayer_cannons': {
			asset: 'cannon_asset',
			scale: 0.8,
			tint: 0xFF0000
		},
		'battle_horn': {
			asset: 'flag_bearer_asset',
			scale: 0.8,
			tint: 0xFFD700
		}
	};
	function displayUpgradeDetails(index) {
		// Clear existing content
		while (upgradeListContainer.children.length > 0) {
			upgradeListContainer.removeChildAt(0);
		}
		var upgradeInfo = allUpgrades[index];
		var assetInfo = upgradeAssets[upgradeInfo.id] || {
			asset: 'arrow',
			scale: 0.6
		};
		// Upgrade display container
		var upgradeDisplay = new Container();
		upgradeDisplay.y = 0;
		upgradeListContainer.addChild(upgradeDisplay);
		// Add upgrade graphic
		if (assetInfo.count) {
			// Special case for multiple projectiles
			for (var i = 0; i < assetInfo.count; i++) {
				var graphic = upgradeDisplay.attachAsset(assetInfo.asset, {
					anchorX: 0.5,
					anchorY: 0.5,
					scaleX: assetInfo.scale,
					scaleY: assetInfo.scale,
					x: -400 + (i - 1) * 100,
					y: 50
				});
				if (assetInfo.tint) {
					graphic.tint = assetInfo.tint;
				}
			}
		} else {
			var upgradeGraphic = upgradeDisplay.attachAsset(assetInfo.asset, {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: assetInfo.scale,
				scaleY: assetInfo.scale,
				x: -400,
				y: 50
			});
			if (assetInfo.tint) {
				upgradeGraphic.tint = assetInfo.tint;
			}
			// Special visual effects
			if (assetInfo.special === 'seeking') {
				// Add rotation animation hint for seeking arrows
				upgradeGraphic.rotation = Math.PI / 6;
			}
		}
		// Add upgrade name
		var nameText = new Text2(upgradeInfo.name, {
			size: 70,
			fill: 0xFFFFFF
		});
		nameText.anchor.set(0.5, 0);
		nameText.x = 0;
		nameText.y = -400;
		upgradeDisplay.addChild(nameText);
		// Add description
		var descText = new Text2(upgradeInfo.description, {
			size: 45,
			fill: 0xCCCCCC,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		descText.anchor.set(0.5, 0);
		descText.x = 0;
		descText.y = -300;
		upgradeDisplay.addChild(descText);
		// Add detailed ability description
		var abilityText = getDetailedAbility(upgradeInfo.id);
		var abilityDisplay = new Text2('Ability: ' + abilityText, {
			size: 40,
			fill: 0x88FF88,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		abilityDisplay.anchor.set(0.5, 0);
		abilityDisplay.x = 0;
		abilityDisplay.y = -150;
		upgradeDisplay.addChild(abilityDisplay);
		// Status display
		var statusText = new Text2('Upgrade ' + (index + 1) + ' of ' + totalUpgrades, {
			size: 35,
			fill: 0xAAAAAA
		});
		statusText.anchor.set(0.5, 0);
		statusText.x = 0;
		statusText.y = 250;
		upgradeDisplay.addChild(statusText);
		// Navigation buttons
		var navButtons = new Container();
		navButtons.y = 350;
		upgradeDisplay.addChild(navButtons);
		// Previous button
		var prevButton = createUpgradeNavButton('← Previous', -250, function () {
			currentUpgrade = (currentUpgrade - 1 + totalUpgrades) % totalUpgrades;
			displayUpgradeDetails(currentUpgrade);
		});
		navButtons.addChild(prevButton);
		// Next button
		var nextButton = createUpgradeNavButton('Next →', 250, function () {
			currentUpgrade = (currentUpgrade + 1) % totalUpgrades;
			displayUpgradeDetails(currentUpgrade);
		});
		navButtons.addChild(nextButton);
	}
	function getDetailedAbility(upgradeId) {
		var abilities = {
			'faster_reload': 'Reduces the cooldown time between reloads by 20%. Stacks multiplicatively with minimum 1 second cooldown.',
			'piercing_shots': 'Each arrow can pierce through one additional enemy. Stacks to pierce multiple enemies.',
			'quiver': 'Increases maximum ammo capacity by 5 arrows before needing to reload.',
			'heat_tipped': 'Increases arrow damage by 1. Affects all arrow-based attacks including allies.',
			'archer_ally': 'Spawns an allied archer that independently targets and shoots at enemies every 3 seconds.',
			'sabotage': 'Reduces all enemy movement speed by 10%. Stacks multiplicatively with minimum 50% speed.',
			'swordsman': 'Creates a tower that spawns temporary swordsmen allies every 3 seconds. Swordsmen chase and attack nearby enemies.',
			'more_shots': 'Fire 3 arrows at once in a spread pattern. Works with all arrow upgrades.',
			'poison_shots': 'Arrows apply poison stacks that deal damage over time. Each stack deals damage every 0.5 seconds.',
			'cannon': 'Deploys a cannon that targets the strongest enemy and fires high-damage cannonballs every 5 seconds.',
			'ally_atk_speed': 'All allies attack 20% faster. Stacks multiplicatively.',
			'wizard_tower': 'Builds a tower that shoots magic balls causing slowdown effect on hit. Dragons are immune to slowdown.',
			'aimbot': 'Arrows and magic balls automatically seek the nearest enemy. Updates target if current target is destroyed.',
			'green_killer': 'Deal 50% extra damage to all Green-tagged enemies (Wizards, Spearmen, War Elephants, Shamans).',
			'refined_projectiles': 'Non-arrow projectiles (cannonballs, magic balls, axes) gain +5 damage and +5 speed.',
			'viking_ally': 'Summons a viking warrior that throws piercing axes. Each axe can pierce through 3 enemies.',
			'green_slowdown': 'Projectiles slow Green-tagged enemies by 10% for 10 seconds. Effect does not stack.',
			'dart_shooter': 'Deploys a rapid-fire dart shooter that deals double damage to Green enemies.',
			'angel_of_light': 'Summons an angel that stuns enemies for 5 seconds and deals triple damage to Black-tagged enemies. Dragons cannot be stunned.',
			'bouncy_ball': 'Releases a bouncing projectile that ricochets off walls dealing massive damage. Lasts 10 seconds or 20 bounces.',
			'bomber': 'Deploys a bomber that throws area damage bombs. Cannot directly target Dragons but explosion can damage them.',
			'xbow': 'Installs a large crossbow that rapidly fires arrows every 0.33 seconds. Arrows travel 50% faster.',
			'xbow_smart_targeting': 'XBOWs can now target either the enemy closest to bastion or the strongest enemy. All other allies have this by default.',
			'dragon_slayer_cannons': 'Transforms all current and future cannons into rocket launchers. Rockets deal 25x damage to Dragon-type enemies and prioritize targeting them over all other enemy types.',
			'battle_horn': 'Doubles enemy spawn rate but forces all spawned enemies to be basic swordsmen. Great for farming score since swordsmen are easy to defeat!'
		};
		return abilities[upgradeId] || 'Special ability that enhances your defenses.';
	}
	function createUpgradeNavButton(label, xPos, callback) {
		var button = new Container();
		button.x = xPos;
		var buttonBg = button.attachAsset('pedia_nav_button_bg', {
			width: 250,
			height: 80,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 40,
			fill: 0xFFFFFF
		});
		buttonText.anchor.set(0.5, 0.5);
		button.addChild(buttonText);
		button.interactive = true;
		button.down = callback;
		return button;
	}
	// Initial display
	displayUpgradeDetails(currentUpgrade);
}
// Create upgradepedia button
upgradepediaButton = new Container();
upgradepediaButton.x = 200; // Position on the left side
upgradepediaButton.y = GAME_HEIGHT - 200;
// Add button background
var upgradeBtnBg = upgradepediaButton.attachAsset('pedia_button_bg', {
	width: 300,
	height: 100,
	anchorX: 0.5,
	anchorY: 0.5
});
// Add button text
var upgradeBtnText = new Text2('Upgradepedia', {
	size: 40,
	fill: 0xFFFFFF
});
upgradeBtnText.anchor.set(0.5, 0.5);
upgradepediaButton.addChild(upgradeBtnText);
// Make button interactive
upgradepediaButton.interactive = true;
upgradepediaButton.down = function () {
	showUpgradepedia();
};
// Add the button to the game scene
game.addChild(upgradepediaButton);
// --- Relic Shop Button ---
var relicShopButton = new Container();
relicShopButton.x = GAME_WIDTH - 200; // Position on the right side
relicShopButton.y = GAME_HEIGHT - 320; // Position above Enemypedia button
var relicBtnBg = relicShopButton.attachAsset('pedia_button_bg', {
	width: 300,
	height: 100,
	anchorX: 0.5,
	anchorY: 0.5
});
var relicBtnText = new Text2('Relic Shop', {
	size: 40,
	fill: 0xFFFFFF
});
relicBtnText.anchor.set(0.5, 0.5);
relicShopButton.addChild(relicBtnText);
relicShopButton.interactive = true;
relicShopButton.down = function () {
	showRelicShop();
};
game.addChild(relicShopButton);
// --- Visual Setup ---
var bastionLine = game.addChild(LK.getAsset('bastionLine', {
	anchorX: 0.0,
	// Anchor at the left edge.
	anchorY: 0.5,
	// Anchor vertically centered.
	x: 0,
	// Position at the left edge of the screen.
	y: BASTION_Y // Position at the defined bastion Y-coordinate.
}));
// Create and configure the score display text.
scoreTxt = new Text2('0', {
	size: 150,
	// Font size.
	fill: 0xFFFFFF // White color.
});
scoreTxt.anchor.set(0.5, 0); // Anchor at the horizontal center, top edge.
// Add score text to the GUI layer at the top-center position.
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 30; // Add padding below the top edge. Ensure it's clear of the top-left menu icon area.
// Create and configure the ammo display text.
ammoTxt = new Text2('Ammo: ' + maxArrowsBeforeCooldown, {
	size: 80,
	fill: 0xFFFFFF // White color.
});
ammoTxt.anchor.set(0.5, 0); // Anchor at the horizontal center, top edge.
LK.gui.top.addChild(ammoTxt);
ammoTxt.y = 180; // Position below the score text
// --- Enemypedia ---
var enemypediaButton;
var enemypediaPopup = null;
var enemyListContainer = null; // Container for enemy list items
function showEnemypedia() {
	isUpgradePopupActive = true; // Pause the game while enemypedia is open
	enemypediaPopup = new Container();
	enemypediaPopup.x = GAME_WIDTH / 2;
	enemypediaPopup.y = GAME_HEIGHT / 2;
	game.addChild(enemypediaPopup);
	// Add a semi-transparent background overlay
	var bg = enemypediaPopup.attachAsset('bastionLine', {
		width: 1600,
		height: 1200,
		// Increased height for better layout
		color: 0x000000,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	// Add title text
	var title = new Text2('Enemypedia', {
		size: 100,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -500; // Position relative to popup center
	enemypediaPopup.addChild(title);
	// Add a close button
	var closeButton = createCloseButton();
	closeButton.x = 750; // Position relative to popup center
	closeButton.y = -500;
	enemypediaPopup.addChild(closeButton);
	// Container for the enemy details
	enemyListContainer = new Container();
	enemyListContainer.y = -100; // Centered position for detailed view
	enemypediaPopup.addChild(enemyListContainer);
	displayEnemyStats();
}
function hideEnemypedia() {
	if (enemypediaPopup) {
		enemypediaPopup.destroy();
		enemypediaPopup = null;
	}
	isUpgradePopupActive = false; // Unpause the game
}
function createCloseButton() {
	var buttonContainer = new Container();
	var buttonBg = buttonContainer.attachAsset('bastionLine', {
		width: 150,
		height: 80,
		color: 0xCC0000,
		// Red color for close
		anchorX: 0.5,
		anchorY: 0.5
	});
	var buttonText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF
	});
	buttonText.anchor.set(0.5, 0.5);
	buttonContainer.addChild(buttonText);
	buttonContainer.interactive = true;
	buttonContainer.down = function () {
		hideEnemypedia();
	};
	return buttonContainer;
}
function displayEnemyStats() {
	// Dummy data representing enemy types and their stats
	var enemyData = [{
		type: 'swordsman',
		assetId: 'enemy',
		description: 'Basic melee unit that has very low HP.',
		baseHealth: 1,
		baseSpeed: 3,
		dodgeChance: 0
	}, {
		type: 'knight',
		assetId: 'knight',
		description: 'A threat for the first few waves cause of its high health, but is slow.',
		baseHealth: 5,
		baseSpeed: 3 * 0.9,
		dodgeChance: 0
	}, {
		type: 'thief',
		assetId: 'thief',
		description: 'Fast, low health unit with a dodge chance; likes gravy.',
		baseHealth: 1,
		baseSpeed: 3 * 1.2,
		dodgeChance: 0.1
	}, {
		type: 'boss',
		assetId: 'boss',
		description: 'a boss that spawns randomly when youre in trobule.',
		baseHealth: 5,
		// Base health before scaling
		baseSpeed: 3 * 0.7,
		dodgeChance: 0
	}, {
		type: 'shield',
		assetId: 'shield_enemy',
		description: 'Slow unit that has high HP',
		baseHealth: 20,
		baseSpeed: 3 * 0.5,
		dodgeChance: 0
	}, {
		type: 'wizard',
		assetId: 'wizard_enemy',
		description: 'kinda tricky cause it teleports and has moderate speed.',
		baseHealth: 2,
		baseSpeed: 3 * 0.7,
		dodgeChance: 0
	}, {
		type: 'spearman',
		assetId: 'spearman',
		description: 'Standard, annoying green unit that spawns from Elephants most of the time.',
		baseHealth: 2,
		baseSpeed: 3 * 1.0,
		dodgeChance: 0
	}, {
		type: 'war_elephant',
		assetId: 'war_elephant',
		description: 'Extremely high health elephant, spawns spearmen on death',
		baseHealth: 500,
		baseSpeed: 3 * 0.3,
		dodgeChance: 0
	}, {
		type: 'elite_knight',
		assetId: 'elite_knight_asset',
		description: 'High health knight variant that is loyal to the king',
		baseHealth: 45,
		baseSpeed: 3 * 0.85,
		dodgeChance: 0
	}, {
		type: 'elite_shield',
		assetId: 'elite_shield_asset',
		description: 'Even higher health shield variant that is loyal to the king',
		baseHealth: 200,
		baseSpeed: 3 * 0.4,
		dodgeChance: 0
	}, {
		type: 'shaman',
		assetId: 'shaman_enemy',
		description: 'Reduces your ammo when he feels like it',
		baseHealth: 2,
		baseSpeed: 3 * 0.8,
		dodgeChance: 0
	}, {
		type: 'hot_air_balloon',
		assetId: 'hot_air_balloon_asset',
		description: 'Very low health. Spawns random non-green enemies on death.',
		baseHealth: 1,
		baseSpeed: 3 * 0.2,
		dodgeChance: 0
	}, {
		type: 'dark_bowman',
		assetId: 'dark_bowman_asset',
		description: 'Immune to arrows and cannonballs. Worst enemy of blue archers',
		baseHealth: 5,
		baseSpeed: 3 * 1.1,
		dodgeChance: 0
	}, {
		type: 'jester',
		assetId: 'jester_asset',
		description: 'High chance to dodge or reflect non-cannonball projectiles...YOU WILL LAUGH AT ALL OF HIS TRICKS',
		baseHealth: 2,
		baseSpeed: 3 * 1.1,
		dodgeChance: 0.3,
		// 30% dodge
		reflectChance: 0.2 // 20% reflect chance for non-cannonballs
	}, {
		type: 'dark_war_elephant',
		assetId: 'dark_war_elephant_asset',
		description: 'Immune to arrows. variant of green elephant, spawns Dark Bowmen on death.',
		baseHealth: 450,
		// Slightly less than green elephant
		baseSpeed: 3 * 0.3,
		// Same slow speed
		dodgeChance: 0
	}, {
		type: 'dark_spearman',
		assetId: 'dark_spearman_asset',
		description: 'A faster and more resistant spearman variant that came straight from rome. Immune to arrows and cannonballs',
		baseHealth: 15,
		// Base health
		baseSpeed: 3 * 1.2,
		// Faster than spearman
		dodgeChance: 0,
		tag: 'Black' // Immune to arrows and cannonballs
	}, {
		type: 'dragon',
		assetId: 'dragon_asset',
		description: 'A fearsome dragon with great HP and a high chance to dodge attacks. Cant be slowed down',
		baseHealth: 250,
		// Great HP
		baseSpeed: 3 * 0.9,
		// Moderately fast
		dodgeChance: 0.40,
		// High dodge chance (40%)
		tag: 'Dragon' // Special tag if needed for other mechanics, for now dodge is key
	}, {
		type: 'flag_bearer',
		assetId: 'flag_bearer_asset',
		description: 'Green-tagged enemy with an aura that makes nearby enemies move 50% faster',
		baseHealth: 5,
		baseSpeed: 3 * 0.8,
		dodgeChance: 0,
		tag: 'Green'
	}, {
		type: 'baby_dragon',
		assetId: 'baby_dragon_asset',
		description: 'Small dragon with less health but enters rage mode (double speed) when no other dragons are present',
		baseHealth: 50,
		baseSpeed: 3 * 1.1,
		dodgeChance: 0.25,
		tag: 'Dragon'
	}];
	// Clear any existing content in the list container
	while (enemyListContainer.children.length > 0) {
		enemyListContainer.removeChildAt(0);
	}
	// Current page tracking
	var currentEnemy = 0;
	var totalEnemies = enemyData.length;
	// Create enemy details display
	function displayEnemyDetails(index) {
		// Clear any existing content in the list container
		while (enemyListContainer.children.length > 0) {
			enemyListContainer.removeChildAt(0);
		}
		var enemyInfo = enemyData[index];
		// Enemy display container
		var enemyDisplay = new Container();
		enemyDisplay.y = 0;
		enemyListContainer.addChild(enemyDisplay);
		// Add enemy graphic (larger for individual view)
		var enemyGraphic = enemyDisplay.attachAsset(enemyInfo.assetId, {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: 0.8,
			scaleY: 0.8,
			x: -400,
			y: 50
		});
		// Add enemy name (larger font)
		var nameText = new Text2(enemyInfo.type.replace(/_/g, ' ').toUpperCase(), {
			size: 60,
			fill: 0xFFFFFF
		});
		nameText.anchor.set(0.5, 0);
		nameText.x = 0;
		nameText.y = -300;
		enemyDisplay.addChild(nameText);
		// Add description
		var descText = new Text2('Description: ' + enemyInfo.description, {
			size: 40,
			fill: 0xCCCCCC,
			wordWrap: true,
			wordWrapWidth: 1000
		});
		descText.anchor.set(0, 0);
		descText.x = -100;
		descText.y = -200;
		enemyDisplay.addChild(descText);
		// Add stats with improved layout
		var healthText = new Text2('Health: ' + enemyInfo.baseHealth, {
			size: 40,
			fill: 0x88FF88
		});
		healthText.anchor.set(0, 0);
		healthText.x = -100;
		healthText.y = -100;
		enemyDisplay.addChild(healthText);
		var speedText = new Text2('Speed: ' + enemyInfo.baseSpeed.toFixed(1), {
			size: 40,
			fill: 0x88CCFF
		});
		speedText.anchor.set(0, 0);
		speedText.x = -100;
		speedText.y = -40;
		enemyDisplay.addChild(speedText);
		var dodgeText = new Text2('Dodge Chance: ' + (enemyInfo.dodgeChance * 100).toFixed(0) + '%', {
			size: 40,
			fill: 0xFFCC88
		});
		dodgeText.anchor.set(0, 0);
		dodgeText.x = -100;
		dodgeText.y = 20;
		enemyDisplay.addChild(dodgeText);
		// Add reflect chance
		var reflectText = new Text2('Reflect Chance: ' + (enemyInfo.reflectChance * 100 || 0).toFixed(0) + '%', {
			size: 40,
			fill: 0xFFCCEE
		});
		reflectText.anchor.set(0, 0);
		reflectText.x = -100;
		reflectText.y = 80;
		enemyDisplay.addChild(reflectText);
		// Add unlock score
		var unlockScore = 0; // Default for swordsman
		if (enemyInfo.type === 'spearman') {
			unlockScore = 10;
		} else if (enemyInfo.type === 'thief') {
			unlockScore = 15;
		} else if (enemyInfo.type === 'knight') {
			unlockScore = 23;
		} else if (enemyInfo.type === 'wizard') {
			unlockScore = 25;
		} else if (enemyInfo.type === 'shield') {
			unlockScore = 30;
		} else if (enemyInfo.type === 'shaman') {
			unlockScore = 35;
		} else if (enemyInfo.type === 'dark_spearman') {
			unlockScore = 55;
		} // Dark Spearman unlock score
		else if (enemyInfo.type === 'dark_bowman') {
			unlockScore = 55;
		} // Note: Same as Dark Spearman, might need adjustment if only one is desired at 55. Keeping as per request.
		else if (enemyInfo.type === 'jester') {
			unlockScore = 69;
		} else if (enemyInfo.type === 'dragon') {
			unlockScore = 134;
		} // Dragon unlock score
		else if (enemyInfo.type === 'flag_bearer') {
			unlockScore = 27;
		} // Flag Bearer unlock score
		else if (enemyInfo.type === 'baby_dragon') {
			unlockScore = 125;
		} // Baby Dragon unlock score (same as war elephant)
		else if (enemyInfo.type === 'elite_knight') {
			unlockScore = 100;
		} else if (enemyInfo.type === 'elite_shield') {
			unlockScore = 112;
		} else if (enemyInfo.type === 'war_elephant') {
			unlockScore = 125;
		} else if (enemyInfo.type === 'dark_war_elephant') {
			unlockScore = 145;
		} // Dark war elephant starts appearing at score 145
		else if (enemyInfo.type === 'hot_air_balloon') {
			unlockScore = 154;
		}
		var unlockText = new Text2('Unlocks at Score: ' + unlockScore, {
			size: 40,
			fill: 0xFF88FF
		});
		unlockText.anchor.set(0, 0);
		unlockText.x = -100;
		unlockText.y = 140; // Adjusted Y position
		enemyDisplay.addChild(unlockText);
		// Status display (current enemy / total)
		var statusText = new Text2('Enemy ' + (index + 1) + ' of ' + totalEnemies, {
			size: 30,
			fill: 0xAAAAAA
		});
		statusText.anchor.set(0.5, 0);
		statusText.x = 0;
		statusText.y = 150;
		enemyDisplay.addChild(statusText);
		// Navigation buttons container
		var navButtons = new Container();
		navButtons.y = 250;
		enemyDisplay.addChild(navButtons);
		// Previous button
		var prevButton = createNavButton('← Previous', -250, function () {
			currentEnemy = (currentEnemy - 1 + totalEnemies) % totalEnemies;
			displayEnemyDetails(currentEnemy);
		});
		navButtons.addChild(prevButton);
		// Next button
		var nextButton = createNavButton('Next →', 250, function () {
			currentEnemy = (currentEnemy + 1) % totalEnemies;
			displayEnemyDetails(currentEnemy);
		});
		navButtons.addChild(nextButton);
	}
	// Create navigation button
	function createNavButton(label, xPos, callback) {
		var button = new Container();
		button.x = xPos;
		var buttonBg = button.attachAsset('bastionLine', {
			width: 250,
			height: 80,
			color: 0x555555,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 40,
			fill: 0xFFFFFF
		});
		buttonText.anchor.set(0.5, 0.5);
		button.addChild(buttonText);
		button.interactive = true;
		button.down = callback;
		return button;
	}
	// Initial display
	displayEnemyDetails(currentEnemy);
}
enemypediaButton = new Container();
// Position the button (e.g., bottom right of GUI)
enemypediaButton.x = GAME_WIDTH - 200; // Example X
enemypediaButton.y = GAME_HEIGHT - 200; // Example Y
// Add button background
var buttonBg = enemypediaButton.attachAsset('bastionLine', {
	// Reusing asset for shape
	width: 300,
	height: 100,
	color: 0x444444,
	// Grey color
	anchorX: 0.5,
	anchorY: 0.5
});
// Add button text
var buttonText = new Text2('Enemypedia', {
	size: 40,
	fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
enemypediaButton.addChild(buttonText);
// Make button interactive
enemypediaButton.interactive = true;
enemypediaButton.down = function () {
	showEnemypedia();
};
// Add the button to the game scene (or GUI if needed)
game.addChild(enemypediaButton);
// --- Relic Shop ---
var relicShopPopup = null;
var relicListContainer = null;
var goldText; // Text display for gold
function showRelicShop() {
	isUpgradePopupActive = true; // Pause the game
	relicShopPopup = new Container();
	relicShopPopup.x = GAME_WIDTH / 2;
	relicShopPopup.y = GAME_HEIGHT / 2;
	game.addChild(relicShopPopup);
	var bg = relicShopPopup.attachAsset('pedia_screen_bg', {
		width: 1600,
		height: 2000,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.9
	});
	var title = new Text2('Relic Shop', {
		size: 100,
		fill: 0xFFFFFF
	});
	title.anchor.set(0.5, 0.5);
	title.y = -900;
	relicShopPopup.addChild(title);
	var closeButton = createRelicShopCloseButton();
	closeButton.x = 750;
	closeButton.y = -900;
	relicShopPopup.addChild(closeButton);
	// Gold display
	goldText = new Text2('Gold: ' + playerGold, {
		size: 50,
		fill: 0xFFD700
	});
	goldText.anchor.set(0.5, 0.5);
	goldText.y = -800;
	relicShopPopup.addChild(goldText);
	relicListContainer = new Container();
	relicListContainer.y = -200;
	relicShopPopup.addChild(relicListContainer);
	displayRelicDetails();
}
function hideRelicShop() {
	if (relicShopPopup) {
		relicShopPopup.destroy();
		relicShopPopup = null;
	}
	isUpgradePopupActive = false; // Unpause the game
}
function createRelicShopCloseButton() {
	var buttonContainer = new Container();
	var buttonBg = buttonContainer.attachAsset('pedia_button_bg', {
		width: 150,
		height: 80,
		color: 0xCC0000,
		anchorX: 0.5,
		anchorY: 0.5
	});
	var buttonText = new Text2('X', {
		size: 60,
		fill: 0xFFFFFF
	});
	buttonText.anchor.set(0.5, 0.5);
	buttonContainer.addChild(buttonText);
	buttonContainer.interactive = true;
	buttonContainer.down = function () {
		hideRelicShop();
	};
	return buttonContainer;
}
function displayRelicDetails() {
	while (relicListContainer.children.length > 0) {
		relicListContainer.removeChildAt(0);
	}
	var relicsData = [{
		id: 'damage',
		name: 'Damage Relic',
		description: 'Increase projectile, swordsman, and poison damage.',
		effect: '+1 damage per level'
	}, {
		id: 'slowdown',
		name: 'Slowdown Relic',
		description: 'All enemies are slower.',
		effect: '+2% slowdown per level'
	}, {
		id: 'green',
		name: 'Green Relic',
		description: 'Green enemies are slower and take more damage.',
		effect: '+2% slow & +2% damage per level'
	}, {
		id: 'dark',
		name: 'Dark Relic',
		description: 'Dark enemies can be hit by arrows/cannonballs and take more damage from them.',
		effect: '+5% damage per level'
	}, {
		id: 'dragon',
		name: 'Dragon Relic',
		description: 'Projectiles stun dragons.',
		effect: '+0.05 seconds stun per level'
	}, {
		id: 'reload',
		name: 'Reload Relic',
		description: 'Reload faster! Essential for rapid-fire gameplay.',
		effect: '-0.5 seconds reload time per level'
	}, {
		id: 'ammo',
		name: 'Ammo Relic',
		description: 'Regenerate ammo over time without reloading.',
		effect: '+1 ammo regenerated every 5 seconds per level'
	}, {
		id: 'swordsman',
		name: 'Swordsman Relic',
		description: 'Start each battle with a permanent swordsman ally.',
		effect: 'Unlocks permanent swordsman, +2 damage per upgrade'
	}];
	// Current page tracking
	var currentRelic = 0;
	var totalRelics = relicsData.length;
	// Create relic details display
	function displayRelicItem(index) {
		// Clear any existing content in the list container
		while (relicListContainer.children.length > 0) {
			relicListContainer.removeChildAt(0);
		}
		var relic = relicsData[index];
		var relicInfo = playerRelics[relic.id];
		// Relic display container
		var relicDisplay = new Container();
		relicDisplay.y = 0;
		relicListContainer.addChild(relicDisplay);
		// Background
		var bg = relicDisplay.attachAsset('pedia_button_bg', {
			width: 1400,
			height: 400,
			color: 0x333355,
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Relic Name
		var nameText = new Text2(relic.name + ' (Level ' + relicInfo.level + '/' + RELIC_MAX_LEVEL + ')', {
			size: 70,
			fill: 0xFFFFFF
		});
		nameText.anchor.set(0.5, 0);
		nameText.x = 0;
		nameText.y = -300;
		relicDisplay.addChild(nameText);
		// Relic Description
		var descText = new Text2(relic.description, {
			size: 45,
			fill: 0xCCCCCC,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		descText.anchor.set(0.5, 0);
		descText.x = 0;
		descText.y = -200;
		relicDisplay.addChild(descText);
		// Relic Effect
		var effectText = new Text2('Effect: ' + relic.effect, {
			size: 40,
			fill: 0x88FF88,
			wordWrap: true,
			wordWrapWidth: 1200
		});
		effectText.anchor.set(0.5, 0);
		effectText.x = 0;
		effectText.y = -100;
		relicDisplay.addChild(effectText);
		// Buttons container
		var buttonsContainer = new Container();
		buttonsContainer.y = 0;
		relicDisplay.addChild(buttonsContainer);
		// Buy/Upgrade Button
		var buyButton = new Container();
		buyButton.x = -200;
		var buyBtnBgColor = relicInfo.level < RELIC_MAX_LEVEL ? 0x00CC00 : 0x666666;
		var buyBtnTextColor = relicInfo.level < RELIC_MAX_LEVEL ? 0xFFFFFF : 0xAAAAAA;
		var buyBtnBg = buyButton.attachAsset('pedia_nav_button_bg', {
			width: 200,
			height: 80,
			color: buyBtnBgColor,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buyBtnText = new Text2(relicInfo.level < RELIC_MAX_LEVEL ? 'Buy (5)' : 'MAX', {
			size: 40,
			fill: buyBtnTextColor
		});
		buyBtnText.anchor.set(0.5, 0.5);
		buyButton.addChild(buyBtnText);
		buyButton.interactive = relicInfo.level < RELIC_MAX_LEVEL && playerGold >= RELIC_COST_PER_LEVEL;
		if (buyButton.interactive) {
			buyButton.down = function (relicId) {
				return function () {
					if (playerGold >= RELIC_COST_PER_LEVEL && playerRelics[relicId].level < RELIC_MAX_LEVEL) {
						playerGold -= RELIC_COST_PER_LEVEL;
						playerRelics[relicId].level++;
						storage.playerGold = playerGold;
						// Reset ammo relic timer if ammo relic was upgraded
						if (relicId === 'ammo') {
							ammoRelicTimer = 0; // Reset timer when upgrading
						}
						// Save relics to storage using safe serialization
						try {
							var relicsData = {};
							relicsData.damage_level = playerRelics.damage.level;
							relicsData.damage_enabled = playerRelics.damage.enabled;
							relicsData.slowdown_level = playerRelics.slowdown.level;
							relicsData.slowdown_enabled = playerRelics.slowdown.enabled;
							relicsData.green_level = playerRelics.green.level;
							relicsData.green_enabled = playerRelics.green.enabled;
							relicsData.dark_level = playerRelics.dark.level;
							relicsData.dark_enabled = playerRelics.dark.enabled;
							relicsData.dragon_level = playerRelics.dragon.level;
							relicsData.dragon_enabled = playerRelics.dragon.enabled;
							relicsData.reload_level = playerRelics.reload.level;
							relicsData.reload_enabled = playerRelics.reload.enabled;
							relicsData.ammo_level = playerRelics.ammo.level;
							relicsData.ammo_enabled = playerRelics.ammo.enabled;
							relicsData.swordsman_level = playerRelics.swordsman.level;
							relicsData.swordsman_enabled = playerRelics.swordsman.enabled;
							storage.playerRelicsData = relicsData;
						} catch (e) {
							console.log("Error saving relics:", e);
						}
						goldText.setText('Gold: ' + playerGold);
						displayRelicItem(currentRelic); // Refresh the current relic display
					}
				};
			}(relic.id);
		}
		buttonsContainer.addChild(buyButton);
		// On/Off Button
		var toggleButton = new Container();
		toggleButton.x = 200;
		var toggleBtnBgColor = relicInfo.enabled ? 0x008800 : 0x880000;
		var toggleBtnBg = toggleButton.attachAsset('pedia_nav_button_bg', {
			width: 150,
			height: 80,
			color: toggleBtnBgColor,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var toggleBtnText = new Text2(relicInfo.enabled ? 'ON' : 'OFF', {
			size: 40,
			fill: 0xFFFFFF
		});
		toggleBtnText.anchor.set(0.5, 0.5);
		toggleButton.addChild(toggleBtnText);
		toggleButton.interactive = relicInfo.level > 0; // Only interactive if relic is owned
		if (toggleButton.interactive) {
			toggleButton.down = function (relicId) {
				return function () {
					playerRelics[relicId].enabled = !playerRelics[relicId].enabled;
					// Reset ammo relic timer if ammo relic was toggled
					if (relicId === 'ammo') {
						ammoRelicTimer = 0; // Reset timer when toggling
					}
					// Save relics to storage using safe serialization
					try {
						var relicsData = {};
						relicsData.damage_level = playerRelics.damage.level;
						relicsData.damage_enabled = playerRelics.damage.enabled;
						relicsData.slowdown_level = playerRelics.slowdown.level;
						relicsData.slowdown_enabled = playerRelics.slowdown.enabled;
						relicsData.green_level = playerRelics.green.level;
						relicsData.green_enabled = playerRelics.green.enabled;
						relicsData.dark_level = playerRelics.dark.level;
						relicsData.dark_enabled = playerRelics.dark.enabled;
						relicsData.dragon_level = playerRelics.dragon.level;
						relicsData.dragon_enabled = playerRelics.dragon.enabled;
						relicsData.reload_level = playerRelics.reload.level;
						relicsData.reload_enabled = playerRelics.reload.enabled;
						relicsData.ammo_level = playerRelics.ammo.level;
						relicsData.ammo_enabled = playerRelics.ammo.enabled;
						relicsData.swordsman_level = playerRelics.swordsman.level;
						relicsData.swordsman_enabled = playerRelics.swordsman.enabled;
						storage.playerRelicsData = relicsData;
					} catch (e) {
						console.log("Error saving relics:", e);
					}
					displayRelicItem(currentRelic); // Refresh the current relic display
				};
			}(relic.id);
		} else {
			toggleBtnBg.tint = 0x666666; // Grey out if not owned
		}
		buttonsContainer.addChild(toggleButton);
		// Status display (current relic / total)
		var statusText = new Text2('Relic ' + (index + 1) + ' of ' + totalRelics, {
			size: 35,
			fill: 0xAAAAAA
		});
		statusText.anchor.set(0.5, 0);
		statusText.x = 0;
		statusText.y = 150;
		relicDisplay.addChild(statusText);
		// Navigation buttons container
		var navButtons = new Container();
		navButtons.y = 250;
		relicDisplay.addChild(navButtons);
		// Previous button
		var prevButton = createRelicNavButton('← Previous', -250, function () {
			currentRelic = (currentRelic - 1 + totalRelics) % totalRelics;
			displayRelicItem(currentRelic);
		});
		navButtons.addChild(prevButton);
		// Next button
		var nextButton = createRelicNavButton('Next →', 250, function () {
			currentRelic = (currentRelic + 1) % totalRelics;
			displayRelicItem(currentRelic);
		});
		navButtons.addChild(nextButton);
	}
	function createRelicNavButton(label, xPos, callback) {
		var button = new Container();
		button.x = xPos;
		var buttonBg = button.attachAsset('pedia_nav_button_bg', {
			width: 250,
			height: 80,
			anchorX: 0.5,
			anchorY: 0.5
		});
		var buttonText = new Text2(label, {
			size: 40,
			fill: 0xFFFFFF
		});
		buttonText.anchor.set(0.5, 0.5);
		button.addChild(buttonText);
		button.interactive = true;
		button.down = callback;
		return button;
	}
	// Initial display
	displayRelicItem(currentRelic);
}
// --- Input Event Handlers ---
// Handles touch/mouse press down event on the game area.
game.down = function (x, y, obj) {
	// Record the starting position of the drag in game coordinates.
	var gamePos = game.toLocal({
		x: x,
		y: y
	});
	dragStartX = gamePos.x;
	dragStartY = gamePos.y;
	// Potential enhancement: Show an aiming indicator originating from FIRING_POS_X, FIRING_POS_Y towards the drag point.
};
// Handles touch/mouse move event while dragging on the game area.
game.move = function (x, y, obj) {
	// Only process if a drag is currently active.
	if (dragStartX !== null) {
		var gamePos = game.toLocal({
			x: x,
			y: y
		});
		// Potential enhancement: Update the aiming indicator based on the current drag position (gamePos).
	}
};
// Handles touch/mouse release event on the game area.
game.up = function (x, y, obj) {
	// Only process if a drag was active.
	if (dragStartX !== null && cooldownTimer <= 0) {
		// Only allow firing if not on cooldown.
		var gamePos = game.toLocal({
			x: x,
			y: y
		});
		var dragEndX = gamePos.x;
		var dragEndY = gamePos.y;
		// Calculate the difference between the firing position and the release point to determine direction.
		// A longer drag could potentially mean more power, but we'll keep it simple: direction only.
		var dx = dragEndX - FIRING_POS_X;
		var dy = dragEndY - FIRING_POS_Y;
		// Avoid division by zero or zero vector if start and end points are the same.
		if (dx === 0 && dy === 0) {
			// Optionally handle this case, e.g., fire straight up or do nothing.
			// Let's fire straight up if drag distance is negligible.
			dy = -1;
		}
		// Calculate the angle using atan2. Note the order (dx, dy) and the negation of dy
		// because the Y-axis is inverted in screen coordinates (positive Y is down).
		var angle = Math.atan2(dx, -dy);
		// Create a new arrow instance with the calculated angle.
		var newArrow = new Arrow(angle);
		newArrow.x = FIRING_POS_X;
		newArrow.y = FIRING_POS_Y;
		// Initialize last position for state tracking (e.g., off-screen detection)
		newArrow.lastY = newArrow.y;
		newArrow.lastX = newArrow.x;
		// Add the arrow to the game scene and the tracking array.
		game.addChild(newArrow);
		arrows.push(newArrow);
		if (multiShotEnabled) {
			// Fire a second arrow with a slight angle offset
			var angle2 = angle + Math.PI / 12; // Offset by 15 degrees
			var newArrow2 = new Arrow(angle2);
			newArrow2.x = FIRING_POS_X;
			newArrow2.y = FIRING_POS_Y;
			newArrow2.lastY = newArrow2.y;
			newArrow2.lastX = newArrow2.x;
			game.addChild(newArrow2);
			arrows.push(newArrow2);
			// Fire a third arrow with the opposite angle offset
			var angle3 = angle - Math.PI / 12; // Offset by -15 degrees
			var newArrow3 = new Arrow(angle3);
			newArrow3.x = FIRING_POS_X;
			newArrow3.y = FIRING_POS_Y;
			newArrow3.lastY = newArrow3.y;
			newArrow3.lastX = newArrow3.x;
			game.addChild(newArrow3);
			arrows.push(newArrow3);
		}
		LK.getSound('shoot').play(); // Play shooting sound.
		arrowsFired++; // Increment arrow count.
		ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired)); // Update ammo display.
		// Check if cooldown needs to start based on Quiver upgrade
		if (arrowsFired >= maxArrowsBeforeCooldown) {
			var effectiveCooldownDuration = cooldownDuration;
			// Apply reload relic bonus if enabled
			if (playerRelics.reload.enabled) {
				effectiveCooldownDuration = Math.max(30, cooldownDuration - playerRelics.reload.level * 30); // 0.5 seconds faster per level, min 0.5s
			}
			cooldownTimer = effectiveCooldownDuration; // Start cooldown (duration affected by Faster Reload upgrade and reload relic)
			arrowsFired = 0; // Reset arrow count.
			ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired)); // Update ammo display.
			LK.getSound('Reload').play(); // Play reload sound.
		}
		// Reset drag state.
		dragStartX = null;
		dragStartY = null;
		// Potential enhancement: Hide the aiming indicator.
	}
};
// --- Main Game Update Loop ---
// This function is called automatically by the LK engine on every frame (tick).
game.update = function () {
	// --- Upgrade System Check ---
	var currentScore = LK.getScore();
	// Check if score reached a multiple of 10 and is higher than the last upgrade score
	if (!isUpgradePopupActive && currentScore > 0 && currentScore % 10 === 0 && currentScore !== lastUpgradeScore) {
		lastUpgradeScore = currentScore; // Mark this score level as having triggered an upgrade offer
		showUpgradePopup(); // Show the upgrade selection screen
	}
	// --- Pause Game Logic if Upgrade Popup is Active ---
	if (isUpgradePopupActive) {
		// Potential: Update UI animations if any
		return; // Skip the rest of the game update loop
	}
	// --- Resume Game Logic ---
	if (isUpgradePopupActive) {
		return; // Skip enemy movement and spawning if upgrade popup is active
	}
	// Handle ammo relic regeneration
	if (playerRelics.ammo.enabled && playerRelics.ammo.level > 0) {
		ammoRelicTimer++;
		// Give ammo every 5 seconds (300 ticks)
		if (ammoRelicTimer >= 300) {
			ammoRelicTimer = 0;
			// Only regenerate if not at max ammo and not reloading
			if (arrowsFired > 0 && cooldownTimer <= 0) {
				// Give ammo based on relic level (1 per level)
				var ammoToRegenerate = playerRelics.ammo.level;
				arrowsFired = Math.max(0, arrowsFired - ammoToRegenerate);
				ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired));
			}
		}
	}
	// Decrease cooldown timer if active.
	if (cooldownTimer > 0) {
		cooldownTimer--;
		ammoTxt.setText('Reloading...'); // Show reloading status
	} else if (ammoTxt.text !== 'Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired)) {
		// Ensure ammo display is correct if not reloading
		ammoTxt.setText('Ammo: ' + (maxArrowsBeforeCooldown - arrowsFired));
	}
	// 1. Update and check Arrows
	for (var i = arrows.length - 1; i >= 0; i--) {
		var arrow = arrows[i];
		// Note: LK engine calls arrow.update() automatically as it's added to the game stage.
		// Initialize last position if it hasn't been set yet (first frame).
		if (arrow.lastY === undefined) {
			arrow.lastY = arrow.y;
		}
		if (arrow.lastX === undefined) {
			arrow.lastX = arrow.x;
		}
		// Check for collisions between the current arrow and all enemies.
		var hitEnemy = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			// Use the intersects method for collision detection.
			if (arrow.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Calculate damage, applying Green Killer bonus if applicable
				var damageToDeal = arrow.damage;
				if (greenKillerEnabled && enemy.tag === 'Green') {
					damageToDeal *= 1.5; // Apply 50% damage bonus
				}
				// Apply damage to the enemy and check if it was defeated
				var enemyDefeated = enemy.takeDamage(damageToDeal, arrow); // Pass the arrow object as source
				// Check if the arrow was reflected (takeDamage returns false and arrow is destroyed)
				if (!enemyDefeated && !arrow.parent) {
					// Arrow was reflected, remove it from the array and stop processing
					arrows.splice(i, 1);
					hitEnemy = true; // Mark that this arrow is done
					break; // Stop checking this arrow against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Handle arrow piercing
				arrow.pierceLeft--; // Decrease remaining pierces
				if (arrow.pierceLeft <= 0) {
					// Arrow has no pierces left, destroy it
					arrow.destroy();
					arrows.splice(i, 1); // Remove arrow from array.
					hitEnemy = true; // Mark that this arrow is done
					break; // Stop checking this arrow against other enemies as it's destroyed
				} else {
					// Arrow pierced this enemy and can continue
					// We don't set hitEnemy = true here because the arrow continues
					// We don't break because it might hit another enemy in the same frame further along its path
					// Apply Green Slowdown if applicable and arrow is still piercing
					if (!enemyDefeated && greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
						enemy.slowTimer = 10 * 60;
						enemy.currentSlowAmount = 0.9;
					}
				}
			}
		}
		// If the arrow hit an enemy, it was destroyed, so skip to the next arrow.
		if (hitEnemy) {
			continue;
		}
		// Check if the arrow has gone off-screen (top, left, or right).
		// Use transition detection: check if it was on screen last frame and is off screen now.
		var wasOnScreen = arrow.lastY > -arrow.height / 2 && arrow.lastX > -arrow.width / 2 && arrow.lastX < GAME_WIDTH + arrow.width / 2;
		var isOffScreen = arrow.y < -arrow.height / 2 ||
		// Off top edge
		arrow.x < -arrow.width / 2 ||
		// Off left edge
		arrow.x > GAME_WIDTH + arrow.width / 2; // Off right edge
		if (wasOnScreen && isOffScreen) {
			// Arrow is off-screen, destroy it and remove from the array.
			arrow.destroy();
			arrows.splice(i, 1);
		} else if (!isOffScreen) {
			// Update last known position only if the arrow is still potentially on screen
			arrow.lastY = arrow.y;
			arrow.lastX = arrow.x;
		}
	}
	// 2. Update and check Cannonballs
	for (var cb = cannonballs.length - 1; cb >= 0; cb--) {
		var cannonball = cannonballs[cb];
		// Note: LK engine calls cannonball.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (cannonball.lastY === undefined) {
			cannonball.lastY = cannonball.y;
		}
		if (cannonball.lastX === undefined) {
			cannonball.lastX = cannonball.x;
		}
		// Check for collisions between the current cannonball and all enemies.
		var hitEnemy = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			// Use the intersects method for collision detection.
			if (cannonball.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Apply damage to the enemy and check if it was defeated
				var damageToApply = cannonball.damage;
				// Apply dragon slayer damage multiplier if applicable
				if (cannonball.dragonDamageMultiplier && enemy.tag === 'Dragon') {
					damageToApply *= cannonball.dragonDamageMultiplier;
				}
				var enemyDefeated = enemy.takeDamage(damageToApply, cannonball); // Pass cannonball as source
				// Check if the cannonball had no effect (e.g. Dark War Elephant immunity) and is still in game
				if (!enemyDefeated && cannonball.parent) {
					// Cannonball had no effect, but wasn't destroyed by a normal hit.
					// It might have been immune. If so, we still destroy the cannonball.
					cannonball.destroy();
					cannonballs.splice(cb, 1);
					hitEnemy = true; // Mark that this cannonball is done
					break; // Stop checking this cannonball against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Cannonballs are destroyed on hit
				cannonball.destroy();
				// Apply Green Slowdown if applicable before destroying cannonball
				if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
					enemy.slowTimer = 10 * 60;
					enemy.currentSlowAmount = 0.9;
				}
				cannonball.destroy();
				cannonballs.splice(cb, 1); // Remove cannonball from array.
				hitEnemy = true; // Mark that this cannonball is done
				break; // Stop checking this cannonball against other enemies as it's destroyed
			}
		}
		// If the cannonball hit an enemy, it was destroyed, so skip to the next cannonball.
		if (hitEnemy) {
			continue;
		}
		// Check if the cannonball has gone off-screen.
		var wasOnScreen = cannonball.lastY > -cannonball.height / 2 && cannonball.lastX > -cannonball.width / 2 && cannonball.lastX < GAME_WIDTH + cannonball.width / 2;
		var isOffScreen = cannonball.y < -cannonball.height / 2 ||
		// Off top edge
		cannonball.x < -cannonball.width / 2 ||
		// Off left edge
		cannonball.x > GAME_WIDTH + cannonball.width / 2; // Off right edge
		if (wasOnScreen && isOffScreen) {
			// Cannonball is off-screen, destroy it and remove from the array.
			cannonball.destroy();
			cannonballs.splice(cb, 1);
		} else if (!isOffScreen) {
			// Update last known position only if the cannonball is still potentially on screen
			cannonball.lastY = cannonball.y;
			cannonball.lastX = cannonball.x;
		}
	}
	// 3. Update and check Enemies
	for (var k = enemies.length - 1; k >= 0; k--) {
		var enemy = enemies[k];
		// Note: LK engine calls enemy.update() automatically.
		// Initialize last position if not set.
		if (enemy.lastY === undefined) {
			enemy.lastY = enemy.y;
		}
		// Check if the enemy has reached or passed the bastion line.
		// Use transition detection: was the enemy's bottom edge above the line last frame,
		// and is it on or below the line now?
		var enemyBottomY = enemy.y + enemy.height / 2;
		var enemyLastBottomY = enemy.lastY + enemy.height / 2;
		var wasAboveBastion = enemyLastBottomY < BASTION_Y;
		var isAtOrBelowBastion = enemyBottomY >= BASTION_Y;
		if (wasAboveBastion && isAtOrBelowBastion) {
			// Enemy reached the bastion! Game Over.
			LK.getSound('gameOverSfx').play(); // Play game over sound effect.
			LK.showGameOver(); // Trigger the engine's game over sequence.
			// Calculate gold earned
			var goldEarned = Math.floor(currentScore / 5);
			playerGold += goldEarned;
			storage.playerGold = playerGold; // Save gold to storage
			// Save relics to storage using safe serialization
			try {
				var relicsData = {};
				relicsData.damage_level = playerRelics.damage.level;
				relicsData.damage_enabled = playerRelics.damage.enabled;
				relicsData.slowdown_level = playerRelics.slowdown.level;
				relicsData.slowdown_enabled = playerRelics.slowdown.enabled;
				relicsData.green_level = playerRelics.green.level;
				relicsData.green_enabled = playerRelics.green.enabled;
				relicsData.dark_level = playerRelics.dark.level;
				relicsData.dark_enabled = playerRelics.dark.enabled;
				relicsData.dragon_level = playerRelics.dragon.level;
				relicsData.dragon_enabled = playerRelics.dragon.enabled;
				relicsData.reload_level = playerRelics.reload.level;
				relicsData.reload_enabled = playerRelics.reload.enabled;
				relicsData.ammo_level = playerRelics.ammo.level;
				relicsData.ammo_enabled = playerRelics.ammo.enabled;
				relicsData.swordsman_level = playerRelics.swordsman.level;
				relicsData.swordsman_enabled = playerRelics.swordsman.enabled;
				storage.playerRelicsData = relicsData;
			} catch (e) {
				console.log("Error saving relics:", e);
			}
			console.log("Game Over! Earned " + goldEarned + " gold. Total gold: " + playerGold);
			// LK.showGameOver handles game state reset, no need to manually clear arrays here.
			return; // Exit the update loop immediately as the game is over.
		} else {
			// Update last known position if game is not over for this enemy.
			enemy.lastY = enemy.y;
		}
	}
	// 3. Update and check Swordsmen (allies)
	for (var l = swordsmen.length - 1; l >= 0; l--) {
		var swordsman = swordsmen[l];
		// Swordsman update method handles its own lifetime and attacking
		// Check if the swordsman has been destroyed by its lifetime timer
		if (!swordsman.parent) {
			// If it no longer has a parent, it has been destroyed
			swordsmen.splice(l, 1); // Remove swordsman from array
		}
	}
	// 4. Update and check Cannons (allies)
	for (var m = cannons.length - 1; m >= 0; m--) {
		var cannon = cannons[m];
		// Cannons do not have a lifetime timer or destruction logic in this basic version
		// If they had, we'd check !cannon.parent and splice here as in Swordsmen
	}
	// 5. Update and check Wizard Towers (allies)
	for (var wt = wizardTowers.length - 1; wt >= 0; wt--) {
		var tower = wizardTowers[wt];
		// Wizard towers do not have a lifetime timer or destruction logic in this basic version
		// If they had, we'd check !tower.parent and splice here
	}
	// 5.5 Update and check Viking Allies
	for (var va = vikingAllies.length - 1; va >= 0; va--) {
		var viking = vikingAllies[va];
		// Vikings do not have a lifetime timer or destruction logic in this version
		// LK engine calls viking.update() automatically.
	}
	// 5.6 Update and check Angel of Lights (allies)
	for (var angelIdx = angelOfLights.length - 1; angelIdx >= 0; angelIdx--) {
		var angel = angelOfLights[angelIdx];
		// Angels do not have a lifetime timer or destruction logic in this version
		// LK engine calls angel.update() automatically.
	}
	// 5.7 Update and check Bouncy Balls
	for (var bbIdx = bouncyBalls.length - 1; bbIdx >= 0; bbIdx--) {
		var ball = bouncyBalls[bbIdx];
		// LK engine calls ball.update() automatically.
		// Check for collisions with enemies
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (ball.intersects(enemy)) {
				// Apply damage
				var enemyDefeated = enemy.takeDamage(ball.damage, ball);
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1);
					scoreTxt.setText(LK.getScore());
					enemy.destroy();
					enemies.splice(j, 1);
				}
				// Bouncy ball doesn't get destroyed on hit
				LK.effects.flashObject(enemy, 0xFF00FF, 300);
			}
		}
		// Check if ball was destroyed by lifetime
		if (!ball.parent) {
			bouncyBalls.splice(bbIdx, 1);
		}
	}
	// 5.8 Update and check Bombs
	for (var bombIdx = bombs.length - 1; bombIdx >= 0; bombIdx--) {
		var bomb = bombs[bombIdx];
		// LK engine calls bomb.update() automatically.
		// Check if bomb was destroyed after explosion
		if (!bomb.parent) {
			bombs.splice(bombIdx, 1);
		}
	}
	// 5.9 Update and check Bombers
	for (var bomberIdx = bombers.length - 1; bomberIdx >= 0; bomberIdx--) {
		var bomber = bombers[bomberIdx];
		// LK engine calls bomber.update() automatically.
	}
	// 5.10 Update and check XBOWs
	for (var xbowIdx = xbows.length - 1; xbowIdx >= 0; xbowIdx--) {
		var xbow = xbows[xbowIdx];
		// LK engine calls xbow.update() automatically.
	}
	// 6. Update and check Magic Balls
	for (var mb = magicBalls.length - 1; mb >= 0; mb--) {
		var magicBall = magicBalls[mb];
		// Note: LK engine calls magicBall.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (magicBall.lastY === undefined) {
			magicBall.lastY = magicBall.y;
		}
		if (magicBall.lastX === undefined) {
			magicBall.lastX = magicBall.x;
		}
		// Check for collisions between the current magic ball and all enemies.
		var hitEnemy = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			// Use the intersects method for collision detection.
			if (magicBall.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Apply damage (minimal) and slowdown effect to the enemy and check if it was defeated
				var enemyDefeated = enemy.takeDamage(magicBall.damage, magicBall); // Pass the magic ball object as source
				// Check if the magic ball was reflected (takeDamage returns false and magicBall is destroyed)
				if (!enemyDefeated && !magicBall.parent) {
					// Magic ball was reflected, remove it from the array and stop processing
					magicBalls.splice(mb, 1);
					hitEnemy = true; // Mark that this magic ball is done
					break; // Stop checking this magic ball against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					// Destroy the enemy
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Magic balls are destroyed on hit
				magicBall.destroy();
				// Apply Green Slowdown if applicable before destroying magic ball
				if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
					// Note: Enemy.takeDamage already checks for MagicBall source to apply its default slow.
					// This adds the Green Slowdown effect *on top* if applicable and not already slowed.
					// However, takeDamage applies slow based on MagicBall properties. Let's apply Green Slowdown here explicitly.
					enemy.slowTimer = 10 * 60; // 10 seconds
					enemy.currentSlowAmount = 0.9; // 10% slow
				}
				magicBall.destroy();
				magicBalls.splice(mb, 1); // Remove magic ball from array.
				hitEnemy = true; // Mark that this magic ball is done
				break; // Stop checking this magic ball against other enemies as it's destroyed
			}
		}
		// If the magic ball hit an enemy, it was destroyed, so skip to the next magic ball.
		if (hitEnemy) {
			continue;
		}
		// Check if the magic ball has gone off-screen.
		var wasOnScreen = magicBall.lastY > -magicBall.height / 2 && magicBall.lastX > -magicBall.width / 2 && magicBall.lastX < GAME_WIDTH + magicBall.width / 2;
		var isOffScreen = magicBall.y < -magicBall.height / 2 ||
		// Off top edge
		magicBall.x < -magicBall.width / 2 ||
		// Off left edge
		magicBall.x > GAME_WIDTH + magicBall.width / 2; // Off right edge
		if (wasOnScreen && isOffScreen) {
			// Magic ball is off-screen, destroy it and remove from the array.
			magicBall.destroy();
			magicBalls.splice(mb, 1);
		} else if (!isOffScreen) {
			// Update last known position only if the magic ball is still potentially on screen
			magicBall.lastY = magicBall.y;
			magicBall.lastX = magicBall.x;
		}
	}
	// 6.5 Update and check Viking Axes
	for (var axeIdx = vikingAxes.length - 1; axeIdx >= 0; axeIdx--) {
		var axe = vikingAxes[axeIdx];
		// Note: LK engine calls axe.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (axe.lastY === undefined) {
			axe.lastY = axe.y;
		}
		if (axe.lastX === undefined) {
			axe.lastX = axe.x;
		}
		// Check for collisions between the current axe and all enemies.
		var hitEnemyAxe = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (axe.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Apply Green Killer bonus if applicable (Vikings benefit too)
				var damageToDealAxe = axe.damage;
				if (greenKillerEnabled && enemy.tag === 'Green') {
					damageToDealAxe *= 1.5; // Apply 50% damage bonus
				}
				// Apply damage and check if defeated
				var enemyDefeated = enemy.takeDamage(damageToDealAxe, axe); // Pass axe as source for potential effects
				// Check if the axe was reflected (takeDamage returns false and axe is destroyed)
				if (!enemyDefeated && !axe.parent) {
					// Axe was reflected, remove it from the array and stop processing
					vikingAxes.splice(axeIdx, 1);
					hitEnemyAxe = true; // Mark that this axe is done
					break; // Stop checking this axe against other enemies as it's destroyed
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Handle axe piercing
				axe.pierceLeft--; // Decrease remaining pierces
				if (axe.pierceLeft <= 0) {
					// Axe has no pierces left, destroy it
					axe.destroy();
					vikingAxes.splice(axeIdx, 1); // Remove axe from array.
					hitEnemyAxe = true; // Mark that this axe is done
					break; // Stop checking this axe against other enemies
				} else {
					// Axe pierced this enemy and can continue
					// Potentially apply Green Slowdown if enabled
					if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
						enemy.slowTimer = 10 * 60;
						enemy.currentSlowAmount = 0.9;
					}
				}
			}
		}
		// If the axe hit and was destroyed, skip to the next axe.
		if (hitEnemyAxe) {
			continue;
		}
		// Check if the axe has gone off-screen.
		var wasOnScreenAxe = axe.lastY > -axe.height / 2 && axe.lastX > -axe.width / 2 && axe.lastX < GAME_WIDTH + axe.width / 2;
		var isOffScreenAxe = axe.y < -axe.height / 2 || axe.y > GAME_HEIGHT + axe.height / 2 || axe.x < -axe.width / 2 || axe.x > GAME_WIDTH + axe.width / 2;
		if (wasOnScreenAxe && isOffScreenAxe) {
			axe.destroy();
			vikingAxes.splice(axeIdx, 1);
		} else if (!isOffScreenAxe) {
			axe.lastY = axe.y;
			axe.lastX = axe.x;
		}
	}
	// 6.6 Update and check Darts
	for (var dartIdx = darts.length - 1; dartIdx >= 0; dartIdx--) {
		var dart = darts[dartIdx];
		// Note: LK engine calls dart.update() automatically.
		// Initialize last position if it hasn't been set yet (first frame).
		if (dart.lastY === undefined) {
			dart.lastY = dart.y;
		}
		if (dart.lastX === undefined) {
			dart.lastX = dart.x;
		}
		// Check for collisions between the current dart and all enemies.
		var hitEnemyDart = false;
		for (var j = enemies.length - 1; j >= 0; j--) {
			var enemy = enemies[j];
			if (dart.intersects(enemy)) {
				// Collision detected!
				LK.getSound('hit').play(); // Play hit sound.
				// Calculate damage, applying bonus against Green enemies
				var damageToDealDart = dart.damage;
				var greenDamageMultiplier = 2; // Base multiplier for darts vs Green enemies
				// Apply Green Relic damage bonus if enabled and enemy is Green-tagged
				if (playerRelics.green.enabled && enemy.tag === 'Green') {
					greenDamageMultiplier += playerRelics.green.level * 0.02; // Additional damage multiplier from relic
				}
				if (enemy.tag === 'Green') {
					damageToDealDart *= greenDamageMultiplier; // Apply calculated multiplier
				}
				// Apply damage and check if defeated
				var enemyDefeated = enemy.takeDamage(damageToDealDart, dart); // Pass dart as source
				// Check if the dart was reflected (takeDamage returns false and dart is destroyed)
				if (!enemyDefeated && !dart.parent) {
					// Dart was reflected, remove it from the array and stop processing
					darts.splice(dartIdx, 1);
					hitEnemyDart = true; // Mark that this dart is done
					break; // Stop checking this dart against other enemies
				}
				if (enemyDefeated) {
					LK.setScore(LK.getScore() + 1); // Increment score.
					scoreTxt.setText(LK.getScore()); // Update score display.
					enemy.destroy();
					enemies.splice(j, 1); // Remove enemy from array.
				}
				// Darts are destroyed on hit
				dart.destroy();
				// Apply Green Slowdown if applicable before destroying dart
				if (greenSlowdownEnabled && enemy.tag === 'Green' && enemy.slowTimer <= 0) {
					enemy.slowTimer = 10 * 60;
					enemy.currentSlowAmount = 0.9;
				}
				darts.splice(dartIdx, 1); // Remove dart from array.
				hitEnemyDart = true; // Mark that this dart is done
				break; // Stop checking this dart against other enemies
			}
		}
		// If the dart hit and was destroyed, skip to the next dart.
		if (hitEnemyDart) {
			continue;
		}
		// Check if the dart has gone off-screen.
		var wasOnScreenDart = dart.lastY > -dart.height / 2 && dart.lastX > -dart.width / 2 && dart.lastX < GAME_WIDTH + dart.width / 2;
		var isOffScreenDart = dart.y < -dart.height / 2 || dart.y > GAME_HEIGHT + dart.height / 2 || dart.x < -dart.width / 2 || dart.x > GAME_WIDTH + dart.width / 2;
		if (wasOnScreenDart && isOffScreenDart) {
			dart.destroy();
			darts.splice(dartIdx, 1);
		} else if (!isOffScreenDart) {
			dart.lastY = dart.y;
			dart.lastX = dart.x;
		}
	}
	// 7. Spawn new Enemies periodically
	// Use LK.ticks and the spawn interval. Ensure interval doesn't go below minimum.
	if (LK.ticks % Math.max(minEnemySpawnInterval, Math.floor(enemySpawnInterval)) === 0) {
		var currentScore = LK.getScore();
		var baseSpeedForSpawn = Math.min(maxEnemySpeed, currentEnemySpeed); // Base speed adjusted by game difficulty progression
		// Determine if this spawn *could* be a boss (e.g., every 7th spawn after score 10)
		var potentialBoss = (enemies.length + 1) % 7 === 0 && currentScore >= 10;
		var typeToSpawn = 'swordsman'; // Default type
		var enemyHealth = 1; // Default health
		var enemyDodgeChance = 0; // Default dodge chance
		var enemySpeed = baseSpeedForSpawn; // Start with base speed
		// Determine base type based on score thresholds and randomness
		var possibleTypes = ['swordsman'];
		if (currentScore >= 10) {
			possibleTypes.push('spearman');
		}
		if (currentScore >= 15) {
			possibleTypes.push('thief');
		}
		if (currentScore >= 23) {
			possibleTypes.push('knight');
		}
		if (currentScore >= 25) {
			possibleTypes.push('wizard');
		} // Wizards start appearing at score 25
		if (currentScore >= 30) {
			possibleTypes.push('shield');
		} // Shields start appearing at score 30
		if (currentScore >= 35) {
			possibleTypes.push('shaman'); // Shaman appears at score 35
			console.log("Shaman added to possible enemy types");
		}
		if (currentScore >= 55) {
			possibleTypes.push('dark_bowman'); // Dark bowman appears at score 55
			possibleTypes.push('dark_spearman'); // Dark Spearman appears at score 55
		}
		if (currentScore >= 69) {
			possibleTypes.push('jester'); // Jester appears at score 69
		}
		if (currentScore >= 100) {
			possibleTypes.push('elite_knight'); // Elite Knights start appearing at score 100
		}
		if (currentScore >= 134) {
			possibleTypes.push('dragon'); // Dragon appears at score 134
		}
		if (currentScore >= 112) {
			possibleTypes.push('elite_shield'); // Elite Shields appear at score 112
		}
		if (currentScore >= 125) {
			// War Elephant appears at score 125
			possibleTypes.push('war_elephant');
			// Baby Dragon also appears at score 125 (same as war elephant)
			possibleTypes.push('baby_dragon');
		}
		if (currentScore >= 145) {
			possibleTypes.push('dark_war_elephant'); // Dark War Elephant appears at score 145
		}
		if (currentScore >= 154) {
			// Hot Air Balloon appears at score 100
			possibleTypes.push('hot_air_balloon');
		}
		if (currentScore >= 27) {
			possibleTypes.push('flag_bearer'); // Flag Bearer appears at score 27
		}
		// Check if Battle Horn is active - if so, make half of spawns swordsmen, rest random
		if (battleHornEnabled) {
			// 50% chance to force swordsman, 50% chance to pick random
			if (Math.random() < 0.5) {
				typeToSpawn = 'swordsman';
			} else {
				var chosenTypeIndex = Math.floor(Math.random() * possibleTypes.length);
				typeToSpawn = possibleTypes[chosenTypeIndex];
			}
		} else {
			// Randomly select a type from the available pool for this score level
			var chosenTypeIndex = Math.floor(Math.random() * possibleTypes.length);
			typeToSpawn = possibleTypes[chosenTypeIndex];
		}
		// Set stats based on chosen type and apply score-based scaling
		if (typeToSpawn === 'knight') {
			var baseKnightHP = 5;
			var hpIncreaseIntervalKnight = 30; // Health increases every 30 score points after appearing
			var hpIncreasesKnight = Math.floor(Math.max(0, currentScore - 23) / hpIncreaseIntervalKnight);
			enemyHealth = baseKnightHP + hpIncreasesKnight * 5;
			enemySpeed *= 0.9; // Knights are slightly slower than base swordsman speed
		} else if (typeToSpawn === 'thief') {
			enemyHealth = 1; // Thieves are fragile
			enemyDodgeChance = 0.10; // 10% dodge chance
			var speedIncreaseIntervalThief = 25; // Speed increases every 25 score points after appearing
			var speedIncreasePercentThief = 0.05; // 5% speed increase each time
			var speedIncreasesThief = Math.floor(Math.max(0, currentScore - 15) / speedIncreaseIntervalThief);
			var thiefSpeedMultiplier = Math.pow(1 + speedIncreasePercentThief, speedIncreasesThief);
			enemySpeed *= 1.2 * thiefSpeedMultiplier; // Thieves are faster base + scaling speed
		} else if (typeToSpawn === 'shield') {
			var baseShieldHP = 20;
			var hpIncreaseIntervalShield = 35; // Gains HP every 35 score points after appearing
			var hpIncreasesShield = Math.floor(Math.max(0, currentScore - 30) / hpIncreaseIntervalShield);
			enemyHealth = baseShieldHP + hpIncreasesShield * 20;
			enemySpeed *= 0.5; // Shield enemies are very slow
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'shaman') {
			var baseShamanHP = 2;
			var statIncreaseIntervalShaman = 10; // Gains stats every 10 score points after appearing
			var statIncreasesShaman = Math.floor(Math.max(0, currentScore - 35) / statIncreaseIntervalShaman);
			enemyHealth = baseShamanHP + statIncreasesShaman * 1; // Gains 1 HP per interval
			enemySpeed *= 0.8 * Math.pow(1.04, statIncreasesShaman); // Base speed, gains 4% speed per interval
			enemyDodgeChance = 0; // Shaman cannot dodge
		} else if (typeToSpawn === 'wizard') {
			var baseWizardHP = 2;
			var statIncreaseIntervalWizard = 10; // Gains stats every 10 score points after appearing
			var statIncreasesWizard = Math.floor(Math.max(0, currentScore - 25) / statIncreaseIntervalWizard);
			enemyHealth = baseWizardHP + statIncreasesWizard * 1; // Gains 1 HP per interval
			enemySpeed *= 0.7 * Math.pow(1.05, statIncreasesWizard); // Slow base, gains 5% speed per interval
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'elite_knight') {
			var baseEliteKnightHP = 45;
			var hpIncreaseIntervalElite = 30; // Gains HP every 30 score points after appearing
			var hpIncreasesElite = Math.floor(Math.max(0, currentScore - 100) / hpIncreaseIntervalElite);
			enemyHealth = baseEliteKnightHP + hpIncreasesElite * 15;
			enemySpeed *= 0.85; // Slightly slower than base knight speed
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'elite_shield') {
			var baseEliteShieldHP = 200; // Starts with 200 HP
			var hpIncreaseIntervalEliteShield = 20; // Gains HP every 20 score points after appearing
			var hpIncreasesEliteShield = Math.floor(Math.max(0, currentScore - 112) / hpIncreaseIntervalEliteShield);
			enemyHealth = baseEliteShieldHP + hpIncreasesEliteShield * 50; // Gains 50 HP per interval
			enemySpeed *= 0.4; // Elite Shield enemies are slower than regular shield enemies
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'spearman') {
			var baseSpearmanHP = 2;
			var hpIncreaseIntervalSpearman = 10; // Gains HP every 10 score points after appearing
			var hpIncreasesSpearman = Math.floor(Math.max(0, currentScore - 10) / hpIncreaseIntervalSpearman);
			enemyHealth = baseSpearmanHP + hpIncreasesSpearman * 3; // Gains 3 HP per interval
			var speedIncreaseIntervalSpearman = 10; // Gains speed every 10 score points after appearing
			var speedIncreasePercentSpearman = 0.05; // 5% speed increase each time
			var speedIncreasesSpearman = Math.floor(Math.max(0, currentScore - 10) / speedIncreaseIntervalSpearman);
			var spearmanSpeedMultiplier = Math.pow(1 + speedIncreasePercentSpearman, speedIncreasesSpearman);
			enemySpeed *= 1.0 * spearmanSpeedMultiplier; // Base speed + scaling speed
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'war_elephant') {
			var baseElephantHP = 500;
			var hpIncreaseIntervalElephant = 15; // Gains HP every 15 score points after appearing
			var hpIncreasesElephant = Math.floor(Math.max(0, currentScore - 125) / hpIncreaseIntervalElephant);
			enemyHealth = baseElephantHP + hpIncreasesElephant * 100; // Gains 100 HP per interval
			enemySpeed *= 0.3; // War Elephants are very slow
			enemyDodgeChance = 0;
			// Note: War elephant death spawns spearmen - this will be handled in the Enemy death logic.
		} else if (typeToSpawn === 'hot_air_balloon') {
			enemyHealth = 1; // Always has 1 HP
			enemySpeed *= 0.2; // Very slow movement
			enemyDodgeChance = 0;
			// Note: Hot air balloon death spawns 5 random non-green enemies - handled in Enemy death logic
		} else if (typeToSpawn === 'dark_bowman') {
			var baseDarkBowmanHP = 5;
			var statIncreaseIntervalBowman = 10; // Gains stats every 10 score points after appearing
			var statIncreasesBowman = Math.floor(Math.max(0, currentScore - 55) / statIncreaseIntervalBowman);
			enemyHealth = baseDarkBowmanHP + statIncreasesBowman * 3; // Gains 3 HP per interval
			var speedIncreasePercentBowman = 0.05; // 5% speed increase each time
			var bowmanSpeedMultiplier = Math.pow(1 + speedIncreasePercentBowman, statIncreasesBowman);
			enemySpeed *= 1.1 * bowmanSpeedMultiplier; // Slightly faster than base speed + scaling
			enemyDodgeChance = 0;
			// Note: Dark bowman has Black tag making it immune to arrows
		} else if (typeToSpawn === 'jester') {
			var baseJesterHP = 2;
			enemyHealth = baseJesterHP; // Jester HP doesn't scale with score
			var baseJesterSpeed = baseSpeedForSpawn * 1.1; // Jester starts faster
			var speedIncreaseIntervalJester = 12; // Gains speed every 12 score points after appearing
			var speedIncreasePercentJester = 0.03; // 3% speed increase each time
			var speedIncreasesJester = Math.floor(Math.max(0, currentScore - 69) / speedIncreaseIntervalJester);
			enemySpeed = baseJesterSpeed * Math.pow(1 + speedIncreasePercentJester, speedIncreasesJester);
			enemyDodgeChance = 0.30; // 30% dodge chance
			// The reflectChance is set in the Enemy class constructor based on type, no need to set here.
		} else if (typeToSpawn === 'dark_war_elephant') {
			var baseDarkElephantHP = 450;
			var hpIncreaseIntervalDarkElephant = 10; // Gains HP every 10 score points after appearing
			var hpIncreasesDarkElephant = Math.floor(Math.max(0, currentScore - 120) / hpIncreaseIntervalDarkElephant);
			enemyHealth = baseDarkElephantHP + hpIncreasesDarkElephant * 80; // Gains 80 HP per interval
			enemySpeed *= 0.3; // Dark War Elephants are very slow
			enemyDodgeChance = 0;
			// Note: Dark War elephant death spawns dark bowmen - this will be handled in the Enemy death logic.
		} else if (typeToSpawn === 'dark_spearman') {
			var baseDarkSpearmanHP = 15;
			var baseDarkSpearmanSpeedMultiplier = 1.2;
			var statIncreaseIntervalDarkSpearman = 10; // Gains stats every 10 score points after appearing
			var statIncreasesDarkSpearman = Math.floor(Math.max(0, currentScore - 55) / statIncreaseIntervalDarkSpearman);
			enemyHealth = baseDarkSpearmanHP + statIncreasesDarkSpearman * 5; // Gains 5 HP per interval
			var darkSpearmanSpeedBonus = Math.pow(1 + 0.03, statIncreasesDarkSpearman); // Gains 3% speed per interval
			enemySpeed *= baseDarkSpearmanSpeedMultiplier * darkSpearmanSpeedBonus;
			enemyDodgeChance = 0;
			// Tag 'Black' is set in Enemy constructor
		} else if (typeToSpawn === 'dragon') {
			var baseDragonHP = 250;
			var hpIncreaseIntervalDragon = 15; // Gains HP every 15 score points after appearing
			var hpIncreasesDragon = Math.floor(Math.max(0, currentScore - 100) / hpIncreaseIntervalDragon);
			enemyHealth = baseDragonHP + hpIncreasesDragon * 50; // Gains 50 HP per interval
			enemySpeed *= 0.9; // Dragons are moderately fast
			enemyDodgeChance = 0.40; // 40% dodge chance
			// Tag 'Dragon' could be set in Enemy constructor if needed for other mechanics
		} else if (typeToSpawn === 'flag_bearer') {
			var baseFlagBearerHP = 5;
			var hpIncreaseIntervalFlagBearer = 10; // Gains HP every 10 score points after appearing
			var hpIncreasesFlagBearer = Math.floor(Math.max(0, currentScore - 27) / hpIncreaseIntervalFlagBearer);
			enemyHealth = baseFlagBearerHP + hpIncreasesFlagBearer * 2; // Gains 2 HP per interval
			var speedIncreaseIntervalFlagBearer = 10; // Gains speed every 10 score points
			var speedIncreasesFlagBearer = Math.floor(Math.max(0, currentScore - 27) / speedIncreaseIntervalFlagBearer);
			var flagBearerSpeedMultiplier = Math.pow(1.03, speedIncreasesFlagBearer); // 3% speed increase per interval
			enemySpeed *= 0.8 * flagBearerSpeedMultiplier; // Slower base speed but increases over time
			enemyDodgeChance = 0;
		} else if (typeToSpawn === 'baby_dragon') {
			var baseBabyDragonHP = 50;
			var hpIncreaseIntervalBabyDragon = 9; // Gains HP every 9 score points after appearing
			var hpIncreasesBabyDragon = Math.floor(Math.max(0, currentScore - 125) / hpIncreaseIntervalBabyDragon);
			enemyHealth = baseBabyDragonHP + hpIncreasesBabyDragon * 10; // Gains 10 HP per interval
			var speedIncreaseIntervalBabyDragon = 9; // Gains speed every 9 score points
			var speedIncreasesBabyDragon = Math.floor(Math.max(0, currentScore - 125) / speedIncreaseIntervalBabyDragon);
			var babyDragonSpeedMultiplier = Math.pow(1.02, speedIncreasesBabyDragon); // 2% speed increase per interval
			enemySpeed *= 1.1 * babyDragonSpeedMultiplier; // Faster than regular dragon
			enemyDodgeChance = 0.25; // 25% dodge chance
		} else {
			// Swordsman (default)
			enemyHealth = 1;
			// Speed remains baseSpeedForSpawn initially
		}
		// Check if this spawn should be overridden to be a Boss
		if (potentialBoss) {
			typeToSpawn = 'boss'; // Set type to boss
			enemyHealth = 5 + Math.floor(currentScore / 8); // Boss health scales significantly with score
			enemySpeed = baseSpeedForSpawn * 0.7; // Bosses are slower but much tougher (reset speed based on base)
			enemyDodgeChance = 0; // Bosses typically don't dodge
		}
		// Apply the global Sabotage speed multiplier AFTER type-specific adjustments
		enemySpeed *= enemySpeedMultiplier;
		// Create the new enemy instance with the calculated stats
		var newEnemy;
		if (typeToSpawn === 'flag_bearer') {
			newEnemy = new FlagBearer();
			newEnemy.speed = enemySpeed;
			newEnemy.baseSpeed = enemySpeed;
			newEnemy.health = enemyHealth;
			newEnemy.maxHealth = enemyHealth;
			newEnemy.dodgeChance = enemyDodgeChance;
		} else if (typeToSpawn === 'baby_dragon') {
			newEnemy = new BabyDragon();
			newEnemy.speed = enemySpeed;
			newEnemy.baseSpeed = enemySpeed;
			newEnemy.health = enemyHealth;
			newEnemy.maxHealth = enemyHealth;
			newEnemy.dodgeChance = enemyDodgeChance;
		} else {
			newEnemy = new Enemy(typeToSpawn, enemySpeed, enemyHealth, enemyDodgeChance);
		}
		// Position the new enemy at the top, random horizontal position with padding
		// Use the actual width of the created enemy's graphic for padding calculation
		// Need to access width after creation, use a sensible default or estimate if needed before creation
		var tempAsset = LK.getAsset(newEnemy.assetId || 'enemy', {}); // Get asset dimensions (might need refinement if assetId isn't on newEnemy yet)
		var spawnPadding = (tempAsset ? tempAsset.width / 2 : 100) + 20; // Use default if asset not found easily
		newEnemy.x = spawnPadding + Math.random() * (GAME_WIDTH - 2 * spawnPadding);
		newEnemy.y = -(tempAsset ? tempAsset.height / 2 : 100); // Start just above the top edge.
		// Initialize last position for state tracking (used for bastion collision check).
		newEnemy.lastY = newEnemy.y;
		// Add the new enemy to the game scene and the tracking array.
		game.addChild(newEnemy);
		enemies.push(newEnemy);
		// Increase difficulty for the next spawn: decrease spawn interval and increase base speed.
		// These affect the *next* potential spawn's base calculations.
		enemySpawnInterval -= enemySpawnRateDecrease;
		currentEnemySpeed += enemySpeedIncrease;
	}
};
// --- Swordsman Relic Initial Setup ---
if (playerRelics.swordsman.enabled && playerRelics.swordsman.level > 0) {
	// Spawn permanent swordsman for swordsman relic
	var permanentSwordsman = new Swordsman();
	permanentSwordsman.x = FIRING_POS_X + 100; // Position near player
	permanentSwordsman.y = FIRING_POS_Y - 50;
	permanentSwordsman.lifetime = Infinity; // Permanent swordsman
	permanentSwordsman.attackDamage = 1 + (playerRelics.swordsman.level - 1) * 2; // Base damage +2 per level after first
	game.addChild(permanentSwordsman);
	swordsmen.push(permanentSwordsman);
}
// --- Initial Game Setup ---
// Set the initial score text based on the starting score (which is 0).
scoreTxt.setText(LK.getScore());
// Set the initial ammo display.
if (ammoTxt) {
	// Ensure ammoTxt is initialized
	ammoTxt.setText('Ammo: ' + maxArrowsBeforeCooldown);
}
;
// Play the background music.
// Check if we need to show a title screen first
if (!isGameStarted) {// Assuming a flag 'isGameStarted' for title screen state
	// Don't play music immediately if showing title screen
} else {
	LK.playMusic('Gamemusic');
	;
}
// Placeholder for the title screen container
var titleScreen = null;
// Flag to track game start state
var isGameStarted = false;
// Function to show the title screen
function showTitleScreen() {
	isGameStarted = false; // Ensure game is not started
	// Create the title screen container
	titleScreen = new Container();
	titleScreen.x = GAME_WIDTH / 2;
	titleScreen.y = GAME_HEIGHT / 2;
	game.addChild(titleScreen);
	// Add title text
	var titleText = new Text2('Defend Your Bastion!', {
		size: 120,
		fill: 0xFFFFFF
	});
	titleText.anchor.set(0.5, 0.5);
	titleText.y = -200;
	titleScreen.addChild(titleText);
	// Add a simple instruction text
	var instructionText = new Text2('Tap to Start', {
		size: 60,
		fill: 0xCCCCCC
	});
	instructionText.anchor.set(0.5, 0.5);
	instructionText.y = 100;
	titleScreen.addChild(instructionText);
	// Make the title screen interactive to start the game
	titleScreen.interactive = true;
	titleScreen.down = function () {
		startGame(); // Start the game when tapped
	};
	// Pause game logic while title screen is active
	isUpgradePopupActive = true; // Reusing this flag to pause game logic
}
// Function to start the game
function startGame() {
	isGameStarted = true; // Set game started flag
	isUpgradePopupActive = false; // Unpause game logic
	if (titleScreen) {
		titleScreen.destroy();
		titleScreen = null;
	}
	// Reset game state if needed (LK might handle this on game start)
	// Play game music
	LK.playMusic('Gamemusic');
}
// Initially show the title screen
showTitleScreen();
 Arrow. In-Game asset. 2d. High contrast. No shadows. Topdown
 Red stickman with a sword. In-Game asset. 2d. High contrast. No shadows. Topdown
 Blue stickman with a bow. In-Game asset. 2d. High contrast. No shadows
 Red stickman with an iron helmet, iron sword and iron shield. In-Game asset. 2d. High contrast. No shadows. No eyes
 Red stickman with a knife and a thief's bandana. In-Game asset. 2d. High contrast. No shadows. No eyes
 Purple stickman with a crown. In-Game asset. 2d. High contrast. No shadows
 Blue stickman with a sword. In-Game asset. 2d. High contrast. No shadows
 Tower. In-Game asset. 2d. High contrast. No shadows
 Red stickman with a big wooden shield full of spikes. In-Game asset. 2d. High contrast. No shadows
 Green stickman with a blue wizard hat and a staff; no eyes. In-Game asset. 2d. High contrast. No shadows
 Red stickman with a golden knight helmet, gold sword and gold shield and gold boots. In-Game asset. 2d. High contrast. No shadows
 Cannon. In-Game asset. 2d. High contrast. No shadows
 Cannonball. In-Game asset. 2d. High contrast. No shadows
 Yellow stickman with an azur wizard hat and staff on a tower. In-Game asset. 2d. High contrast. No shadows
 Magic ice ball. In-Game asset. 2d. High contrast. No shadows
 Green stickman with a Spartan helmet, Spartan shield and Spartan spear. In-Game asset. 2d. High contrast. No shadows
 Green war elephant. In-Game asset. 2d. High contrast. No shadows
 Yellow viking stickman holding an axe and is about to throw it. In-Game asset. 2d. High contrast. No shadows
 Hatchet. In-Game asset. 2d. High contrast. No shadows
 A red stickman with a big golden shield and golden armor. In-Game asset. 2d. High contrast. No shadows
 
 Gray stickman with it's face covered with a black hood equipped with a bow In-Game asset. 2d. High contrast. No shadows, no eyes
 Hot air balloon full of red stickmen. In-Game asset. 2d. High contrast. No shadows
 Black war elephant with red eyes. In-Game asset. 2d. High contrast. No shadows
 Red stickman that is a jester that is on a blue ball and is juggling. In-Game asset. 2d. High contrast. No shadows
 Green stickman with a tribal mask and a stick to shoot darts. In-Game asset. 2d. High contrast. No shadows
 White female stickman that is an angel with golden armor and a heavenly sword. In-Game asset. 2d. High contrast. No shadows
 Wooden dart In-Game asset. 2d. High contrast. No shadows. Topdown
 Orb of light. In-Game asset. 2d. High contrast. No shadows
 Purple dragon with a red stickman riding it. In-Game asset. 2d. High contrast. No shadows
 Add a Roman shield
 Bomb. In-Game asset. 2d. High contrast. No shadows
 Blue stickman with safety goggles, yellow safety helmet and a bomb. In-Game asset. 2d. High contrast. No shadows
 Giant crossbow. In-Game asset. 2d. High contrast. No shadows. Topdown
 Green stickman with a British soldier's hat and with a red flag with 2 swords. In-Game asset. 2d. High contrast. No shadows
 Baby dragon from clash of clans. In-Game asset. 2d. High contrast. No shadows
 Missile launcher BTD6. In-Game asset. 2d. High contrast. No shadows
 Red Missile. In-Game asset. 2d. High contrast. No shadows