/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 8;
	self.direction = {
		x: 0,
		y: 0
	};
	self.lifetime = 0;
	self.maxLifetime = 120; // 2 seconds at 60fps
	self.update = function () {
		self.x += self.direction.x * self.speed;
		self.y += self.direction.y * self.speed;
		self.lifetime++;
	};
	return self;
});
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0xFFFFFF
	});
	self.speed = 1;
	self.health = 2;
	self.attackRange = 40;
	self.attackCooldown = 0;
	self.attackInterval = 60; // Attack every second at 60fps
	self.patrolDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction
	self.patrolAxis = Math.random() > 0.5 ? 'x' : 'y'; // Random patrol axis (horizontal or vertical)
	self.patrolDistance = CELL_SIZE * 3; // Patrol 3 cells distance
	self.startPosition = {
		x: 0,
		y: 0
	}; // Will be set when enemy is placed
	self.isMoving = false;
	self.lastPlayerDistance = Infinity;
	self.startPatrol = function () {
		if (self.isMoving) return;
		self.isMoving = true;
		var targetX = self.x;
		var targetY = self.y;
		// Calculate target position based on patrol axis
		if (self.patrolAxis === 'x') {
			targetX = self.startPosition.x + self.patrolDirection * self.patrolDistance;
		} else {
			targetY = self.startPosition.y + self.patrolDirection * self.patrolDistance;
		}
		// Check if target position is valid
		if (canMoveTo(targetX, targetY)) {
			// Store the original position for safe restoration
			var originalX = self.x;
			var originalY = self.y;
			// Move to target position using tween
			tween(self, {
				x: targetX,
				y: targetY
			}, {
				duration: 2000,
				easing: tween.linear,
				onFinish: function onFinish() {
					// Ensure enemy is at a valid position after movement
					if (!canMoveTo(self.x, self.y)) {
						// If somehow ended up in invalid position, restore to original
						self.x = originalX;
						self.y = originalY;
					}
					self.isMoving = false;
					self.patrolDirection *= -1; // Reverse direction
				}
			});
		} else {
			// If can't move in current direction, reverse immediately
			self.isMoving = false;
			self.patrolDirection *= -1;
		}
	};
	self.update = function () {
		// Add bouncing animation when enemy is not moving (idle/waiting state)
		if (!self.isMoving) {
			if (!self.bounceTimer) self.bounceTimer = 0;
			self.bounceTimer++;
			// Create a subtle bouncing effect
			var bounceOffset = Math.sin(self.bounceTimer * 0.15) * 2;
			// Use current position as base instead of startPosition to avoid conflicts
			var baseY = self.startPosition.y;
			self.y = baseY + bounceOffset;
		} else {
			// Reset bounce timer when moving to ensure smooth transitions
			self.bounceTimer = 0;
		}
		var dx = player.x - self.x;
		var dy = player.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var detectionRange = CELL_SIZE * 4; // Enemy can see player from 4 cells away
		// Check if player is within detection range and line of sight (optimized - check every 10 frames)
		var canSeePlayer = false;
		if (distance < detectionRange) {
			// Only do expensive line of sight calculation every 10 frames
			if (!self.losCheckTimer) self.losCheckTimer = 0;
			self.losCheckTimer++;
			if (self.losCheckTimer >= 10 || !self.hasOwnProperty('lastCanSeePlayer')) {
				self.losCheckTimer = 0;
				// Simple line of sight check - check if there are walls between enemy and player
				var steps = Math.ceil(distance / 40); // Reduced precision from 20 to 40
				var stepX = dx / steps;
				var stepY = dy / steps;
				self.lastCanSeePlayer = true;
				for (var step = 1; step < steps; step++) {
					var checkX = self.x + stepX * step;
					var checkY = self.y + stepY * step;
					if (!canMoveTo(checkX, checkY)) {
						self.lastCanSeePlayer = false;
						break;
					}
				}
			}
			canSeePlayer = self.lastCanSeePlayer;
		} else {
			canSeePlayer = self.lastCanSeePlayer;
		}
		// If can see player and not in attack range, move towards player
		if (canSeePlayer && distance > self.attackRange) {
			if (!self.isMoving) {
				self.isMoving = true;
				// Stop current patrol movement
				tween.stop(self);
				// Calculate next position towards player (one cell at a time)
				var moveDistance = CELL_SIZE;
				var normalizedDx = dx / distance;
				var normalizedDy = dy / distance;
				var targetX = self.x + normalizedDx * moveDistance;
				var targetY = self.y + normalizedDy * moveDistance;
				// Try to move towards player, prioritize the axis with larger distance
				if (Math.abs(dx) > Math.abs(dy)) {
					// Try horizontal movement first
					var horizontalTarget = self.x + (dx > 0 ? moveDistance : -moveDistance);
					if (canMoveTo(horizontalTarget, self.y)) {
						targetX = horizontalTarget;
						targetY = self.y;
					} else if (canMoveTo(self.x, self.y + (dy > 0 ? moveDistance : -moveDistance))) {
						// If horizontal blocked, try vertical
						targetX = self.x;
						targetY = self.y + (dy > 0 ? moveDistance : -moveDistance);
					} else {
						// Can't move towards player
						targetX = self.x;
						targetY = self.y;
					}
				} else {
					// Try vertical movement first
					var verticalTarget = self.y + (dy > 0 ? moveDistance : -moveDistance);
					if (canMoveTo(self.x, verticalTarget)) {
						targetX = self.x;
						targetY = verticalTarget;
					} else if (canMoveTo(self.x + (dx > 0 ? moveDistance : -moveDistance), self.y)) {
						// If vertical blocked, try horizontal
						targetX = self.x + (dx > 0 ? moveDistance : -moveDistance);
						targetY = self.y;
					} else {
						// Can't move towards player
						targetX = self.x;
						targetY = self.y;
					}
				}
				// Move towards calculated target
				if (targetX !== self.x || targetY !== self.y) {
					// Store current position for safety
					var safeX = self.x;
					var safeY = self.y;
					tween(self, {
						x: targetX,
						y: targetY
					}, {
						duration: 1000,
						easing: tween.linear,
						onFinish: function onFinish() {
							// Validate final position
							if (!canMoveTo(self.x, self.y)) {
								self.x = safeX;
								self.y = safeY;
							}
							self.isMoving = false;
						}
					});
				} else {
					self.isMoving = false;
				}
			}
		} else if (!canSeePlayer) {
			// Start patrol movement if not already moving and can't see player
			if (!self.isMoving) {
				self.startPatrol();
			}
		}
		// Attack player if in range
		if (distance < self.attackRange) {
			// Stop patrolling when in attack range
			if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) {
				tween.stop(self);
				self.isMoving = false;
			}
			// Continuously attack while in range
			if (self.attackCooldown <= 0) {
				// Perform melee attack
				playerHealth--;
				LK.effects.flashObject(player, 0xFF0000, 500);
				// Visual attack feedback - enemy briefly grows and turns red
				tween(self, {
					tint: 0xFF0000,
					scaleX: 1.3,
					scaleY: 1.3
				}, {
					duration: 200,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						// Return to normal appearance
						tween(self, {
							tint: 0xFFFFFF,
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 200,
							easing: tween.easeOut
						});
					}
				});
				// Reset attack cooldown
				self.attackCooldown = self.attackInterval;
			}
		}
		// Update attack cooldown
		if (self.attackCooldown > 0) {
			self.attackCooldown--;
		}
		self.lastPlayerDistance = distance;
	};
	return self;
});
var Ore = Container.expand(function () {
	var self = Container.call(this);
	var oreGraphics = self.attachAsset('ore', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.value = 1;
	self.bobTimer = 0;
	self.baseY = self.y;
	self.update = function () {
		self.bobTimer++;
		self.y = self.baseY + Math.sin(self.bobTimer * 0.1) * 3;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x2C1810
});
/**** 
* Game Code
****/ 
// Game constants
var MAZE_WIDTH = 13;
var MAZE_HEIGHT = 17;
var CELL_SIZE = 80;
var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2;
var MAZE_OFFSET_Y = 100;
// Game variables
var maze = [];
var player;
var enemies = [];
var ores = [];
var bullets = [];
var playerHealth = 3;
var oreCollected = 0;
var oreTarget = 10;
var level = 1;
var exit;
var gameContainer;
// UI elements
var healthText = new Text2('Health: 3', {
	size: 60,
	fill: 0xFF4444
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
var oreText = new Text2('Ore: 0/10', {
	size: 60,
	fill: 0xFFD700
});
oreText.anchor.set(0.5, 0);
LK.gui.top.addChild(oreText);
var levelText = new Text2('Level: 1', {
	size: 60,
	fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
// Initialize maze array
function initializeMaze() {
	maze = [];
	for (var y = 0; y < MAZE_HEIGHT; y++) {
		maze[y] = [];
		for (var x = 0; x < MAZE_WIDTH; x++) {
			maze[y][x] = 1; // 1 = wall, 0 = floor
		}
	}
}
// Simple maze generation using recursive backtracking
function generateMaze() {
	initializeMaze();
	var stack = [];
	var startX = 1;
	var startY = 1;
	maze[startY][startX] = 0;
	stack.push({
		x: startX,
		y: startY
	});
	while (stack.length > 0) {
		var current = stack[stack.length - 1];
		var neighbors = [];
		// Check all four directions
		var directions = [{
			x: 0,
			y: -2
		}, {
			x: 2,
			y: 0
		}, {
			x: 0,
			y: 2
		}, {
			x: -2,
			y: 0
		}];
		for (var i = 0; i < directions.length; i++) {
			var nx = current.x + directions[i].x;
			var ny = current.y + directions[i].y;
			if (nx > 0 && nx < MAZE_WIDTH - 1 && ny > 0 && ny < MAZE_HEIGHT - 1 && maze[ny][nx] === 1) {
				neighbors.push({
					x: nx,
					y: ny,
					dir: directions[i]
				});
			}
		}
		if (neighbors.length > 0) {
			var chosen = neighbors[Math.floor(Math.random() * neighbors.length)];
			// Remove wall between current and chosen
			maze[current.y + chosen.dir.y / 2][current.x + chosen.dir.x / 2] = 0;
			maze[chosen.y][chosen.x] = 0;
			stack.push(chosen);
		} else {
			stack.pop();
		}
	}
}
// Create visual maze
function createMazeVisual() {
	gameContainer = game.addChild(new Container());
	for (var y = 0; y < MAZE_HEIGHT; y++) {
		for (var x = 0; x < MAZE_WIDTH; x++) {
			var cellX = MAZE_OFFSET_X + x * CELL_SIZE;
			var cellY = MAZE_OFFSET_Y + y * CELL_SIZE;
			if (maze[y][x] === 1) {
				// Wall
				var wall = LK.getAsset('wall', {
					x: cellX,
					y: cellY
				});
				gameContainer.addChild(wall);
			} else {
				// Floor
				var floor = LK.getAsset('floor', {
					x: cellX,
					y: cellY
				});
				gameContainer.addChild(floor);
			}
		}
	}
}
// Place ore in maze
function placeOre() {
	var oreCount = oreTarget + Math.floor(level / 2);
	var placed = 0;
	while (placed < oreCount) {
		var x = Math.floor(Math.random() * MAZE_WIDTH);
		var y = Math.floor(Math.random() * MAZE_HEIGHT);
		if (maze[y][x] === 0 && (x !== 1 || y !== 1)) {
			var ore = gameContainer.addChild(new Ore());
			ore.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
			ore.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
			ore.baseY = ore.y;
			ores.push(ore);
			placed++;
		}
	}
}
// Place enemies in maze
function placeEnemies() {
	var enemyCount = 3 + level;
	var placed = 0;
	while (placed < enemyCount) {
		var x = Math.floor(Math.random() * MAZE_WIDTH);
		var y = Math.floor(Math.random() * MAZE_HEIGHT);
		if (maze[y][x] === 0 && (x !== 1 || y !== 1) && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 5) {
			var enemy = gameContainer.addChild(new Enemy());
			enemy.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
			enemy.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
			enemy.startPosition.x = enemy.x;
			enemy.startPosition.y = enemy.y;
			enemies.push(enemy);
			placed++;
		}
	}
}
// Place exit
function placeExit() {
	// Find a position far from start
	var placed = false;
	while (!placed) {
		var x = Math.floor(Math.random() * MAZE_WIDTH);
		var y = Math.floor(Math.random() * MAZE_HEIGHT);
		if (maze[y][x] === 0 && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 10) {
			exit = gameContainer.addChild(LK.getAsset('exit', {
				x: MAZE_OFFSET_X + x * CELL_SIZE,
				y: MAZE_OFFSET_Y + y * CELL_SIZE
			}));
			placed = true;
		}
	}
}
// Create detailed background with various environmental elements
function createDetailedBackground() {
	if (!gameContainer) {
		console.log("gameContainer not available for background creation");
		return;
	}
	var backgroundElements = [];
	// Select one of 9 background variations randomly
	var backgroundType = Math.floor(Math.random() * 9);
	// Background variation 0: Rock dominant
	if (backgroundType === 0) {
		// Add many background rocks
		for (var i = 0; i < 15; i++) {
			var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.4,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgRock1);
		}
		for (var i = 0; i < 20; i++) {
			var bgRock2 = gameContainer.addChild(LK.getAsset('bgRock2', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgRock2);
		}
	}
	// Background variation 1: Crystal cave
	else if (backgroundType === 1) {
		for (var i = 0; i < 30; i++) {
			var bgCrystal = gameContainer.addChild(LK.getAsset('bgCrystal', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.5,
				rotation: Math.random() * Math.PI * 2,
				scaleY: 0.8 + Math.random() * 0.4
			}));
			backgroundElements.push(bgCrystal);
		}
	}
	// Background variation 2: Moss covered
	else if (backgroundType === 2) {
		for (var i = 0; i < 40; i++) {
			var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.45,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgMoss);
		}
		// Add some vines
		for (var i = 0; i < 15; i++) {
			var bgVines = gameContainer.addChild(LK.getAsset('bgVines', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgVines);
		}
	}
	// Background variation 3: Stalactite heavy
	else if (backgroundType === 3) {
		for (var i = 0; i < 25; i++) {
			var bgStalactite = gameContainer.addChild(LK.getAsset('bgStalactite', {
				x: Math.random() * 2048,
				y: Math.random() * 400,
				// Extended from top
				anchorX: 0.5,
				anchorY: 0,
				alpha: 0.4,
				rotation: Math.random() * 0.4 - 0.2,
				scaleY: 0.8 + Math.random() * 0.6
			}));
			backgroundElements.push(bgStalactite);
		}
	}
	// Background variation 4: Pebble field
	else if (backgroundType === 4) {
		for (var i = 0; i < 35; i++) {
			var bgPebbles = gameContainer.addChild(LK.getAsset('bgPebbles', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.35,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgPebbles);
		}
	}
	// Background variation 5: Cracked terrain
	else if (backgroundType === 5) {
		for (var i = 0; i < 50; i++) {
			var bgCracks = gameContainer.addChild(LK.getAsset('bgCracks', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.25,
				rotation: Math.random() * Math.PI * 2,
				scaleX: 0.5 + Math.random() * 1.5
			}));
			backgroundElements.push(bgCracks);
		}
	}
	// Background variation 6: Boulder field
	else if (backgroundType === 6) {
		for (var i = 0; i < 12; i++) {
			var bgBoulder = gameContainer.addChild(LK.getAsset('bgBoulder', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgBoulder);
		}
	}
	// Background variation 7: Mixed cave
	else if (backgroundType === 7) {
		// Mixed environment with moderate amounts of everything
		for (var i = 0; i < 8; i++) {
			var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgRock1);
		}
		for (var i = 0; i < 10; i++) {
			var bgCrystal = gameContainer.addChild(LK.getAsset('bgCrystal', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.4,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgCrystal);
		}
		for (var i = 0; i < 15; i++) {
			var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.35,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgMoss);
		}
	}
	// Background variation 8: Vine jungle cave
	else if (backgroundType === 8) {
		for (var i = 0; i < 30; i++) {
			var bgVines = gameContainer.addChild(LK.getAsset('bgVines', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.4,
				rotation: Math.random() * Math.PI * 2,
				scaleX: 0.8 + Math.random() * 0.4
			}));
			backgroundElements.push(bgVines);
		}
		for (var i = 0; i < 25; i++) {
			var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgMoss);
		}
	}
	// Send all background elements to back
	for (var i = 0; i < backgroundElements.length; i++) {
		gameContainer.setChildIndex(backgroundElements[i], 0);
	}
}
// Check if position is valid for movement
function canMoveTo(x, y) {
	var mazeX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE);
	var mazeY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE);
	if (mazeX < 0 || mazeX >= MAZE_WIDTH || mazeY < 0 || mazeY >= MAZE_HEIGHT) {
		return false;
	}
	return maze[mazeY][mazeX] === 0;
}
// Initialize level
function initializeLevel() {
	// Clear existing game objects
	if (gameContainer) {
		gameContainer.destroy();
	}
	enemies = [];
	ores = [];
	bullets = [];
	oreCollected = 0;
	// Add detailed background
	var background = game.addChild(LK.getAsset('background', {
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	}));
	// Generate new maze
	generateMaze();
	createMazeVisual();
	// Create detailed background elements
	createDetailedBackground();
	// Create player
	player = gameContainer.addChild(LK.getAsset('player', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: MAZE_OFFSET_X + 1 * CELL_SIZE + CELL_SIZE / 2,
		y: MAZE_OFFSET_Y + 1 * CELL_SIZE + CELL_SIZE / 2
	}));
	// Place game objects
	placeOre();
	placeEnemies();
	placeExit();
	// Update UI
	updateUI();
}
// Update UI
function updateUI() {
	healthText.setText('Health: ' + playerHealth);
	oreText.setText('Ore: ' + oreCollected + '/' + oreTarget);
	levelText.setText('Level: ' + level);
}
// Shooting system
var dragNode = null;
var shootCooldown = 0;
function shoot(targetX, targetY) {
	if (shootCooldown > 0) return;
	// Limit maximum bullets to prevent lag
	if (bullets.length >= 15) return;
	var dx = targetX - player.x;
	var dy = targetY - player.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	if (distance < 50) return; // Don't shoot if too close
	// Calculate base direction
	var baseDirectionX = dx / distance;
	var baseDirectionY = dy / distance;
	// Create three bullets with spread angles
	var spreadAngles = [-0.3, 0, 0.3]; // Left, center, right (in radians, about 17 degrees each side)
	for (var i = 0; i < spreadAngles.length; i++) {
		var angle = Math.atan2(baseDirectionY, baseDirectionX) + spreadAngles[i];
		var bullet = gameContainer.addChild(new Bullet());
		bullet.x = player.x;
		bullet.y = player.y;
		bullet.direction.x = Math.cos(angle);
		bullet.direction.y = Math.sin(angle);
		bullets.push(bullet);
	}
	shootCooldown = 15; // Quarter second cooldown
	LK.getSound('shoot').play();
}
// Main game loop
game.update = function () {
	if (shootCooldown > 0) shootCooldown--;
	// Handle hold movement
	if (isTracking && !isHolding) {
		var currentTime = Date.now();
		var holdTime = currentTime - holdStartTime;
		// Check if we should start hold movement
		if (holdTime >= holdThreshold) {
			var dx = swipeEnd.x - swipeStart.x;
			var dy = swipeEnd.y - swipeStart.y;
			var swipeDistance = Math.sqrt(dx * dx + dy * dy);
			// Only start hold if not moving much (stationary hold)
			if (swipeDistance < swipeThreshold) {
				isHolding = true;
				lastHoldMoveTime = currentTime;
				// Determine hold direction based on player center to touch position
				var holdDx = swipeStart.x - player.x;
				var holdDy = swipeStart.y - player.y;
				var holdDistance = Math.sqrt(holdDx * holdDx + holdDy * holdDy);
				if (holdDistance > 30) {
					// Must be reasonable distance from center
					if (Math.abs(holdDx) > Math.abs(holdDy)) {
						// Horizontal hold movement
						holdDirection.x = holdDx > 0 ? 1 : -1;
						holdDirection.y = 0;
					} else {
						// Vertical hold movement
						holdDirection.x = 0;
						holdDirection.y = holdDy > 0 ? 1 : -1;
					}
				}
			}
		}
	}
	// Process hold movement
	if (isHolding && !isPlayerMoving) {
		var currentTime = Date.now();
		if (currentTime - lastHoldMoveTime >= holdMoveInterval) {
			var moveX = holdDirection.x * playerSpeed;
			var moveY = holdDirection.y * playerSpeed;
			var newX = player.x + moveX;
			var newY = player.y + moveY;
			// Try to move in hold direction
			if (canMoveTo(newX, player.y) && holdDirection.x !== 0) {
				// Flip player sprite based on hold movement direction
				if (holdDirection.x > 0) {
					// Moving right - face right (normal)
					player.scaleX = 1;
				} else {
					// Moving left - face left (flipped)
					player.scaleX = -1;
				}
				isPlayerMoving = true;
				tween(player, {
					x: newX
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						isPlayerMoving = false;
					}
				});
				lastHoldMoveTime = currentTime;
			} else if (canMoveTo(player.x, newY) && holdDirection.y !== 0) {
				isPlayerMoving = true;
				tween(player, {
					y: newY
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						isPlayerMoving = false;
					}
				});
				lastHoldMoveTime = currentTime;
			}
		}
	}
	// Update bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		var bullet = bullets[i];
		// Check bullet lifetime
		if (bullet.lifetime >= bullet.maxLifetime) {
			bullet.destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check wall collision
		if (!canMoveTo(bullet.x, bullet.y)) {
			bullet.destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check enemy collision (optimized - only check every other frame for performance)
		var hitEnemy = false;
		if (LK.ticks % 2 === 0 || bullet.lifetime < 10) {
			// Always check new bullets
			for (var j = enemies.length - 1; j >= 0; j--) {
				if (bullet.intersects(enemies[j])) {
					enemies[j].health--;
					LK.getSound('enemyHit').play();
					if (enemies[j].health <= 0) {
						// Create red circular explosion animation
						var dyingEnemy = enemies[j];
						var explosionX = dyingEnemy.x;
						var explosionY = dyingEnemy.y;
						// Create red explosion circle
						var explosion = gameContainer.addChild(LK.getAsset('bullet', {
							anchorX: 0.5,
							anchorY: 0.5,
							x: explosionX,
							y: explosionY,
							scaleX: 0.1,
							scaleY: 0.1,
							tint: 0xFF0000
						}));
						// Animate explosion circle expanding and fading
						tween(explosion, {
							scaleX: 8,
							scaleY: 8,
							alpha: 0
						}, {
							duration: 500,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								explosion.destroy();
							}
						});
						// Create enemy death animation with spinning
						tween(dyingEnemy, {
							tint: 0xFF0000,
							scaleX: 1.5,
							scaleY: 1.5,
							rotation: Math.PI * 2
						}, {
							duration: 150,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								// Second stage: Continue growing while fading to dark red and spinning faster
								tween(dyingEnemy, {
									tint: 0x800000,
									scaleX: 2.5,
									scaleY: 2.5,
									alpha: 0.7,
									rotation: Math.PI * 6
								}, {
									duration: 200,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										// Final stage: Fade out completely with final spin
										tween(dyingEnemy, {
											alpha: 0,
											scaleX: 3,
											scaleY: 3,
											rotation: Math.PI * 10
										}, {
											duration: 200,
											easing: tween.easeIn,
											onFinish: function onFinish() {
												dyingEnemy.destroy();
											}
										});
									}
								});
							}
						});
						enemies.splice(j, 1);
					}
					bullet.destroy();
					bullets.splice(i, 1);
					hitEnemy = true;
					break;
				}
			}
		}
		if (hitEnemy) continue;
	}
	// Check ore collection
	for (var i = ores.length - 1; i >= 0; i--) {
		if (player.intersects(ores[i])) {
			oreCollected++;
			LK.getSound('oreCollect').play();
			ores[i].destroy();
			ores.splice(i, 1);
			updateUI();
		}
	}
	// Check exit condition
	if (exit && player.intersects(exit) && oreCollected >= oreTarget) {
		level++;
		oreTarget += 2;
		initializeLevel();
		return;
	}
	// Check game over
	if (playerHealth <= 0) {
		LK.showGameOver();
		return;
	}
	// Check win condition (survive 10 levels)
	if (level > 10) {
		LK.showYouWin();
		return;
	}
};
// Swipe and hold-based movement system
var swipeStart = {
	x: 0,
	y: 0
};
var swipeEnd = {
	x: 0,
	y: 0
};
var isTracking = false;
var playerSpeed = 80; // Full cell movement
var swipeThreshold = 50; // Minimum distance for swipe detection
var lastMoveTime = 0;
var moveDelay = 200; // Delay between moves in milliseconds
var isPlayerMoving = false;
// Hold movement system
var isHolding = false;
var holdStartTime = 0;
var holdThreshold = 300; // Time to distinguish between tap and hold (ms)
var holdMoveInterval = 150; // Interval between moves while holding
var lastHoldMoveTime = 0;
var holdDirection = {
	x: 0,
	y: 0
};
game.down = function (x, y, obj) {
	swipeStart.x = x;
	swipeStart.y = y;
	isTracking = true;
	holdStartTime = Date.now();
	isHolding = false;
};
game.move = function (x, y, obj) {
	if (isTracking) {
		swipeEnd.x = x;
		swipeEnd.y = y;
	}
};
game.up = function (x, y, obj) {
	if (!isTracking) return;
	isTracking = false;
	isHolding = false; // Stop hold movement
	var holdTime = Date.now() - holdStartTime;
	// Check if this was a hold operation
	if (holdTime >= holdThreshold) {
		// This was a hold, don't process as tap
		return;
	}
	// Check if this is a swipe for shooting
	var dx = swipeEnd.x - swipeStart.x;
	var dy = swipeEnd.y - swipeStart.y;
	var swipeDistance = Math.sqrt(dx * dx + dy * dy);
	// If swipe distance is significant, shoot towards swipe direction
	if (swipeDistance >= swipeThreshold) {
		// Calculate target position based on swipe direction
		var targetX = player.x + dx * 3; // Multiply for longer range
		var targetY = player.y + dy * 3;
		shoot(targetX, targetY);
		return; // Don't process as movement
	}
	// Tap only - move towards target position
	// Prevent too frequent moves and simultaneous movements
	var currentTime = Date.now();
	if (currentTime - lastMoveTime < moveDelay || isPlayerMoving) return;
	// Calculate direction from player to tap position
	var tapDx = x - player.x;
	var tapDy = y - player.y;
	var distance = Math.sqrt(tapDx * tapDx + tapDy * tapDy);
	if (distance < 50) return; // Don't move if tapped too close to player
	// Determine movement direction (one cell at a time)
	var moveX = 0;
	var moveY = 0;
	if (Math.abs(tapDx) > Math.abs(tapDy)) {
		// Move horizontally towards tap
		moveX = tapDx > 0 ? playerSpeed : -playerSpeed;
	} else {
		// Move vertically towards tap
		moveY = tapDy > 0 ? playerSpeed : -playerSpeed;
	}
	// Calculate new position
	var newX = player.x + moveX;
	var newY = player.y + moveY;
	// Check if movement is valid and animate smoothly
	if (canMoveTo(newX, player.y) && Math.abs(moveX) > 0) {
		// Flip player sprite based on movement direction
		if (moveX > 0) {
			// Moving right - face right (normal)
			player.scaleX = 1;
		} else {
			// Moving left - face left (flipped)
			player.scaleX = -1;
		}
		isPlayerMoving = true;
		tween(player, {
			x: newX
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				isPlayerMoving = false;
			}
		});
		lastMoveTime = currentTime;
	} else if (canMoveTo(player.x, newY) && Math.abs(moveY) > 0) {
		isPlayerMoving = true;
		tween(player, {
			y: newY
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				isPlayerMoving = false;
			}
		});
		lastMoveTime = currentTime;
	}
};
// Initialize the first level
initializeLevel();
// Start background music
LK.playMusic('1dwarftheme'); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 8;
	self.direction = {
		x: 0,
		y: 0
	};
	self.lifetime = 0;
	self.maxLifetime = 120; // 2 seconds at 60fps
	self.update = function () {
		self.x += self.direction.x * self.speed;
		self.y += self.direction.y * self.speed;
		self.lifetime++;
	};
	return self;
});
var Enemy = Container.expand(function () {
	var self = Container.call(this);
	var enemyGraphics = self.attachAsset('enemy', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0xFFFFFF
	});
	self.speed = 1;
	self.health = 2;
	self.attackRange = 40;
	self.attackCooldown = 0;
	self.attackInterval = 60; // Attack every second at 60fps
	self.patrolDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction
	self.patrolAxis = Math.random() > 0.5 ? 'x' : 'y'; // Random patrol axis (horizontal or vertical)
	self.patrolDistance = CELL_SIZE * 3; // Patrol 3 cells distance
	self.startPosition = {
		x: 0,
		y: 0
	}; // Will be set when enemy is placed
	self.isMoving = false;
	self.lastPlayerDistance = Infinity;
	self.startPatrol = function () {
		if (self.isMoving) return;
		self.isMoving = true;
		var targetX = self.x;
		var targetY = self.y;
		// Calculate target position based on patrol axis
		if (self.patrolAxis === 'x') {
			targetX = self.startPosition.x + self.patrolDirection * self.patrolDistance;
		} else {
			targetY = self.startPosition.y + self.patrolDirection * self.patrolDistance;
		}
		// Check if target position is valid
		if (canMoveTo(targetX, targetY)) {
			// Store the original position for safe restoration
			var originalX = self.x;
			var originalY = self.y;
			// Move to target position using tween
			tween(self, {
				x: targetX,
				y: targetY
			}, {
				duration: 2000,
				easing: tween.linear,
				onFinish: function onFinish() {
					// Ensure enemy is at a valid position after movement
					if (!canMoveTo(self.x, self.y)) {
						// If somehow ended up in invalid position, restore to original
						self.x = originalX;
						self.y = originalY;
					}
					self.isMoving = false;
					self.patrolDirection *= -1; // Reverse direction
				}
			});
		} else {
			// If can't move in current direction, reverse immediately
			self.isMoving = false;
			self.patrolDirection *= -1;
		}
	};
	self.update = function () {
		// Add bouncing animation when enemy is not moving (idle/waiting state)
		if (!self.isMoving) {
			if (!self.bounceTimer) self.bounceTimer = 0;
			self.bounceTimer++;
			// Create a subtle bouncing effect
			var bounceOffset = Math.sin(self.bounceTimer * 0.15) * 2;
			// Use current position as base instead of startPosition to avoid conflicts
			var baseY = self.startPosition.y;
			self.y = baseY + bounceOffset;
		} else {
			// Reset bounce timer when moving to ensure smooth transitions
			self.bounceTimer = 0;
		}
		var dx = player.x - self.x;
		var dy = player.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var detectionRange = CELL_SIZE * 4; // Enemy can see player from 4 cells away
		// Check if player is within detection range and line of sight (optimized - check every 10 frames)
		var canSeePlayer = false;
		if (distance < detectionRange) {
			// Only do expensive line of sight calculation every 10 frames
			if (!self.losCheckTimer) self.losCheckTimer = 0;
			self.losCheckTimer++;
			if (self.losCheckTimer >= 10 || !self.hasOwnProperty('lastCanSeePlayer')) {
				self.losCheckTimer = 0;
				// Simple line of sight check - check if there are walls between enemy and player
				var steps = Math.ceil(distance / 40); // Reduced precision from 20 to 40
				var stepX = dx / steps;
				var stepY = dy / steps;
				self.lastCanSeePlayer = true;
				for (var step = 1; step < steps; step++) {
					var checkX = self.x + stepX * step;
					var checkY = self.y + stepY * step;
					if (!canMoveTo(checkX, checkY)) {
						self.lastCanSeePlayer = false;
						break;
					}
				}
			}
			canSeePlayer = self.lastCanSeePlayer;
		} else {
			canSeePlayer = self.lastCanSeePlayer;
		}
		// If can see player and not in attack range, move towards player
		if (canSeePlayer && distance > self.attackRange) {
			if (!self.isMoving) {
				self.isMoving = true;
				// Stop current patrol movement
				tween.stop(self);
				// Calculate next position towards player (one cell at a time)
				var moveDistance = CELL_SIZE;
				var normalizedDx = dx / distance;
				var normalizedDy = dy / distance;
				var targetX = self.x + normalizedDx * moveDistance;
				var targetY = self.y + normalizedDy * moveDistance;
				// Try to move towards player, prioritize the axis with larger distance
				if (Math.abs(dx) > Math.abs(dy)) {
					// Try horizontal movement first
					var horizontalTarget = self.x + (dx > 0 ? moveDistance : -moveDistance);
					if (canMoveTo(horizontalTarget, self.y)) {
						targetX = horizontalTarget;
						targetY = self.y;
					} else if (canMoveTo(self.x, self.y + (dy > 0 ? moveDistance : -moveDistance))) {
						// If horizontal blocked, try vertical
						targetX = self.x;
						targetY = self.y + (dy > 0 ? moveDistance : -moveDistance);
					} else {
						// Can't move towards player
						targetX = self.x;
						targetY = self.y;
					}
				} else {
					// Try vertical movement first
					var verticalTarget = self.y + (dy > 0 ? moveDistance : -moveDistance);
					if (canMoveTo(self.x, verticalTarget)) {
						targetX = self.x;
						targetY = verticalTarget;
					} else if (canMoveTo(self.x + (dx > 0 ? moveDistance : -moveDistance), self.y)) {
						// If vertical blocked, try horizontal
						targetX = self.x + (dx > 0 ? moveDistance : -moveDistance);
						targetY = self.y;
					} else {
						// Can't move towards player
						targetX = self.x;
						targetY = self.y;
					}
				}
				// Move towards calculated target
				if (targetX !== self.x || targetY !== self.y) {
					// Store current position for safety
					var safeX = self.x;
					var safeY = self.y;
					tween(self, {
						x: targetX,
						y: targetY
					}, {
						duration: 1000,
						easing: tween.linear,
						onFinish: function onFinish() {
							// Validate final position
							if (!canMoveTo(self.x, self.y)) {
								self.x = safeX;
								self.y = safeY;
							}
							self.isMoving = false;
						}
					});
				} else {
					self.isMoving = false;
				}
			}
		} else if (!canSeePlayer) {
			// Start patrol movement if not already moving and can't see player
			if (!self.isMoving) {
				self.startPatrol();
			}
		}
		// Attack player if in range
		if (distance < self.attackRange) {
			// Stop patrolling when in attack range
			if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) {
				tween.stop(self);
				self.isMoving = false;
			}
			// Continuously attack while in range
			if (self.attackCooldown <= 0) {
				// Perform melee attack
				playerHealth--;
				LK.effects.flashObject(player, 0xFF0000, 500);
				// Visual attack feedback - enemy briefly grows and turns red
				tween(self, {
					tint: 0xFF0000,
					scaleX: 1.3,
					scaleY: 1.3
				}, {
					duration: 200,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						// Return to normal appearance
						tween(self, {
							tint: 0xFFFFFF,
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 200,
							easing: tween.easeOut
						});
					}
				});
				// Reset attack cooldown
				self.attackCooldown = self.attackInterval;
			}
		}
		// Update attack cooldown
		if (self.attackCooldown > 0) {
			self.attackCooldown--;
		}
		self.lastPlayerDistance = distance;
	};
	return self;
});
var Ore = Container.expand(function () {
	var self = Container.call(this);
	var oreGraphics = self.attachAsset('ore', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.value = 1;
	self.bobTimer = 0;
	self.baseY = self.y;
	self.update = function () {
		self.bobTimer++;
		self.y = self.baseY + Math.sin(self.bobTimer * 0.1) * 3;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x2C1810
});
/**** 
* Game Code
****/ 
// Game constants
var MAZE_WIDTH = 13;
var MAZE_HEIGHT = 17;
var CELL_SIZE = 80;
var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2;
var MAZE_OFFSET_Y = 100;
// Game variables
var maze = [];
var player;
var enemies = [];
var ores = [];
var bullets = [];
var playerHealth = 3;
var oreCollected = 0;
var oreTarget = 10;
var level = 1;
var exit;
var gameContainer;
// UI elements
var healthText = new Text2('Health: 3', {
	size: 60,
	fill: 0xFF4444
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
var oreText = new Text2('Ore: 0/10', {
	size: 60,
	fill: 0xFFD700
});
oreText.anchor.set(0.5, 0);
LK.gui.top.addChild(oreText);
var levelText = new Text2('Level: 1', {
	size: 60,
	fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
// Initialize maze array
function initializeMaze() {
	maze = [];
	for (var y = 0; y < MAZE_HEIGHT; y++) {
		maze[y] = [];
		for (var x = 0; x < MAZE_WIDTH; x++) {
			maze[y][x] = 1; // 1 = wall, 0 = floor
		}
	}
}
// Simple maze generation using recursive backtracking
function generateMaze() {
	initializeMaze();
	var stack = [];
	var startX = 1;
	var startY = 1;
	maze[startY][startX] = 0;
	stack.push({
		x: startX,
		y: startY
	});
	while (stack.length > 0) {
		var current = stack[stack.length - 1];
		var neighbors = [];
		// Check all four directions
		var directions = [{
			x: 0,
			y: -2
		}, {
			x: 2,
			y: 0
		}, {
			x: 0,
			y: 2
		}, {
			x: -2,
			y: 0
		}];
		for (var i = 0; i < directions.length; i++) {
			var nx = current.x + directions[i].x;
			var ny = current.y + directions[i].y;
			if (nx > 0 && nx < MAZE_WIDTH - 1 && ny > 0 && ny < MAZE_HEIGHT - 1 && maze[ny][nx] === 1) {
				neighbors.push({
					x: nx,
					y: ny,
					dir: directions[i]
				});
			}
		}
		if (neighbors.length > 0) {
			var chosen = neighbors[Math.floor(Math.random() * neighbors.length)];
			// Remove wall between current and chosen
			maze[current.y + chosen.dir.y / 2][current.x + chosen.dir.x / 2] = 0;
			maze[chosen.y][chosen.x] = 0;
			stack.push(chosen);
		} else {
			stack.pop();
		}
	}
}
// Create visual maze
function createMazeVisual() {
	gameContainer = game.addChild(new Container());
	for (var y = 0; y < MAZE_HEIGHT; y++) {
		for (var x = 0; x < MAZE_WIDTH; x++) {
			var cellX = MAZE_OFFSET_X + x * CELL_SIZE;
			var cellY = MAZE_OFFSET_Y + y * CELL_SIZE;
			if (maze[y][x] === 1) {
				// Wall
				var wall = LK.getAsset('wall', {
					x: cellX,
					y: cellY
				});
				gameContainer.addChild(wall);
			} else {
				// Floor
				var floor = LK.getAsset('floor', {
					x: cellX,
					y: cellY
				});
				gameContainer.addChild(floor);
			}
		}
	}
}
// Place ore in maze
function placeOre() {
	var oreCount = oreTarget + Math.floor(level / 2);
	var placed = 0;
	while (placed < oreCount) {
		var x = Math.floor(Math.random() * MAZE_WIDTH);
		var y = Math.floor(Math.random() * MAZE_HEIGHT);
		if (maze[y][x] === 0 && (x !== 1 || y !== 1)) {
			var ore = gameContainer.addChild(new Ore());
			ore.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
			ore.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
			ore.baseY = ore.y;
			ores.push(ore);
			placed++;
		}
	}
}
// Place enemies in maze
function placeEnemies() {
	var enemyCount = 3 + level;
	var placed = 0;
	while (placed < enemyCount) {
		var x = Math.floor(Math.random() * MAZE_WIDTH);
		var y = Math.floor(Math.random() * MAZE_HEIGHT);
		if (maze[y][x] === 0 && (x !== 1 || y !== 1) && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 5) {
			var enemy = gameContainer.addChild(new Enemy());
			enemy.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
			enemy.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
			enemy.startPosition.x = enemy.x;
			enemy.startPosition.y = enemy.y;
			enemies.push(enemy);
			placed++;
		}
	}
}
// Place exit
function placeExit() {
	// Find a position far from start
	var placed = false;
	while (!placed) {
		var x = Math.floor(Math.random() * MAZE_WIDTH);
		var y = Math.floor(Math.random() * MAZE_HEIGHT);
		if (maze[y][x] === 0 && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 10) {
			exit = gameContainer.addChild(LK.getAsset('exit', {
				x: MAZE_OFFSET_X + x * CELL_SIZE,
				y: MAZE_OFFSET_Y + y * CELL_SIZE
			}));
			placed = true;
		}
	}
}
// Create detailed background with various environmental elements
function createDetailedBackground() {
	if (!gameContainer) {
		console.log("gameContainer not available for background creation");
		return;
	}
	var backgroundElements = [];
	// Select one of 9 background variations randomly
	var backgroundType = Math.floor(Math.random() * 9);
	// Background variation 0: Rock dominant
	if (backgroundType === 0) {
		// Add many background rocks
		for (var i = 0; i < 15; i++) {
			var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.4,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgRock1);
		}
		for (var i = 0; i < 20; i++) {
			var bgRock2 = gameContainer.addChild(LK.getAsset('bgRock2', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgRock2);
		}
	}
	// Background variation 1: Crystal cave
	else if (backgroundType === 1) {
		for (var i = 0; i < 30; i++) {
			var bgCrystal = gameContainer.addChild(LK.getAsset('bgCrystal', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.5,
				rotation: Math.random() * Math.PI * 2,
				scaleY: 0.8 + Math.random() * 0.4
			}));
			backgroundElements.push(bgCrystal);
		}
	}
	// Background variation 2: Moss covered
	else if (backgroundType === 2) {
		for (var i = 0; i < 40; i++) {
			var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.45,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgMoss);
		}
		// Add some vines
		for (var i = 0; i < 15; i++) {
			var bgVines = gameContainer.addChild(LK.getAsset('bgVines', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgVines);
		}
	}
	// Background variation 3: Stalactite heavy
	else if (backgroundType === 3) {
		for (var i = 0; i < 25; i++) {
			var bgStalactite = gameContainer.addChild(LK.getAsset('bgStalactite', {
				x: Math.random() * 2048,
				y: Math.random() * 400,
				// Extended from top
				anchorX: 0.5,
				anchorY: 0,
				alpha: 0.4,
				rotation: Math.random() * 0.4 - 0.2,
				scaleY: 0.8 + Math.random() * 0.6
			}));
			backgroundElements.push(bgStalactite);
		}
	}
	// Background variation 4: Pebble field
	else if (backgroundType === 4) {
		for (var i = 0; i < 35; i++) {
			var bgPebbles = gameContainer.addChild(LK.getAsset('bgPebbles', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.35,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgPebbles);
		}
	}
	// Background variation 5: Cracked terrain
	else if (backgroundType === 5) {
		for (var i = 0; i < 50; i++) {
			var bgCracks = gameContainer.addChild(LK.getAsset('bgCracks', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.25,
				rotation: Math.random() * Math.PI * 2,
				scaleX: 0.5 + Math.random() * 1.5
			}));
			backgroundElements.push(bgCracks);
		}
	}
	// Background variation 6: Boulder field
	else if (backgroundType === 6) {
		for (var i = 0; i < 12; i++) {
			var bgBoulder = gameContainer.addChild(LK.getAsset('bgBoulder', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgBoulder);
		}
	}
	// Background variation 7: Mixed cave
	else if (backgroundType === 7) {
		// Mixed environment with moderate amounts of everything
		for (var i = 0; i < 8; i++) {
			var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgRock1);
		}
		for (var i = 0; i < 10; i++) {
			var bgCrystal = gameContainer.addChild(LK.getAsset('bgCrystal', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.4,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgCrystal);
		}
		for (var i = 0; i < 15; i++) {
			var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.35,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgMoss);
		}
	}
	// Background variation 8: Vine jungle cave
	else if (backgroundType === 8) {
		for (var i = 0; i < 30; i++) {
			var bgVines = gameContainer.addChild(LK.getAsset('bgVines', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.4,
				rotation: Math.random() * Math.PI * 2,
				scaleX: 0.8 + Math.random() * 0.4
			}));
			backgroundElements.push(bgVines);
		}
		for (var i = 0; i < 25; i++) {
			var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
				x: Math.random() * 2048,
				y: Math.random() * 2732,
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				rotation: Math.random() * Math.PI * 2
			}));
			backgroundElements.push(bgMoss);
		}
	}
	// Send all background elements to back
	for (var i = 0; i < backgroundElements.length; i++) {
		gameContainer.setChildIndex(backgroundElements[i], 0);
	}
}
// Check if position is valid for movement
function canMoveTo(x, y) {
	var mazeX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE);
	var mazeY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE);
	if (mazeX < 0 || mazeX >= MAZE_WIDTH || mazeY < 0 || mazeY >= MAZE_HEIGHT) {
		return false;
	}
	return maze[mazeY][mazeX] === 0;
}
// Initialize level
function initializeLevel() {
	// Clear existing game objects
	if (gameContainer) {
		gameContainer.destroy();
	}
	enemies = [];
	ores = [];
	bullets = [];
	oreCollected = 0;
	// Add detailed background
	var background = game.addChild(LK.getAsset('background', {
		x: 0,
		y: 0,
		width: 2048,
		height: 2732
	}));
	// Generate new maze
	generateMaze();
	createMazeVisual();
	// Create detailed background elements
	createDetailedBackground();
	// Create player
	player = gameContainer.addChild(LK.getAsset('player', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: MAZE_OFFSET_X + 1 * CELL_SIZE + CELL_SIZE / 2,
		y: MAZE_OFFSET_Y + 1 * CELL_SIZE + CELL_SIZE / 2
	}));
	// Place game objects
	placeOre();
	placeEnemies();
	placeExit();
	// Update UI
	updateUI();
}
// Update UI
function updateUI() {
	healthText.setText('Health: ' + playerHealth);
	oreText.setText('Ore: ' + oreCollected + '/' + oreTarget);
	levelText.setText('Level: ' + level);
}
// Shooting system
var dragNode = null;
var shootCooldown = 0;
function shoot(targetX, targetY) {
	if (shootCooldown > 0) return;
	// Limit maximum bullets to prevent lag
	if (bullets.length >= 15) return;
	var dx = targetX - player.x;
	var dy = targetY - player.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	if (distance < 50) return; // Don't shoot if too close
	// Calculate base direction
	var baseDirectionX = dx / distance;
	var baseDirectionY = dy / distance;
	// Create three bullets with spread angles
	var spreadAngles = [-0.3, 0, 0.3]; // Left, center, right (in radians, about 17 degrees each side)
	for (var i = 0; i < spreadAngles.length; i++) {
		var angle = Math.atan2(baseDirectionY, baseDirectionX) + spreadAngles[i];
		var bullet = gameContainer.addChild(new Bullet());
		bullet.x = player.x;
		bullet.y = player.y;
		bullet.direction.x = Math.cos(angle);
		bullet.direction.y = Math.sin(angle);
		bullets.push(bullet);
	}
	shootCooldown = 15; // Quarter second cooldown
	LK.getSound('shoot').play();
}
// Main game loop
game.update = function () {
	if (shootCooldown > 0) shootCooldown--;
	// Handle hold movement
	if (isTracking && !isHolding) {
		var currentTime = Date.now();
		var holdTime = currentTime - holdStartTime;
		// Check if we should start hold movement
		if (holdTime >= holdThreshold) {
			var dx = swipeEnd.x - swipeStart.x;
			var dy = swipeEnd.y - swipeStart.y;
			var swipeDistance = Math.sqrt(dx * dx + dy * dy);
			// Only start hold if not moving much (stationary hold)
			if (swipeDistance < swipeThreshold) {
				isHolding = true;
				lastHoldMoveTime = currentTime;
				// Determine hold direction based on player center to touch position
				var holdDx = swipeStart.x - player.x;
				var holdDy = swipeStart.y - player.y;
				var holdDistance = Math.sqrt(holdDx * holdDx + holdDy * holdDy);
				if (holdDistance > 30) {
					// Must be reasonable distance from center
					if (Math.abs(holdDx) > Math.abs(holdDy)) {
						// Horizontal hold movement
						holdDirection.x = holdDx > 0 ? 1 : -1;
						holdDirection.y = 0;
					} else {
						// Vertical hold movement
						holdDirection.x = 0;
						holdDirection.y = holdDy > 0 ? 1 : -1;
					}
				}
			}
		}
	}
	// Process hold movement
	if (isHolding && !isPlayerMoving) {
		var currentTime = Date.now();
		if (currentTime - lastHoldMoveTime >= holdMoveInterval) {
			var moveX = holdDirection.x * playerSpeed;
			var moveY = holdDirection.y * playerSpeed;
			var newX = player.x + moveX;
			var newY = player.y + moveY;
			// Try to move in hold direction
			if (canMoveTo(newX, player.y) && holdDirection.x !== 0) {
				// Flip player sprite based on hold movement direction
				if (holdDirection.x > 0) {
					// Moving right - face right (normal)
					player.scaleX = 1;
				} else {
					// Moving left - face left (flipped)
					player.scaleX = -1;
				}
				isPlayerMoving = true;
				tween(player, {
					x: newX
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						isPlayerMoving = false;
					}
				});
				lastHoldMoveTime = currentTime;
			} else if (canMoveTo(player.x, newY) && holdDirection.y !== 0) {
				isPlayerMoving = true;
				tween(player, {
					y: newY
				}, {
					duration: 120,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						isPlayerMoving = false;
					}
				});
				lastHoldMoveTime = currentTime;
			}
		}
	}
	// Update bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		var bullet = bullets[i];
		// Check bullet lifetime
		if (bullet.lifetime >= bullet.maxLifetime) {
			bullet.destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check wall collision
		if (!canMoveTo(bullet.x, bullet.y)) {
			bullet.destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check enemy collision (optimized - only check every other frame for performance)
		var hitEnemy = false;
		if (LK.ticks % 2 === 0 || bullet.lifetime < 10) {
			// Always check new bullets
			for (var j = enemies.length - 1; j >= 0; j--) {
				if (bullet.intersects(enemies[j])) {
					enemies[j].health--;
					LK.getSound('enemyHit').play();
					if (enemies[j].health <= 0) {
						// Create red circular explosion animation
						var dyingEnemy = enemies[j];
						var explosionX = dyingEnemy.x;
						var explosionY = dyingEnemy.y;
						// Create red explosion circle
						var explosion = gameContainer.addChild(LK.getAsset('bullet', {
							anchorX: 0.5,
							anchorY: 0.5,
							x: explosionX,
							y: explosionY,
							scaleX: 0.1,
							scaleY: 0.1,
							tint: 0xFF0000
						}));
						// Animate explosion circle expanding and fading
						tween(explosion, {
							scaleX: 8,
							scaleY: 8,
							alpha: 0
						}, {
							duration: 500,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								explosion.destroy();
							}
						});
						// Create enemy death animation with spinning
						tween(dyingEnemy, {
							tint: 0xFF0000,
							scaleX: 1.5,
							scaleY: 1.5,
							rotation: Math.PI * 2
						}, {
							duration: 150,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								// Second stage: Continue growing while fading to dark red and spinning faster
								tween(dyingEnemy, {
									tint: 0x800000,
									scaleX: 2.5,
									scaleY: 2.5,
									alpha: 0.7,
									rotation: Math.PI * 6
								}, {
									duration: 200,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										// Final stage: Fade out completely with final spin
										tween(dyingEnemy, {
											alpha: 0,
											scaleX: 3,
											scaleY: 3,
											rotation: Math.PI * 10
										}, {
											duration: 200,
											easing: tween.easeIn,
											onFinish: function onFinish() {
												dyingEnemy.destroy();
											}
										});
									}
								});
							}
						});
						enemies.splice(j, 1);
					}
					bullet.destroy();
					bullets.splice(i, 1);
					hitEnemy = true;
					break;
				}
			}
		}
		if (hitEnemy) continue;
	}
	// Check ore collection
	for (var i = ores.length - 1; i >= 0; i--) {
		if (player.intersects(ores[i])) {
			oreCollected++;
			LK.getSound('oreCollect').play();
			ores[i].destroy();
			ores.splice(i, 1);
			updateUI();
		}
	}
	// Check exit condition
	if (exit && player.intersects(exit) && oreCollected >= oreTarget) {
		level++;
		oreTarget += 2;
		initializeLevel();
		return;
	}
	// Check game over
	if (playerHealth <= 0) {
		LK.showGameOver();
		return;
	}
	// Check win condition (survive 10 levels)
	if (level > 10) {
		LK.showYouWin();
		return;
	}
};
// Swipe and hold-based movement system
var swipeStart = {
	x: 0,
	y: 0
};
var swipeEnd = {
	x: 0,
	y: 0
};
var isTracking = false;
var playerSpeed = 80; // Full cell movement
var swipeThreshold = 50; // Minimum distance for swipe detection
var lastMoveTime = 0;
var moveDelay = 200; // Delay between moves in milliseconds
var isPlayerMoving = false;
// Hold movement system
var isHolding = false;
var holdStartTime = 0;
var holdThreshold = 300; // Time to distinguish between tap and hold (ms)
var holdMoveInterval = 150; // Interval between moves while holding
var lastHoldMoveTime = 0;
var holdDirection = {
	x: 0,
	y: 0
};
game.down = function (x, y, obj) {
	swipeStart.x = x;
	swipeStart.y = y;
	isTracking = true;
	holdStartTime = Date.now();
	isHolding = false;
};
game.move = function (x, y, obj) {
	if (isTracking) {
		swipeEnd.x = x;
		swipeEnd.y = y;
	}
};
game.up = function (x, y, obj) {
	if (!isTracking) return;
	isTracking = false;
	isHolding = false; // Stop hold movement
	var holdTime = Date.now() - holdStartTime;
	// Check if this was a hold operation
	if (holdTime >= holdThreshold) {
		// This was a hold, don't process as tap
		return;
	}
	// Check if this is a swipe for shooting
	var dx = swipeEnd.x - swipeStart.x;
	var dy = swipeEnd.y - swipeStart.y;
	var swipeDistance = Math.sqrt(dx * dx + dy * dy);
	// If swipe distance is significant, shoot towards swipe direction
	if (swipeDistance >= swipeThreshold) {
		// Calculate target position based on swipe direction
		var targetX = player.x + dx * 3; // Multiply for longer range
		var targetY = player.y + dy * 3;
		shoot(targetX, targetY);
		return; // Don't process as movement
	}
	// Tap only - move towards target position
	// Prevent too frequent moves and simultaneous movements
	var currentTime = Date.now();
	if (currentTime - lastMoveTime < moveDelay || isPlayerMoving) return;
	// Calculate direction from player to tap position
	var tapDx = x - player.x;
	var tapDy = y - player.y;
	var distance = Math.sqrt(tapDx * tapDx + tapDy * tapDy);
	if (distance < 50) return; // Don't move if tapped too close to player
	// Determine movement direction (one cell at a time)
	var moveX = 0;
	var moveY = 0;
	if (Math.abs(tapDx) > Math.abs(tapDy)) {
		// Move horizontally towards tap
		moveX = tapDx > 0 ? playerSpeed : -playerSpeed;
	} else {
		// Move vertically towards tap
		moveY = tapDy > 0 ? playerSpeed : -playerSpeed;
	}
	// Calculate new position
	var newX = player.x + moveX;
	var newY = player.y + moveY;
	// Check if movement is valid and animate smoothly
	if (canMoveTo(newX, player.y) && Math.abs(moveX) > 0) {
		// Flip player sprite based on movement direction
		if (moveX > 0) {
			// Moving right - face right (normal)
			player.scaleX = 1;
		} else {
			// Moving left - face left (flipped)
			player.scaleX = -1;
		}
		isPlayerMoving = true;
		tween(player, {
			x: newX
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				isPlayerMoving = false;
			}
		});
		lastMoveTime = currentTime;
	} else if (canMoveTo(player.x, newY) && Math.abs(moveY) > 0) {
		isPlayerMoving = true;
		tween(player, {
			y: newY
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				isPlayerMoving = false;
			}
		});
		lastMoveTime = currentTime;
	}
};
// Initialize the first level
initializeLevel();
// Start background music
LK.playMusic('1dwarftheme');
 2d sprites old dwarf hold shootgun. In-Game asset. 2d. High contrast. No shadows
 2d chibi green evil underground fat ork. In-Game asset. 2d. High contrast. No shadows
 
 2d golds ors brigh stone. In-Game asset. 2d. High contrast. No shadows
 2d cave tunnel corridor. In-Game asset. 2d. High contrast. No shadows